diff --git a/simbot-component-onebot-common/build.gradle.kts b/simbot-component-onebot-common/build.gradle.kts index 70a7e140..902a755f 100644 --- a/simbot-component-onebot-common/build.gradle.kts +++ b/simbot-component-onebot-common/build.gradle.kts @@ -59,12 +59,6 @@ kotlin { api(kotlin("test")) } - jvmMain { - dependencies { - compileOnly(libs.simbot.api) - } - } - jvmTest.dependencies { implementation(libs.log4j.api) implementation(libs.log4j.core) diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-common/build.gradle.kts b/simbot-component-onebot-v11/simbot-component-onebot-v11-common/build.gradle.kts index d1f22dae..31e42a89 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-common/build.gradle.kts +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-common/build.gradle.kts @@ -51,8 +51,8 @@ kotlin { sourceSets { commonMain.dependencies { - implementation(project(":simbot-component-onebot-common")) - implementation(libs.simbot.common.annotations) + api(project(":simbot-component-onebot-common")) + api(libs.simbot.common.annotations) api(libs.kotlinx.serialization.core) } @@ -62,10 +62,6 @@ kotlin { api(libs.kotlinx.coroutines.test) } - jvmMain.dependencies { - compileOnly(libs.simbot.common.annotations) - } - jvmTest.dependencies { compileOnly(libs.simbot.common.annotations) implementation(libs.log4j.api) diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/api/simbot-component-onebot-v11-core.api b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/api/simbot-component-onebot-v11-core.api index db491b60..4cc210a0 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/api/simbot-component-onebot-v11-core.api +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/api/simbot-component-onebot-v11-core.api @@ -1104,7 +1104,10 @@ public abstract interface class love/forte/simbot/component/onebot/v11/core/api/ public abstract fun getAction ()Ljava/lang/String; public abstract fun getApiResultDeserializer ()Lkotlinx/serialization/DeserializationStrategy; public abstract fun getBody ()Ljava/lang/Object; + public fun getMethod ()Lio/ktor/http/HttpMethod; public abstract fun getResultDeserializer ()Lkotlinx/serialization/DeserializationStrategy; + public fun resolveUrlAction (Lio/ktor/http/URLBuilder;Ljava/util/Collection;)V + public fun resolveUrlExtensions (Lio/ktor/http/URLBuilder;)V } public final class love/forte/simbot/component/onebot/v11/core/api/OneBotApi$Actions { @@ -1161,6 +1164,10 @@ public final class love/forte/simbot/component/onebot/v11/core/api/OneBotApiExec public final synthetic fun unbox-impl ()Llove/forte/simbot/component/onebot/v11/core/api/OneBotApiExecutable; } +public final class love/forte/simbot/component/onebot/v11/core/api/OneBotApiKt { + public static final fun resolveUrl (Llove/forte/simbot/component/onebot/v11/core/api/OneBotApi;Lio/ktor/http/URLBuilder;Ljava/util/Collection;)V +} + public final class love/forte/simbot/component/onebot/v11/core/api/OneBotApiRequests { public static final fun getApiLogger ()Lorg/slf4j/Logger; public static final synthetic fun request (Llove/forte/simbot/component/onebot/v11/core/api/OneBotApi;Lio/ktor/client/HttpClient;Lio/ktor/http/Url;Ljava/lang/String;Ljava/util/Collection;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApi.kt b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApi.kt index 98aa7906..51b94f99 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApi.kt +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApi.kt @@ -17,6 +17,7 @@ package love.forte.simbot.component.onebot.v11.core.api +import io.ktor.http.* import kotlinx.serialization.* import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.SerialDescriptor @@ -37,10 +38,48 @@ import love.forte.simbot.component.onebot.v11.core.api.OneBotApiResult.Companion */ public interface OneBotApi { /** - * API 的 action(要进行的动作) + * 此 API 的请求方式。 + * OneBot协议中的标准API通常均为 POST, + * 但是一些额外的扩展或自定义API可能是 GET 或其他方式。 + * @since 1.8.0 + */ + public val method: HttpMethod + get() = HttpMethod.Post + + /** + * API 的 action(要进行的动作),会通过 [resolveUrlAction] 附加在 url 中。 + * 可以重写它来改变此逻辑。 */ public val action: String + /** + * 根据 [action] 和可能额外要求的 [actionSuffixes] 构建一个完整的请求地址。 + * + * [urlBuilder] 中已经添加了基础的 `host` 等信息。 + * + * @since 1.8.0 + */ + public fun resolveUrlAction(urlBuilder: URLBuilder, actionSuffixes: Collection?) { + if (actionSuffixes?.isEmpty() != false) { + urlBuilder.appendPathSegments(action) + } else { + urlBuilder.appendPathSegments( + buildString(action.length) { + append(action) + actionSuffixes.forEach { sf -> append(sf) } + } + ) + } + } + + /** + * 对 [urlBuilder] 进行一些额外的处理,例如当method为GET时为其添加查询参数。 + * 主要面向额外扩展的自定义实现来重写此方法。 + * @since 1.8.0 + */ + public fun resolveUrlExtensions(urlBuilder: URLBuilder) { + } + /** * API的参数。 */ @@ -76,6 +115,15 @@ public interface OneBotApi { } } +/** + * 使用 [OneBotApi.resolveUrlAction] 和 [OneBotApi.resolveUrlExtensions] 。 + * @since 1.8.0 + */ +public fun OneBotApi<*>.resolveUrl(urlBuilder: URLBuilder, actionSuffixes: Collection?) { + resolveUrlAction(urlBuilder, actionSuffixes) + resolveUrlExtensions(urlBuilder) +} + /** * [响应](https://github.com/botuniverse/onebot-11/blob/master/api/README.md#响应) * diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApiRequests.kt b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApiRequests.kt index cd18c62c..4e32fd17 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApiRequests.kt +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/api/OneBotApiRequests.kt @@ -102,19 +102,13 @@ public suspend fun OneBotApi<*>.request( accessToken: String? = null, actionSuffixes: Collection? = null, ): HttpResponse { - return client.post { + val api = this + + return client.request { + this.method = api.method url { takeFrom(host) - if (actionSuffixes?.isEmpty() != false) { - appendPathSegments(action) - } else { - appendPathSegments( - buildString(action.length) { - append(action) - actionSuffixes.forEach { sf -> append(sf) } - } - ) - } + api.resolveUrl(this, actionSuffixes) } headers { @@ -124,7 +118,7 @@ public suspend fun OneBotApi<*>.request( var jsonStr: String? = null - when (val b = this@request.body) { + when (val b = api.body) { null -> { if (GlobalOneBotApiRequestConfiguration.emptyJsonStringIfBodyNull) { setBody(EMPTY_JSON_STR) @@ -163,7 +157,7 @@ public suspend fun OneBotApi<*>.request( "API [{}] REQ ===> {}, body: {}, json: {}", action, url, - this@request.body, + api.body, jsonStr ) }.also { res -> diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonTest/kotlin/love/forte/simbot/component/onebot/v11/core/api/ApiRequestTests.kt b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonTest/kotlin/love/forte/simbot/component/onebot/v11/core/api/ApiRequestTests.kt index afbea77a..3f66b303 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonTest/kotlin/love/forte/simbot/component/onebot/v11/core/api/ApiRequestTests.kt +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonTest/kotlin/love/forte/simbot/component/onebot/v11/core/api/ApiRequestTests.kt @@ -2,8 +2,12 @@ package love.forte.simbot.component.onebot.v11.core.api import io.ktor.client.* import io.ktor.client.engine.mock.* +import io.ktor.client.statement.* +import io.ktor.http.* import kotlinx.coroutines.test.runTest +import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import love.forte.simbot.common.id.IntID.Companion.ID import love.forte.simbot.common.id.literal import love.forte.simbot.component.onebot.common.annotations.ApiResultConstructor @@ -70,4 +74,34 @@ class ApiRequestTests { assertEquals("123", data.messageId.literal) } + @Test + fun customGetApiTest() = runTest { + @Serializable + data class CustomResult(val name: String) + class MyCustomApi : OneBotApi { + override val method: HttpMethod = HttpMethod.Get + override val action: String = "custom_action" + override val body: Any? = null + override val resultDeserializer: DeserializationStrategy = CustomResult.serializer() + override val apiResultDeserializer: DeserializationStrategy> = + OneBotApiResult.serializer(CustomResult.serializer()) + + override fun resolveUrlExtensions(urlBuilder: URLBuilder) { + urlBuilder.parameters.append("name", "forte") + } + } + + val client = createClient( + "custom_action", + respDataSer = { CustomResult.serializer() }, + respData = { CustomResult("forte") } + ) + + val resp = MyCustomApi().request(client, "http://127.0.0.1:8080/") + assertEquals(HttpMethod.Get, resp.request.method) + assertEquals("forte", resp.request.url.parameters["name"]) + + val data = MyCustomApi().requestData(client, "http://127.0.0.1:8080/") + assertEquals("forte", data.name) + } } diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-event/build.gradle.kts b/simbot-component-onebot-v11/simbot-component-onebot-v11-event/build.gradle.kts index 1469f2b3..2db583eb 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-event/build.gradle.kts +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-event/build.gradle.kts @@ -57,7 +57,7 @@ kotlin { implementation(libs.simbot.api) api(libs.simbot.common.annotations) api(project(":simbot-component-onebot-common")) - implementation(libs.kotlinx.serialization.json) + api(libs.kotlinx.serialization.json) api(project(":simbot-component-onebot-v11:simbot-component-onebot-v11-common")) api(project(":simbot-component-onebot-v11:simbot-component-onebot-v11-message")) diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-message/build.gradle.kts b/simbot-component-onebot-v11/simbot-component-onebot-v11-message/build.gradle.kts index 17217c94..11a4e61a 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-message/build.gradle.kts +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-message/build.gradle.kts @@ -63,8 +63,8 @@ kotlin { api(libs.simbot.common.annotations) api(libs.kotlinx.coroutines.core) + api(libs.kotlinx.serialization.json) implementation(libs.kotlinx.io.core) - implementation(libs.kotlinx.serialization.json) implementation(libs.jetbrains.annotations) }