diff --git a/.changelog/v3.3.0.0-beta1.md b/.changelog/v3.3.0.0-beta1.md new file mode 100644 index 00000000..86b1a452 --- /dev/null +++ b/.changelog/v3.3.0.0-beta1.md @@ -0,0 +1,8 @@ +> 对应核心版本: [**v3.3.0**](https://github.com/simple-robot/simpler-robot/releases/tag/v3.3.0) + +> **Warning** +> 目前版本尚处于 **`BETA`** 阶段,代表仍然可能存在大量[已知问题](https://github.com/simple-robot/simbot-component-kook/issues)或未知问题, +以及未完善的内容和落后于官方更新的内容。** + +我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-kook/issues)或[协助](https://github.com/simple-robot/simbot-component-kook/pulls), +感谢您的贡献与支持! diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 7f991d08..3afcb632 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -36,14 +36,14 @@ jobs: - name: Gradle Run Test uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 # arguments: clean assemble test arguments: assemble test -Porg.gradle.daemon=false - name: Gradle Publish Release uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: | publishToSonatype closeAndReleaseStagingRepository @@ -98,7 +98,7 @@ jobs: - name: Gradle publish snapshot uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: clean test publishToSonatype closeAndReleaseStagingRepository env: SIMBOT_IS_SNAPSHOT: true @@ -126,7 +126,7 @@ jobs: - name: Gradle generate documentation uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: | -Porg.gradle.jvmargs="-Xmx4g -Xms4g -XX:MaxMetaspaceSize=2g -Dfile.encoding=UTF-8" -Porg.gradle.daemon=false diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 4fb52eef..69a3366a 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -54,7 +54,7 @@ jobs: - name: Gradle publish snapshot uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: | test publishToSonatype @@ -86,7 +86,7 @@ jobs: - name: Gradle generate documentation uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: | -Porg.gradle.jvmargs="-Xmx4g -Xms4g -XX:MaxMetaspaceSize=2g -Dfile.encoding=UTF-8" -Porg.gradle.daemon=false diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml index 9d3b93a9..65a91fbc 100644 --- a/.github/workflows/qodana_code_quality.yml +++ b/.github/workflows/qodana_code_quality.yml @@ -5,6 +5,7 @@ on: push: branches: - dev/main + - main jobs: qodana: diff --git a/.github/workflows/test-branch.yml b/.github/workflows/test-branch.yml index 6a9e24be..5845e038 100644 --- a/.github/workflows/test-branch.yml +++ b/.github/workflows/test-branch.yml @@ -37,7 +37,7 @@ jobs: - name: Run All Tests uses: gradle/gradle-build-action@v2 with: - gradle-version: 7.6 + gradle-version: 8.5 arguments: | assemble build diff --git a/CHANGELOG.md b/CHANGELOG.md index e66a7b94..07820bc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# v3.3.0.0-beta.1 + +> Release & Pull Notes: [v3.3.0.0-beta.1](https://github.com/simple-robot/simpler-robot/releases/tag/v3.3.0.0-beta.1) + +- fix: 消息发送中增加对 AtAll 的支持 ([`9363c9e`](https://github.com/simple-robot/simpler-robot/commit/9363c9e)) +- website: 配置域名 ([`bfc48ad`](https://github.com/simple-robot/simpler-robot/commit/bfc48ad)) +- fix(doc): 修复部分对配置文件 `ticket` 的描述错误问题 ([`3841f05`](https://github.com/simple-robot/simpler-robot/commit/3841f05)) +- CI: Qodana for branches 'main' ([`e813648`](https://github.com/simple-robot/simpler-robot/commit/e813648)) + # v3.2.0.0-alpha.8 > Release & Pull Notes: [v3.2.0.0-alpha.8](https://github.com/simple-robot/simpler-robot/releases/tag/v3.2.0.0-alpha.8) diff --git a/README.md b/README.md index 24530933..c4927748 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,44 @@ -# Simple Robot KOOK 组件 +# Simple Robot - KOOK 组件 此为 [Simple Robot v3][simbot3] (以下简称为 `simbot3` ) 下基于simbot标准API对 [KOOK API](https://www.kookapp.cn/) 的组件支持。 +**Simple Robot - KOOK 组件** 以下简称KOOK组件 +是一个基于 [KMP](https://kotlinlang.org/docs/multiplatform.html)、 +支持多平台(`JVM`、`JS`、native)且JVM平台库对Java友好、 +(特定模块)实现simbot3标准API的 **KOOK 机器人API** 依赖库。 + +**KOOK组件**提供多平台的KOOK API、bot事件订阅等功能实现的底层库, +以及基于simbot3标准API的高级功能应用库。 + ## 文档 了解**simbot3**: [simbot3官网](https://simbot.forte.love) -KOOK组件的**组件手册**: [组件手册](https://simple-robot.github.io/simbot-component-kook/) +KOOK组件的**组件手册**: [组件手册][website] -> 版本进入稳定后考虑配置域名,目前暂未配置。 +> [!note] +> 手册与simbot3官网均部署于GitHub Pages。 +> 为了更好的浏览体验,**推荐**开启魔法后访问。 **API文档**: [API文档引导站](https://docs.simbot.forte.love) -> **Warning** -> README 施工中。。。 - ## 支持情况 -前往查看 [支持列表](support-list.md) +前往查看 [支持列表](support-list.md)。 -## 使用 +## 快速开始 -前往 [组件官网](https://simple-robot.github.io/simbot-component-kook/) 参考 **快速开始** 相关章节。 +前往 [组件手册][website] 阅读 **快速开始** 相关章节。 ## 走马观花
简单示例 +> [!note] +> Java开发者可直接参考 [组件手册][website] 中**快速开始**相关示例的Java部分代码。 + +> 使用 Kotlin + `simbot-component-kook-core` 配合 `simboot-core-spring-boot-starter` 使用 `Spring Boot` 的情况下: ```kotlin // simbot-core / simbot-boot @@ -54,6 +65,7 @@ suspend fun KookChannelMessageEvent.onEvent(@FilterValue("name") name: String) { ``` 简单的完整示例: +> (使用 Kotlin + `simbot-component-kook-core`, 非 Spring Boot 的情况下:) ```kotlin suspend fun main() { @@ -85,6 +97,10 @@ suspend fun main() {
+## 应用案例 + +如果你想看看通过 simbot 开发的bot是什么样子,不妨添加我们亲爱的 [法欧莉斯卡雷特](https://www.kookapp.cn/app/oauth2/authorize?id=10250&permissions=197958144&client_id=jqdlyHK85xe1i5Bo&redirect_uri=&scope=bot) 并使用 `@法欧莉 今天的我` 来看看效果吧~ + ## License @@ -107,3 +123,5 @@ program. If not, see . [m-stdlib]: simbot-component-kook-stdlib [m-core]: simbot-component-kook-core [simbot3]: https://github.com/simple-robot/simpler-robot + +[website]: https://component-kook.simbot.forte.love/ diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7ff6bb3f..75d745ec 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,9 +24,9 @@ repositories { gradlePluginPortal() } -val kotlinVersion = "1.8.21" -val dokkaVersion = "1.8.10" -val suspendTransformVersion = "0.3.1" +val kotlinVersion = "1.9.21" +val dokkaVersion = "1.9.10" +val suspendTransformVersion = "0.5.1" val gradleCommon = "0.1.1" dependencies { @@ -35,7 +35,6 @@ dependencies { implementation(kotlin("serialization", kotlinVersion)) implementation("org.jetbrains.dokka", "dokka-gradle-plugin", dokkaVersion) implementation("org.jetbrains.dokka", "dokka-base", dokkaVersion) - // see https://github.com/gradle-nexus/publish-plugin implementation("io.github.gradle-nexus:publish-plugin:1.1.0") @@ -46,8 +45,8 @@ dependencies { // implementation("love.forte.gradle.common:gradle-common-all:$gradleCommon") } -val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks +//val compileKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks -compileKotlin.kotlinOptions { - freeCompilerArgs += listOf("-Xinline-classes") -} +//compileKotlin.kotlinOptions { +// freeCompilerArgs += listOf("-Xinline-classes") +//} diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt index 5e61cff5..b425594f 100644 --- a/buildSrc/src/main/kotlin/P.kt +++ b/buildSrc/src/main/kotlin/P.kt @@ -39,7 +39,7 @@ import love.forte.gradle.common.core.project.version as v * */ -val simbotVersion = v(3, 2, 0) +val simbotVersion = v(3, 3, 0) val simbotApi = "love.forte.simbot:simbot-api:$simbotVersion" val simbotAnnotations = "love.forte.simbot.util:simbot-annotations:$simbotVersion" @@ -68,7 +68,7 @@ object P : ProjectDetail() { 0, 0 ) - private val alphaSuffix = v("alpha", 8) + private val alphaSuffix = v("beta1") override val version: Version = baseVersion - alphaSuffix diff --git a/buildSrc/src/main/kotlin/SuspendTransforms.kt b/buildSrc/src/main/kotlin/SuspendTransforms.kt index efef79a0..3fda6df7 100644 --- a/buildSrc/src/main/kotlin/SuspendTransforms.kt +++ b/buildSrc/src/main/kotlin/SuspendTransforms.kt @@ -37,7 +37,7 @@ object SuspendTransforms { */ val jvmAsyncTransformer = SuspendTransformConfiguration.jvmAsyncTransformer.copy( syntheticFunctionIncludeAnnotations = includeAnnotations, - transformFunctionInfo = FunctionInfo("love.forte.simbot.utils", null, "$\$runInAsync"), + transformFunctionInfo = FunctionInfo("love.forte.simbot.utils", null, "$\$runInAsyncNullable"), copyAnnotationExcludes = SuspendTransformConfiguration.jvmAsyncTransformer.copyAnnotationExcludes + SuspendTransformConfiguration.jvmAsyncTransformer.markAnnotation.classInfo ) diff --git a/buildSrc/src/main/kotlin/changelog/GenerateChangelog.kt b/buildSrc/src/main/kotlin/changelog/GenerateChangelog.kt index dfa7b8d4..16951a12 100644 --- a/buildSrc/src/main/kotlin/changelog/GenerateChangelog.kt +++ b/buildSrc/src/main/kotlin/changelog/GenerateChangelog.kt @@ -42,17 +42,19 @@ fun Project.generateChangelog(tag: String) { val coreVersion = simbotVersion - file.writeText(""" + file.writeText( + """ > 对应核心版本: [**v$coreVersion**](https://github.com/simple-robot/simpler-robot/releases/tag/v$coreVersion) - > **Warning** - > 目前版本尚处于 **`ALPHA`** 阶段,代表仍然可能存在大量[已知问题](https://github.com/simple-robot/simbot-component-kook/issues)或未知问题, + > [!warning] + > 目前版本尚处于 **`BETA`** 阶段,代表仍然可能存在部分[已知问题](https://github.com/simple-robot/simbot-component-kook/issues)或未知问题, 以及未完善的内容和落后于官方更新的内容。** 我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-kook/issues)或[协助](https://github.com/simple-robot/simbot-component-kook/pulls), 感谢您的贡献与支持! - """.trimIndent()) + """.trimIndent() + ) } val rootChangelogFile = rootProject.file("CHANGELOG.md").also { file -> @@ -155,7 +157,7 @@ fun Project.generateChangelog(tag: String) { } } - val tmpDir = rootProject.buildDir.resolve("tmp/changelog").apply { mkdirs() } + val tmpDir = rootProject.layout.buildDirectory.dir("tmp/changelog").get().asFile val tmpFile = Files.createTempFile(tmpDir.toPath(), "changelog", "tmp").toFile() diff --git a/buildSrc/src/main/kotlin/kook-multiplatform-maven-publish.gradle.kts b/buildSrc/src/main/kotlin/kook-multiplatform-maven-publish.gradle.kts index 61937be3..793b2987 100644 --- a/buildSrc/src/main/kotlin/kook-multiplatform-maven-publish.gradle.kts +++ b/buildSrc/src/main/kotlin/kook-multiplatform-maven-publish.gradle.kts @@ -44,7 +44,6 @@ multiplatformConfigPublishing { project = P val jarJavadoc by tasks.registering(Jar::class) { - group = "documentation" archiveClassifier.set("javadoc") from(tasks.findByName("dokkaHtml")) } @@ -57,11 +56,12 @@ multiplatformConfigPublishing { if (systemProp("SIMBOT_LOCAL").toBoolean()) { mainHost = null } -// else { -// -// mainHostSupportedTargets = mainHost?.supports(hostManager) ?: emptySet() -// } +} +// TODO see https://github.com/gradle-nexus/publish-plugin/issues/208#issuecomment-1465029831 +val signingTasks: TaskCollection = tasks.withType() +tasks.withType().configureEach { + mustRunAfter(signingTasks) } fun KonanTarget.supports(hostManager: HostManager): Set { diff --git a/buildSrc/src/main/kotlin/simbot-kook-maven-publish.gradle.kts b/buildSrc/src/main/kotlin/simbot-kook-maven-publish.gradle.kts index ac83f345..ec6402c4 100644 --- a/buildSrc/src/main/kotlin/simbot-kook-maven-publish.gradle.kts +++ b/buildSrc/src/main/kotlin/simbot-kook-maven-publish.gradle.kts @@ -91,6 +91,11 @@ if (!isCi || isLinux) { } } +// TODO see https://github.com/gradle-nexus/publish-plugin/issues/208#issuecomment-1465029831 +val signingTasks: TaskCollection = tasks.withType() +tasks.withType().configureEach { + mustRunAfter(signingTasks) +} fun MavenPublication.show() { //// show project info diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e26101d..6d287d1a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] -kotlinx-coroutines = "1.7.0" -kotlinx-serialization = "1.5.0" +kotlinx-coroutines = "1.7.3" +kotlinx-serialization = "1.6.2" spring-boot = "2.7.5" openjdk-jmh = "1.35" forte-di = "0.0.3" forte-annotationTool = "0.6.3" ktor = "2.3.0" log4j = "2.20.0" -atomicfu = "0.20.1" +atomicfu = "0.23.1" [libraries] # jetbrains-annotation diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f42e62f3..a5952066 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/simbot-component-kook-api/Module.md b/simbot-component-kook-api/Module.md new file mode 100644 index 00000000..f8d37135 --- /dev/null +++ b/simbot-component-kook-api/Module.md @@ -0,0 +1,8 @@ +# Module simple-component-kook-api + + +对[KOOK API](https://www.kookapp.cn/)的最基本封装,不包含额外的功能性实现(比如bot、事件调度等)。 + +如果希望使用一个仅仅是针对API的原始封装模块而不需要基础/高级的事件流程控制,那么请考虑使用api模块。 + + diff --git a/simbot-component-kook-api/README.md b/simbot-component-kook-api/README.md new file mode 100644 index 00000000..fdaa6f7d --- /dev/null +++ b/simbot-component-kook-api/README.md @@ -0,0 +1,81 @@ +# simple-component-kook-api + +> [!note] +> 请先阅读 [模块说明](Module.md) + +> [!note] +> 更详细的快速开始建议前往阅读 [组件手册](https://component-kook.simbot.forte.love/docs/quick-start/api) 中的相关章节。 + + +api模块中,所有的API请求封装均在 `love.forte.simbot.kook.api` 中,它们通常以 `Api` 结尾,例如 `GetGuildListApi`。 + +所有的API构造方法均被隐藏,它们会各自提供自身的工厂函数,绝大多数以 `create` 命名,例如 + +```kotlin +val api: GetGuildListApi = GetGuildListApi.create(...) +``` + +## 使用 + +**Gradle Kotlin DSL** + +`api` 模块是多平台模块,在Gradle中需要使用 `kotlin` 插件来引用正确的平台。这并不代表你需要使用Kotlin语言编写。 + +```kotlin +plugin { + java // 你仍然可以使用Java + kotlin("jvm") version "$KOTLIN_VERSION" // 比如 1.9.10 + // 或者使用其他平台,例如 kotlin("js") +} + +dependencies { + implementation("love.forte.simbot.component:simbot-component-kook-api:$VERSION") + + // 你需要自行选择一个想要使用的 ktor-http-client, 例如 cio 或 okhttp 等 + // 更多选择参考 https://ktor.io/docs/http-client-engines.html + runtimeOnly("io.ktor:ktor-client-cio:$KTOR_VERSION") +} +``` + +**Gradle Groovy** + +`api` 模块是多平台模块,在Gradle中需要使用 `kotlin` 插件来引用正确的平台。这并不代表你需要使用Kotlin语言编写。 + +```groovy +plugin { + java // 你仍然可以使用Java + id "org.jetbrains.kotlin.jvm" version "$KOTLIN_VERSION" // 比如 1.8.10 + // 或者使用其他平台,例如 kotlin("js") +} + +dependencies { + implementation 'love.forte.simbot.component:simbot-component-qq-guild-api:$VERSION' + + // 你需要自行选择一个想要使用的 ktor-http-client, 例如 cio 或 okhttp 等 + // 更多选择参考 https://ktor.io/docs/http-client-engines.html + runtimeOnly 'io.ktor:ktor-client-cio:$KTOR_VERSION' +} +``` + +**Maven** + +`api` 模块是多平台模块,在Maven中需要增加 `-jvm` 后缀来使用JVM平台库。 + +```xml + + love.forte.simbot.component + simbot-component-qq-guild-api-jvm + ${VERSION} + + + + + io.ktor + ktor-client-cio-jvm + ${KTOR_VERSION} + runtime + +``` diff --git a/simbot-component-kook-api/build.gradle.kts b/simbot-component-kook-api/build.gradle.kts index aa82d16b..ebc67187 100644 --- a/simbot-component-kook-api/build.gradle.kts +++ b/simbot-component-kook-api/build.gradle.kts @@ -16,7 +16,6 @@ */ import love.forte.gradle.common.core.project.setup -import love.forte.gradle.common.kotlin.multiplatform.NativeTargets plugins { kotlin("multiplatform") @@ -42,6 +41,7 @@ repositories { kotlin { explicitApi() + applyDefaultHierarchyTemplate() sourceSets.configureEach { languageSettings { @@ -69,85 +69,34 @@ kotlin { } - val mainPresets = mutableSetOf() - val testPresets = mutableSetOf() - - // see https://kotlinlang.org/docs/native-target-supporsupportTargets = setOf( - //// // Tier 1 - //// "linuxX64", - //// "macosX64", - //// "macosArm64", - //// "iosSimulatorArm64", - //// "iosX64", - //// - //// // Tier 2 - ////// "linuxArm64", - //// "watchosSimulatorArm64", - //// "watchosX64", - //// "watchosArm32", - //// "watchosArm64", - //// "tvosSimulatorArm64", - //// "tvosX64", - //// "tvosArm64", - //// "iosArm64", - //// - //// // Tier 3 - ////// "androidNativeArm32", - ////// "androidNativeArm64", - ////// "androidNativeX86", - ////// "androidNativeX64", - //// "mingwX64", - ////// "watchosDeviceArm64", - //// )t.html -// val - - val targets = NativeTargets.Official.all.intersect(NativeTargets.KtorClient.all) - - - targets { - presets.filterIsInstance>() - .filter { it.name in targets } - .forEach { presets -> - val target = fromPreset(presets, presets.name) - val mainSourceSet = target.compilations["main"].kotlinSourceSets.first() - val testSourceSet = target.compilations["test"].kotlinSourceSets.first() - - val tn = target.name - when { - // just for test - // main中只使用HttpClient但用不到引擎,没必要指定 - - // win - tn.startsWith("mingw") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.winhttp) - } - } - // linux: CIO..? - tn.startsWith("linux") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.cio) - } - } - - // darwin based - tn.startsWith("macos") - || tn.startsWith("ios") - || tn.startsWith("watchos") - || tn.startsWith("tvos") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.darwin) - } - } - } - - mainPresets.add(mainSourceSet) - testPresets.add(testSourceSet) - } - } + // Tier 1 + macosX64() + macosArm64() + iosSimulatorArm64() + iosX64() + + // Tier 2 + linuxX64() +// linuxArm64() + watchosSimulatorArm64() + watchosX64() + watchosArm32() + watchosArm64() + tvosSimulatorArm64() + tvosX64() + tvosArm64() + iosArm64() + + // Tier 3 +// androidNativeArm32() +// androidNativeArm64() +// androidNativeX86() +// androidNativeX64() + mingwX64() +// watchosDeviceArm64() sourceSets { - val commonMain by getting { + commonMain { dependencies { compileOnly(simbotAnnotations) api(simbotRequestorCore) @@ -159,21 +108,21 @@ kotlin { } } - val commonTest by getting { + commonTest { dependencies { implementation(kotlin("test")) implementation(libs.kotlinx.coroutines.test) } } - getByName("jvmMain") { + jvmMain { dependencies { compileOnly(simbotApi) // use @Api4J annotation compileOnly(simbotAnnotations) // use @Api4J annotation } } - getByName("jvmTest") { + jvmTest { dependencies { implementation(libs.ktor.client.cio) implementation(simbotApi) // use @Api4J annotation @@ -183,28 +132,17 @@ kotlin { } } - getByName("jsMain") { + jsMain { dependencies { + api(simbotAnnotations) api(libs.ktor.client.js) } } - getByName("jsTest") { + jsTest { dependencies { api(libs.ktor.client.js) } } - - val nativeMain by creating { - dependsOn(commonMain) - } - - val nativeTest by creating { - dependsOn(commonTest) - } - - configure(mainPresets) { dependsOn(nativeMain) } - configure(testPresets) { dependsOn(nativeTest) } - } } diff --git a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/KookApi.kt b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/KookApi.kt index 5c05758c..dad1414e 100644 --- a/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/KookApi.kt +++ b/simbot-component-kook-api/src/commonMain/kotlin/love/forte/simbot/kook/api/KookApi.kt @@ -40,7 +40,6 @@ import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext import kotlin.jvm.JvmField import kotlin.jvm.JvmSynthetic -import kotlin.jvm.Volatile /** * 面向平台实现的 [KookApi] 的抽象类。 @@ -429,7 +428,7 @@ public abstract class KookPostApi : BaseKookApi() { override val method: HttpMethod get() = HttpMethod.Post - @Volatile + @kotlin.concurrent.Volatile private lateinit var _body: Any /** diff --git a/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt b/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt index 7422ab7b..87a73719 100644 --- a/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt +++ b/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/bot/KookBotVerifyInfoConfiguration.kt @@ -33,22 +33,26 @@ import love.forte.simbot.kook.TokenType * 作为 [config][KookBotVerifyInfoConfiguration.config] 属性使用。 * * 简化json e.g. + * * ```json * { * "component": "simbot.kook", * "ticket": { * "clientId": "Your client ID", - * "token": "Your ws token", + * "token": "Your ws token" * } * } * ``` * * 完整json e.g. + * * ```json * { * "component": "simbot.kook", - * "clientId": "Your client ID", - * "token": "Your ws token", + * "ticket": { + * "clientId": "Your client ID", + * "token": "Your ws token" + * }, * "config": { * "isCompress": true, * "syncPeriods": { diff --git a/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/message/KookMessagesTransformer.kt b/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/message/KookMessagesTransformer.kt index 53334fa6..9b90eef6 100644 --- a/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/message/KookMessagesTransformer.kt +++ b/simbot-component-kook-core/src/main/kotlin/love/forte/simbot/component/kook/message/KookMessagesTransformer.kt @@ -319,6 +319,12 @@ private suspend inline fun Message.Element<*>.elementToRequest( // this.request // } + is AtAll -> { + withinKmd { + at(AtTarget.All) + } + } + is KookAtAllHere -> { withinKmd { at(AtTarget.Here) diff --git a/simbot-component-kook-stdlib/build.gradle.kts b/simbot-component-kook-stdlib/build.gradle.kts index 94b18b03..a329088f 100644 --- a/simbot-component-kook-stdlib/build.gradle.kts +++ b/simbot-component-kook-stdlib/build.gradle.kts @@ -16,7 +16,6 @@ */ import love.forte.gradle.common.core.project.setup -import love.forte.gradle.common.kotlin.multiplatform.NativeTargets plugins { kotlin("multiplatform") @@ -44,6 +43,7 @@ repositories { kotlin { explicitApi() + applyDefaultHierarchyTemplate() sourceSets.configureEach { languageSettings { @@ -70,118 +70,66 @@ kotlin { nodejs() } - - val mainPresets = mutableSetOf() - val testPresets = mutableSetOf() - - // see https://kotlinlang.org/docs/native-target-suppors - - val targets = NativeTargets.Official.all.intersect(NativeTargets.KtorClient.all) - - targets { - presets.filterIsInstance>() - .filter { it.name in targets } - .forEach { presets -> - val target = fromPreset(presets, presets.name) - val mainSourceSet = target.compilations["main"].kotlinSourceSets.first() - val testSourceSet = target.compilations["test"].kotlinSourceSets.first() - - val tn = target.name - when { - // just for test - // main中只使用HttpClient但用不到引擎,没必要指定 - - // win - tn.startsWith("mingw") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.winhttp) - } - } - // linux: CIO..? - tn.startsWith("linux") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.cio) - } - } - - // darwin based - tn.startsWith("macos") - || tn.startsWith("ios") - || tn.startsWith("watchos") - || tn.startsWith("tvos") -> { - testSourceSet.dependencies { - implementation(libs.ktor.client.darwin) - } - } - } - - mainPresets.add(mainSourceSet) - testPresets.add(testSourceSet) - } - } + // Tier 1 + macosX64() + macosArm64() + iosSimulatorArm64() + iosX64() + + // Tier 2 + linuxX64() +// linuxArm64() + watchosSimulatorArm64() + watchosX64() + watchosArm32() + watchosArm64() + tvosSimulatorArm64() + tvosX64() + tvosArm64() + iosArm64() + + // Tier 3 +// androidNativeArm32() +// androidNativeArm64() +// androidNativeX86() +// androidNativeX64() + mingwX64() +// watchosDeviceArm64() sourceSets { - val commonMain by getting { - dependencies { - api(project(":simbot-component-kook-api")) - api(simbotLogger) - api(simbotUtilLoop) - api(simbotUtilSuspendTransformer) - compileOnly(simbotUtilAnnotations) - api(libs.ktor.client.ws) - api("org.jetbrains.kotlinx:atomicfu:${libs.versions.atomicfu.get()}") - } - } - - val commonTest by getting { - dependencies { - implementation(kotlin("test")) - implementation(libs.kotlinx.coroutines.test) - } - } - - val jvmMain by getting { - dependencies { - compileOnly(simbotUtilAnnotations) // use @Api4J annotation - } + commonMain.dependencies { + compileOnly(simbotUtilAnnotations) + api(project(":simbot-component-kook-api")) + api(simbotLogger) + api(simbotUtilLoop) + api(simbotUtilSuspendTransformer) + api(libs.ktor.serialization.kotlinx.json) + api(libs.kotlinx.serialization.json) + api(libs.kotlinx.coroutines.core) + api(libs.ktor.client.ws) + api("org.jetbrains.kotlinx:atomicfu:${libs.versions.atomicfu.get()}") } -// getByName("jvmMain") { -// dependencies { -// compileOnly(simbotUtilAnnotations) // use @Api4J annotation -// api(project(":simbot-component-kook-api-multi")) -// } -// } - - getByName("jvmTest") { - dependencies { - implementation(libs.ktor.client.cio) - implementation(simbotApi) - implementation(simbotLogger) - implementation(simbotLoggerSlf4j) -// implementation(libs.log4j.api) -// implementation(libs.log4j.core) -// implementation(libs.log4j.slf4j2Impl) - } + commonTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) } - getByName("jsMain") { - dependencies { - implementation(libs.ktor.client.js) - } + jvmMain.dependencies { + compileOnly(simbotUtilAnnotations) // use @Api4J annotation } - val nativeMain by creating { - dependsOn(commonMain) + jvmTest.dependencies { + implementation(libs.ktor.client.cio) + implementation(simbotApi) + implementation(simbotLogger) + implementation(simbotLoggerSlf4j) } - val nativeTest by creating { - dependsOn(commonTest) + jsMain.dependencies { + implementation(libs.ktor.client.js) } - configure(mainPresets) { dependsOn(nativeMain) } - configure(testPresets) { dependsOn(nativeTest) } - } } @@ -192,15 +140,3 @@ atomicfu { jvmVariant = "FU" } - -// suppress all? -//tasks.withType().configureEach { -// dokkaSourceSets.configureEach { -// suppress.set(true) -// perPackageOption { -// suppress.set(true) -// } -// } -//} - - diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/BotConfiguration.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/BotConfiguration.kt index fa526222..905512eb 100644 --- a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/BotConfiguration.kt +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/BotConfiguration.kt @@ -95,7 +95,7 @@ public class BotConfiguration { * 针对 [HttpClientEngineConfig] 中的通用默认属性的配置。 * */ - @Serializable + @kotlinx.serialization.Serializable public data class EngineConfiguration( /** * 参考 [HttpClientEngineConfig.threadsCount][io.ktor.client.engine.HttpClientEngineConfig.threadsCount] diff --git a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/internal/BotImpl.kt b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/internal/BotImpl.kt index f3779c21..6554462d 100644 --- a/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/internal/BotImpl.kt +++ b/simbot-component-kook-stdlib/src/commonMain/kotlin/love/forte/simbot/kook/internal/BotImpl.kt @@ -43,7 +43,6 @@ import love.forte.simbot.kook.event.Signal import love.forte.simbot.logger.LoggerFactory import love.forte.simbot.util.stageloop.loop import kotlin.coroutines.CoroutineContext -import kotlin.jvm.Volatile internal typealias EventProcessor = suspend Event<*>.(raw: String) -> Unit @@ -184,7 +183,7 @@ internal class BotImpl( override var isStarted: Boolean by atomic(false) - @Volatile + @kotlin.concurrent.Volatile private lateinit var _me: Me override suspend fun me(): Me { @@ -202,7 +201,7 @@ internal class BotImpl( private val startLock = Mutex() - @Volatile + @kotlin.concurrent.Volatile private var currentClientJob: Job? = null override suspend fun start(closeBotOnFailure: Boolean) { diff --git a/support-list.md b/support-list.md index bf5adf25..74596bd5 100644 --- a/support-list.md +++ b/support-list.md @@ -1,4 +1,9 @@ -# 功能支持列表 +# 功能支持清单 + +> [!note] +> 清单尚未支持的功能可能会在未来的版本更新中逐步支持,也可能会因为反馈较少而被遗忘。 +> 如果你需要一个尚未支持的 KOOK API(也包括后续官方更新而不存在于此清单中的功能), +> 欢迎提交 [issues](https://github.com/simple-robot/simpler-robot/issues/new/choose) 来让我们知道! ## API diff --git a/website/docs/basic/message.md b/website/docs/basic/message.md new file mode 100644 index 00000000..1919ccb9 --- /dev/null +++ b/website/docs/basic/message.md @@ -0,0 +1,793 @@ +--- +title: 消息 +sidebar_position: 10 +toc_max_heading_level: 4 +--- + + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; +import {version} from '@site/static/version.json' + + +作为一个聊天软件的bot,消息的接收、处理与发送是必不可少的。在 KOOK 组件中,我们理所应当的提供了这方面的能力。 + + +## API、标准库 + +在 API 模块和标准库中,我们提供了针对官方API的对应实现,因此官方的API中对消息的处理是如何的,在这两个模块中就是如何。 + +### 发送消息 + +:::note 消息API + +与消息相关的API都在包路径 `love.forte.simbot.kook.api.message` 中。 + +::: + +你可以通过下面这几个 API 来发送消息: + +- `SendChannelMessageApi`: 发送频道聊天消息 +- `SendDirectMessageApi`: 发送私信聊天消息 + +它们的各个参数等更详细的信息你可以在 [API文档](https://docs.simbot.forte.love/components/kook/) 中找到,这里就不再赘述了。 +以 `SendChannelMessageApi` 为例,提供简单的示例: + + + + +```kotlin +// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。 +// 参考:https://ktor.io/docs/http-client-engines.html +val client = HttpClient(CIO) { + // config... +} + +// 鉴权信息 +// 'Bot' 后面跟的是bot的token,参考 https://developer.kookapp.cn/doc/reference +val authorization = "Bot xxxxxxxxxx" + +// 构建要请求的API,大部分API都有一些可选或必须的参数。 +val api = SendChannelMessageApi.create(targetId = "目标ID", content = "消息内容") + +// 或其他构建方式 +SendChannelMessageApi.create { + content = "" + type = 9 + type(SendMessageType.KMARKDOWN) + nonce = "nonce" + quote = "quote" + tempTargetId = "tempTargetId" +} + +// 得到结果 +val result = api.requestData(client, authorization) +println("result = $result") +println("result.nonce = ${result.nonce}") +println("result.msgId = ${result.msgId}") +println("result.msgTimestamp = ${result.msgTimestamp}") +``` + + + + +```java +// 在Java中构建或获取一个 Ktor 的 HttpClient。 +// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。 +// 参考:https://ktor.io/docs/http-client-engines.html +// 此处以 ktor-cio 引擎为例。 +var client = HttpClientKt.HttpClient(CIO.INSTANCE, config -> { + // config... + return Unit.INSTANCE; + }); + +// 鉴权信息 +// 'Bot' 后面跟的是bot的token,参考 https://developer.kookapp.cn/doc/reference +var authorization = "Bot xxxxxxxxxx"; + +// 构建api +var api = SendChannelMessageApi.create("目标ID", "消息内容"); +// 或其他重载: +SendChannelMessageApi.create(SendMessageType.KMARKDOWN.getValue(), "目标ID", "消息内容"); +SendChannelMessageApi.create(SendMessageType.KMARKDOWN.getValue(), "目标ID", "消息内容", "Quote引用ID", "nonce", "tempTargetId"); +// 或使用builder: +SendChannelMessageApi.builder("目标ID", "消息内容") + .type(SendMessageType.KMARKDOWN) + .content("content") + .quote("quote") + .nonce("nonce") + .tempTargetId("tempTargetId").build(); + +// 请求并得到结果 +var result = api.requestDataBlocking(client, authorization); +System.out.println("result.getMsgId() = " + result.getMsgId()); +System.out.println("result.getNonce() = " + result.getNonce()); +System.out.println("result.getMsgTimestamp() = " + result.getMsgTimestamp()); +``` + + + + +```java +// 在Java中构建或获取一个 Ktor 的 HttpClient。 +// 用于请求的 Ktor HttpClient,如有必要则需要自行引入并选择需要使用的引擎。 +// 参考:https://ktor.io/docs/http-client-engines.html +// 此处以 ktor-cio 引擎为例。 +var client = HttpClientKt.HttpClient(CIO.INSTANCE, config -> { + // config... + return Unit.INSTANCE; + }); + +// 鉴权信息 +// 'Bot' 后面跟的是bot的token,参考 https://developer.kookapp.cn/doc/reference +var authorization = "Bot xxxxxxxxxx"; + +// 构建api +var api = SendChannelMessageApi.create("目标ID", "消息内容"); +// 或其他重载: +SendChannelMessageApi.create(SendMessageType.KMARKDOWN.getValue(), "目标ID", "消息内容"); +SendChannelMessageApi.create(SendMessageType.KMARKDOWN.getValue(), "目标ID", "消息内容", "Quote引用ID", "nonce", "tempTargetId"); +// 或使用builder: +SendChannelMessageApi.builder("目标ID", "消息内容") + .type(SendMessageType.KMARKDOWN) + .content("content") + .quote("quote") + .nonce("nonce") + .tempTargetId("tempTargetId").build(); + +// 请求并得到结果 +api.requestDataAsync(client, authorization).thenAccept(result -> { + // 发送后的结果 + System.out.println("result = " + result); + System.out.println("result.getMsgId() = " + result.getMsgId()); + System.out.println("result.getNonce() = " + result.getNonce()); + System.out.println("result.getMsgTimestamp() = " + result.getMsgTimestamp()); +}); +``` + + + + +:::note USE BOT + +在标准库中,你也可以构建一个 `Bot` 后直接通过 Bot 作为请求的凭证来源,而不再需要手动准备 `HttpClient` 和 `authorization` 了。 + + + + +```kotlin +val bot = BotFactory.create(Ticket.botWsTicket("CLIENT_ID", "TOKEN")) { + // 配置... +} + +// 构建api... +val api = ... + +// 得到结果 +val result = api.requestBy(bot) +``` + + + + +```java +// 准备Ticket +var ticket = Ticket.botWsTicket("CLIENT_ID", "TOKEN"); + +// 配置过程省略... + +// 构建bot +var bot = BotFactory.create(ticket); + +// 构建api... +var api = ... + +// 请求并得到结果 +var result = api.requestByBlocking(bot); +``` + + + + +```java +// 准备Ticket +var ticket = Ticket.botWsTicket("CLIENT_ID", "TOKEN"); + +// 配置过程省略... + +// 构建bot +var bot = BotFactory.create(ticket); + +// 构建api... +var api = ... + +// 请求并得到结果 +api.requestByAsync(bot).thenAccept(result -> { + // ... +}); +``` + + + + +::: + +### 接收消息 + +想要接收消息,首先需要使用核心库注册并启动一个bot来订阅事件。通过订阅消息事件,我们便可以接收到消息。 + + + + +```kotlin +val bot = BotFactory.create(Ticket.botWsTicket("CLIENT_ID", "TOKEN")) { + // 配置... +} + +bot.processor { raw -> // this: Event, raw: String + println("原始JSON: $raw") + println("event: $this") + println("event.extra: ${this.extra}") + println("content: ${this.content}") +} + +bot.startAndJoin() +``` + + + + +```java +// 准备Ticket +var ticket = Ticket.botWsTicket("CLIENT_ID", "TOKEN"); + +// 配置过程省略... + +// 构建bot +var bot = BotFactory.create(ticket); + +bot.blockingProcessor(TextEventExtra.class, (event, raw) -> { + System.out.println("raw = " + raw); + System.out.println("event = " + event); + System.out.println("event.extra = " + event.getExtra()); + System.out.println("content = " + event.getContent()); +}); + +bot.startBlocking(); +bot.joinBlocking(); +``` + + + + +```java +// 准备Ticket +var ticket = Ticket.botWsTicket("CLIENT_ID", "TOKEN"); + +// 配置过程省略... + +// 构建bot +var bot = BotFactory.create(ticket); + +bot.asyncProcessor(TextEventExtra.class, (event, raw) -> { + System.out.println("raw = " + raw); + System.out.println("event = " + event); + System.out.println("event.extra = " + event.getExtra()); + System.out.println("content = " + event.getContent()); + return CompletableFuture.completedFuture(null); +}); + +bot.startAsync().join(); +``` + + + + +其中的 `content` 便是消息内容了。配合事件中其他属性便可以解析、处理消息内容了。 + +## 核心库 + +在核心库中,对消息的发送和接收都有着 simbot API 的风格。 + + +### 消息元素 + +KOOK组件核心库作为 simbot 的组件库之一,自然会对标准消息元素进行部分支持并提供一些其专属的消息元素类型。首先来看看兼容的标准消息元素: + +#### PlainText + +文本消息。这无需多言,文本消息自然能够被支持。 + + + + +```kotlin +val channel = ... + +channel.send("文本消息") +channel.send("文本消息".toText()) +``` + + + + +```java +var channel = ... + +channel.sendBlocking("文本消息"); +channel.sendBlocking(Text.of("文本消息")); +``` + + + + +```java +var channel = ... + +channel.sendAsync("文本消息"); +channel.sendAsync(Text.of("文本消息")); +``` + + + + +#### ResourceImage & Image + +图片消息。可以用来发送图片。 + + + + +```kotlin +val channel = ... + +channel.send(Path("/xx/img.jpg").toResource().toImage()) +``` + + + + +```java +var channel = ... + +var path = Paths.get("/xx/img.jpg"); +var resource = Resource.of(path); +var resourceImage = Image.of(resource); + +channel.sendAsync(resourceImage); +``` + + + + +```java +var channel = ... + +var path = Paths.get("/xx/img.jpg"); +var resource = Resource.of(path); +var resourceImage = Image.of(resource); + +channel.sendAsync(resourceImage); +``` + + + + +#### At + +提及。可以通过 `At` 提及一个**用户**(默认)、一个**频道**或一个**角色**。 + + + + +```kotlin +val channel = ... + +val atUser = At(123.ID) +val atChannel = At(123.ID, KookMessages.AT_TYPE_CHANNEL) +// 或:KookMessages.atChannel(123.ID) +val atRole = At(123.ID, KookMessages.AT_TYPE_ROLE) +// 或:KookMessages.atRole(123.ID) + +channel.send(atUser) +channel.send(atUser + atChannel + atRole) +``` + + + + +```java +var channel = ... + +var atUser = new At(Identifies.ID(123)); +var atChannel = new At(Identifies.ID(123), KookMessages.AT_TYPE_CHANNEL); +// 或:KookMessages.atChannel(Identifies.ID(123)); +var atRole = new At(Identifies.ID(123), KookMessages.AT_TYPE_ROLE); +// 或:KookMessages.atRole(Identifies.ID(123)); + +channel.sendBlocking(atUser); +channel.sendBlocking(Messages.toMessages(atUser, atChannel, atRole)); +``` + + + + +```java +var channel = ... + +var atUser = new At(Identifies.ID(123)); +var atChannel = new At(Identifies.ID(123), KookMessages.AT_TYPE_CHANNEL); +// 或:KookMessages.atChannel(Identifies.ID(123)); +var atRole = new At(Identifies.ID(123), KookMessages.AT_TYPE_ROLE); +// 或:KookMessages.atRole(Identifies.ID(123)); + +channel.sendAsync(atUser); +channel.sendAsync(Messages.toMessages(atUser, atChannel, atRole)); +``` + + + + +#### AtAll + +提及。可以通过 `AtAll` 提及所有。 + + + + +```kotlin +val channel = ... + +channel.send(AtAll) +``` + + + + +```java +var channel = ... + +channel.sendBlocking(AtAll.INSTANCE); +``` + + + + +```java +var channel = ... + +channel.sendAsync(AtAll.INSTANCE); +``` + + + + +#### Emoji + +emoji。是指 [KMarkdown](https://developer.kookapp.cn/doc/kmarkdown) 中所述的 **"emoji"** (`:emoji:`)。 + + + + +```kotlin +val channel = ... + +channel.send(Emoji(123.ID)) +``` + + + + +```java +var channel = ... + +channel.sendBlocking(new Emoji(Identifies.ID(123))); +``` + + + + +```java +var channel = ... + +channel.sendAsync(new Emoji(Identifies.ID(123))); +``` + + + + +除了上述一些 simbot 标准消息类型以外,KOOK组件也提供了一些专属的消息类型来满足更全面的消息发送需求。 + +:::note 类型 + +这些消息类型通常实现了 `KookMessageElement` 接口,并且以 `Kook` 作为类名前缀。 + +::: + +#### KookAssetMessage + +提供一个 API 中上传得到的 `Asset` (附件)和它的类型并作为消息发送。 + + + + +```kotlin +val channel = ... + +// 通过API自行上传一个资源(可以用于避免不必要的多次上传) +val asset = CreateAssetApi.create(...).requestBy(...) + +// 可以选择它是文件,还是图片 +val imgMsg = KookAssetImage(asset) +val assetMsg = KookAsset(asset, MessageType.FILE) // 如果不是文件,你需要指定消息类型 + +channel.send(imgMsg) +channel.send(assetMsg) +``` + + + + +```java +var channel = ... + +// 通过API自行上传一个资源(可以用于避免不必要的多次上传) +var asset = CreateAssetApi.create(...).requestByBlocking(...); + +// 可以选择它是文件,还是图片 +var imgMsg = new KookAssetImage(asset); +var assetMsg = new KookAsset(asset, MessageType.FILE); // 如果不是文件,你需要指定消息类型 + +channel.sendBlocking(imgMsg); +channel.sendBlocking(assetMsg); +``` + + + + +```java +var channel = ... + +// 通过API自行上传一个资源(可以用于避免不必要的多次上传) +CreateAssetApi.create(...).requestByAsync(...).thenAccept(asset -> { + // 可以选择它是文件,还是图片 + var imgMsg = new KookAssetImage(asset); + var assetMsg = new KookAsset(asset, MessageType.FILE); // 如果不是文件,你需要指定消息类型 + + channel.sendAsync(imgMsg); + channel.sendAsync(assetMsg); +}); +``` + + + + + +#### KookKMarkdownMessage + +通过 `KookKMarkdownMessage` 可以做到直接发送一个完全自定义的 `KMarkdown` 消息。 + + + + +```kotlin +val channel = ... + +// 自行构建一个 KMarkdown,并直接作为消息发送。 +val kmd = KookKMarkdownMessage(buildKMarkdown { + bold("这是粗体") + newLine() + hide("隐藏") + newLine() + appendRawMd("直接拼接原始字符串,**不做解析**,_不做处理_") + // 其他... +}) + +channel.send(kmd) +``` + + + + +```java +var channel = ... + +// 构建KMarkdown +var builder = new KMarkdownBuilder(); +builder.bold("加粗").newLine(); +builder.hide("隐藏").newLine(); +builder.appendRawMd("原始的文本,**不做处理**,_直接拼接_"); +var kMarkdown = builder.build(); + +channel.sendBlocking(new KookKMarkdownMessage(kMarkdown)); +``` + + + + +```java +var channel = ... + +// 构建KMarkdown +var builder = new KMarkdownBuilder(); +builder.bold("加粗").newLine(); +builder.hide("隐藏").newLine(); +builder.appendRawMd("原始的文本,**不做处理**,_直接拼接_"); +var kMarkdown = builder.build(); + +channel.sendAsync(new KookKMarkdownMessage(kMarkdown)); +``` + + + + +#### KookCardMessage + +通过 `KookKMarkdownMessage` 来发送 KOOK 中的 [卡片消息](https://developer.kookapp.cn/doc/cardmessage)。 + + + + +```kotlin +val channel = ... + +// 构建card消息 +val cardMessage = KookCardMessage(buildCardMessage { + card { + color = "..." + theme = Theme.PRIMARY + modules { + header("xxx") + // ... + } + // ... + } +}) + +// 也可以直接通过JSON解析 +KookCardMessage(CardMessage.decode("{...}")) // card json value + +channel.send(cardMessage) +``` + + + + +```java +var channel = ... + +// 通过解析卡片消息JSON得到消息对象 +var cardMsg = new KookCardMessage(CardMessage.decode("{...}")); + +channel.sendBlocking(cardMsg); +``` + + + + +```java +var channel = ... + +// 通过解析卡片消息JSON得到消息对象 +var cardMsg = new KookCardMessage(CardMessage.decode("{...}")); + +channel.sendAsync(cardMsg); +``` + + + + +#### KookAtAllHere + +KOOK 中有一个提及所有在线用户的功能,在KMarkdown中表现为 `(met)here(met)`。 + + + + +```kotlin +val channel = ... + +channel.send(KookAtAllHere) +``` + + + + +```java +var channel = ... + +channel.sendBlocking(KookAtAllHere.INSTANCE); +``` + + + + +```java +var channel = ... + +channel.sendAsync(KookAtAllHere.INSTANCE); +``` + + + + + +#### KookAttachmentMessage + +将消息中的多媒体消息 `Attachments` 作为消息元素发送的消息类型。 + +:::note 差异 + +与 `Asset` 不同,`Attachments` 是出现在消息中的,包括发送后或接收的消息,而 `Asset` 是你主动上传的资源。 + +::: + + + + +```kotlin +val channel = ... + +val attachments = ... +// 有4种类型可以选择使用,需要选择一个与 attachements 实际情况匹配的 +val attachmentFile = KookAttachmentFile(attachments) +val attachmentImage = KookAttachmentImage(attachments) +val attachmentVideo = KookAttachmentVideo(attachments) +val attachment = KookAttachment(attachments) + +channel.send(attachmentFile) +channel.send(attachmentImage) +channel.send(attachmentVideo) +channel.send(attachment) +``` + + + + +```java +var channel = ... + +var attachments = ...; +// 有4种类型可以选择使用,需要选择一个与 attachements 实际情况匹配的 +var attachmentFile = new KookAttachmentFile(attachments); +var attachmentImage = new KookAttachmentImage(attachments); +var attachmentVideo = new KookAttachmentVideo(attachments); +var attachment = new KookAttachment(attachments); + +channel.sendBlocking(attachmentFile); +channel.sendBlocking(attachmentImage); +channel.sendBlocking(attachmentVideo); +channel.sendBlocking(attachment); +``` + + + + +```java +var channel = ... + +var attachments = ...; +// 有4种类型可以选择使用,需要选择一个与 attachements 实际情况匹配的 +var attachmentFile = new KookAttachmentFile(attachments); +var attachmentImage = new KookAttachmentImage(attachments); +var attachmentVideo = new KookAttachmentVideo(attachments); +var attachment = new KookAttachment(attachments); + +channel.sendAsync(attachmentFile); +channel.sendAsync(attachmentImage); +channel.sendAsync(attachmentVideo); +channel.sendAsync(attachment); +``` + + + + + +### 发送消息 + +TODO + +### 接收消息 + +TODO diff --git a/website/docs/basic/role.md b/website/docs/basic/role.md new file mode 100644 index 00000000..3d0f308f --- /dev/null +++ b/website/docs/basic/role.md @@ -0,0 +1,7 @@ +--- +title: 角色操作 +sidebar_position: 20 +--- + + +TODO diff --git a/website/docs/basic/unknown-event.md b/website/docs/basic/unknown-event.md index 81ffe93a..f4dacd90 100644 --- a/website/docs/basic/unknown-event.md +++ b/website/docs/basic/unknown-event.md @@ -1,5 +1,6 @@ --- title: 未知事件处理 +sidebar_position: 30 --- diff --git a/website/docs/bot-config/index.md b/website/docs/bot-config/index.md index 8200af18..7771fc8b 100644 --- a/website/docs/bot-config/index.md +++ b/website/docs/bot-config/index.md @@ -2,12 +2,27 @@ title: BOT配置文件 --- +本章节会提供 bot 的配置文件中各属性的含义以及示例。 + +:::info 场景 + +bot 的配置文件通常应用于多组件应用或 Spring Boot 项目中。 + +对于使用Kotlin、不使用SpringBoot的开发者,也可以选择直接使用代码的形式进行配置。 + +::: + +## 示例 + +完整示例: ```json title='xxx.bot.json' { "component": "simbot.kook", - "clientId": "Your client ID", - "token": "Your ws token", + "ticket": { + "clientId": "Your client ID", + "token": "Your ws token" + }, "config": { "isCompress": true, "syncPeriods": { @@ -35,17 +50,27 @@ title: BOT配置文件 } ``` -### `component` +最简示例: -固定值 `simbot.kook`,**必填**,代表此配置文件为KOOK组件的。 +```json title='xxx.bot.json' +{ + "component": "simbot.kook", + "ticket": { + "clientId": "Your client ID", + "token": "Your ws token" + } +} +``` -### `clientId` +## 属性描述 -BOT的 **`Client ID`**。 +### `component` + +固定值 `simbot.kook`,**必填**,代表此配置文件为KOOK组件的。 -### `token` +### `ticket` -BOT使用 **websocket** 模式进行连接的 **`Token`** . +对 bot 身份进行校验、访问 KOOK API 以及连接KOOK服务器进行事件订阅时所需的 bot 票据信息。 :::tip 在哪儿? @@ -53,21 +78,14 @@ BOT使用 **websocket** 模式进行连接的 **`Token`** . ::: -:::caution 后日谈 +#### `ticket.clientId` -日后此类**票据信息**会整合到 `ticket` 字段内。 +BOT的 `Client ID`。 -```json -{ - "component": "simbot.kook", - "ticket": { - "clientId": "Your client ID", - "token": "Your ws token" - } -} -``` +#### `ticket.token` + +BOT使用 **websocket** 模式进行连接的 `token` . -::: ### `config` @@ -96,22 +114,52 @@ BOT使用 **websocket** 模式进行连接的 **`Token`** . } ``` -**`syncPeriods.guild`** +
试着关闭它! + +从 `v3.2.0.0-alpha.8` 重构之后,数据的同步机制比之前的版本而言更加稳定。 +如果你有兴趣,可以尝试直接**禁用定时同步**来观察数据是否会出现差错。 + +```json +{ + "config": { + "syncPeriods": { + "guild": { + "syncPeriod": 0, + "batchDelay": 0 + } + } + } +} +``` + +> _将 `syncPeriod` 设置为 `0` 即可关闭_ + +在预期中,仅通过事件的通知就应满足对内部缓存的同步更新。因此我们希望可以在完全禁用定时同步的情况下依旧可以保证缓存数据的准确性。 +但是目前测试或反馈的数据仍然不足,我们无法完全预判禁用定时同步可能造成的后果或如果因此而产生缓存数据不准确的可能原因。 + +因此我们希望你在可控范围内更多的尝试**禁用定时同步**并在出现问题时及时[**反馈**](https://github.com/simple-robot/simpler-robot/issues/new/choose), +这可以帮助我们完善内部的缓存机制。 + +感谢您的支持与贡献! + +
+ +##### `syncPeriods.guild` 对频道服务器进行同步的周期信息配置,单位毫秒。 -**`syncPeriod`** +##### `syncPeriods.guild.syncPeriod` -对频道服务器进行同步的周期,单位毫秒。 目前服务器同步的同时会去同步此服务器下的所有频道列表与成员列表。 +对频道服务器进行同步的周期,单位毫秒,大于`0`时有效。目前服务器同步的同时会去同步此服务器下的所有频道列表与成员列表。 默认为 `180000`,即 `180000毫秒 -> 180秒 -> 3分钟`。 进行配置的时候需要注意考虑调用频率上限等相关问题。 -**`batchDelay`** +##### `syncPeriods.guild.batchDelay` 同步数据是分页分批次的同步。`batchDelay` 配置每批次后进行挂起等待的时间,单位毫秒。 -可以通过调大此参数来减缓api的请求速率, 默认不等待。 +可以通过调大此参数来减缓 API 的请求速率, 默认不等待。 配置此属性可一定程度上降低触发调用频率限制的风险。 @@ -130,13 +178,13 @@ BOT使用 **websocket** 模式进行连接的 **`Token`** . 它们的配置项都与 Ktor 的 `HttpClientEngineConfig` 的配置相同,没有额外的含义。 -**`threadsCount`** +##### `threadsCount` > Specifies network threads count advice. 更多参考 [Ktor文档](https://ktor.io/docs/http-client-engines.html#configure) -**`pipelining`** +##### `pipelining` > Enables HTTP pipelining advice. @@ -178,19 +226,19 @@ BOT内进行API请求时候的超时时间配置。(基于 [Ktor HttpTimeout]( ::: -**`connectTimeoutMillis`** +##### `connectTimeoutMillis` > a time period required to process an HTTP call: from sending a request to receiving a response. 更多参考 [Ktor HttpTimeout](https://ktor.io/docs/timeout.html#configure_plugin) -**`requestTimeoutMillis`** +##### `requestTimeoutMillis` > a time period in which a client should establish a connection with a server. 更多参考 [Ktor HttpTimeout](https://ktor.io/docs/timeout.html#configure_plugin) -**`socketTimeoutMillis`** +##### `socketTimeoutMillis` > a maximum time of inactivity between two data packets when exchanging data with a server. diff --git a/website/docs/quick-start/_category_.json b/website/docs/quick-start/_category_.json index f615df50..da045185 100644 --- a/website/docs/quick-start/_category_.json +++ b/website/docs/quick-start/_category_.json @@ -1,4 +1,4 @@ { "position": 10, - "label": "快速开始" + "label": "快速开始🚀" } diff --git a/website/docs/quick-start/api.md b/website/docs/quick-start/api.md index bc35b1c7..eb6b3171 100644 --- a/website/docs/quick-start/api.md +++ b/website/docs/quick-start/api.md @@ -1,5 +1,5 @@ --- -title: 使用API模块 +title: 使用API sidebar_position: 2 --- @@ -19,16 +19,40 @@ API模块是**独立的**,实质上并不依赖 simbot API。你可以单独 +`Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin): + +{` +// 使用 Gradle 的 kotlin 插件来允许自动选择依赖的对应平台,比如JVM或JS等。 +plugin { + kotlin("jvm") version "合适且较新的版本" + // 或 multiplatform, 如果你使用多平台的话 + // 如果你使用 Java,也最好添加此插件,因此它可以帮助你自动选择 -jvm 的依赖,而不需要主动添加此后缀 +} +`.trim()} + +依赖: + {` -// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。 implementation("love.forte.simbot.component:simbot-component-kook-api:${version}") // 版本参考下文所述的 Releases `.trim()} +`Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin): + +{` +// 使用 Gradle 的 kotlin 插件来允许自动选择依赖的对应平台,比如JVM或JS等。 +plugin { + id 'org.jetbrains.kotlin.jvm' version '合适且较新的版本' + // 或 org.jetbrains.kotlin.multiplatform, 如果你使用多平台的话 + // 如果你使用 Java,也最好添加此插件,因此它可以帮助你自动选择 -jvm 的依赖,而不需要主动添加此后缀 +} +`.trim()} + +依赖: + {` -// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。 implementation 'love.forte.simbot.component:simbot-component-kook-api:${version}' // 版本参考下文所述的 Releases `.trim()} @@ -37,11 +61,11 @@ implementation 'love.forte.simbot.component:simbot-component-kook-api:${version} {` -love.forte.simbot.component - -simbot-component-kook-api-jvm - -${version} + love.forte.simbot.component + + simbot-component-kook-api-jvm + + ${version} `.trim()} @@ -141,7 +165,6 @@ implementation("io.ktor:ktor-client-curl:<合适且较新的Ktor版本>") 或者如果 Java 版本 `>= Java11`, 使用 [`Java`](https://ktor.io/docs/http-client-engines.html#java) 引擎: ```xml - io.ktor ktor-client-java diff --git a/website/docs/quick-start/simbot-core.md b/website/docs/quick-start/simbot-core.md index e4a64d2c..0382f78c 100644 --- a/website/docs/quick-start/simbot-core.md +++ b/website/docs/quick-start/simbot-core.md @@ -3,11 +3,6 @@ title: 使用simbot核心库 sidebar_position: 3 --- -:::info 其他参考 - -你可以参考simbot3官网中的 [《使用核心库》](https://simbot.forte.love/docs/quick-start/core) - -::: :::danger TODO @@ -16,3 +11,8 @@ sidebar_position: 3 你可以先参考 [使用SpringBoot](spring-boot),它相当于在 Spring Boot 环境下使用simbot核心库。 ::: +:::info 其他参考 + +你也可以参考simbot3官网中的 [《使用核心库》](https://simbot.forte.love/docs/quick-start/core) + +::: diff --git a/website/docs/quick-start/spring-boot.md b/website/docs/quick-start/spring-boot.md index 03ec41e2..c96253e1 100644 --- a/website/docs/quick-start/spring-boot.md +++ b/website/docs/quick-start/spring-boot.md @@ -23,8 +23,12 @@ import {version} from '@site/static/version.json' ## 项目构建 +**1. 准备 Spring Boot 项目** + 首先准备一个SpringBoot项目。可以考虑前往 [start.spring.io](https://start.spring.io) 或借助IDE等工具。 +**2. 添加 simbot 依赖** + 然后**额外添加**两个我们需要的依赖: - `love.forte.simbot.boot:simboot-core-spring-boot-starter`
([**版本参考**](https://github.com/simple-robot/simpler-robot/releases)) - `love.forte.simbot.component:simbot-component-kook-core`
([**版本参考**](https://github.com/simple-robot/simbot-component-kook/releases)) @@ -34,6 +38,8 @@ import {version} from '@site/static/version.json' 注意,在使用 Spring Boot 的时候你需要一些能够使程序保持运行的组件,例如通过 `spring-web` 启用一个服务器,否则程序可能会自动终止。 因为simbot的 starter 并不提供维持程序运行的能力。 +当然,你也可以选择使用一个线程来自行实现程序保活。 + ::: @@ -58,7 +64,6 @@ implementation 'love.forte.simbot.component:simbot-component-kook-core:${version
- {` @@ -79,6 +84,102 @@ implementation 'love.forte.simbot.component:simbot-component-kook-core:${version
+**3. 选择并安装合适的 Ktor Client 依赖** + +前往 [Ktor: HTTP client Engines](https://ktor.io/docs/http-client-engines.html) 选择并使用一个合适的、支持 websocket 连接 的 HTTP Client 引擎。 + +:::caution 限制条件 + +**注意:** 你需要选择一个支持**HTTP 1.1**和**WS Client**的引擎。部分引擎可能不支持**WS Client**,请注意区分。 + +各引擎实现的限制可参考 [Ktor文档](https://ktor.io/docs/http-client-engines.html#limitations)。 + +::: + +例如: + + + + +以 [`CIO`](https://ktor.io/docs/http-client-engines.html#cio) 引擎为例: + +```kotlin +// 或使用 runtimeOnly +implementation("io.ktor:ktor-client-cio:<合适且较新的Ktor版本>") +``` + +如果没有使用 `Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin),则主动分配平台后缀: + +```kotlin +// 或使用 runtimeOnly +implementation("io.ktor:ktor-client-cio-jvm:<合适且较新的Ktor版本>") +``` + +或者如果 Java 版本 `>= Java11`, 可以使用 [`Java`](https://ktor.io/docs/http-client-engines.html#java) 引擎: + +```kotlin +// 或使用 runtimeOnly +implementation("io.ktor:ktor-client-java:<合适且较新的Ktor版本>") +``` + + + + +以 [`CIO`](https://ktor.io/docs/http-client-engines.html#cio) 引擎为例: + +```groovy +// 或使用 runtimeOnly +implementation 'io.ktor:ktor-client-cio:<合适且较新的Ktor版本>' +``` + +如果没有使用 `Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin),则主动分配平台后缀: + +```kotlin +// 或使用 runtimeOnly +implementation 'io.ktor:ktor-client-cio-jvm:<合适且较新的Ktor版本>' +``` + +或者如果 Java 版本 `>= Java11`, 可以使用 [`Java`](https://ktor.io/docs/http-client-engines.html#java) 引擎: + +```groovy +// 或使用 runtimeOnly +implementation 'io.ktor:ktor-client-java:<合适且较新的Ktor版本>' +``` + + + + +以 [`CIO`](https://ktor.io/docs/http-client-engines.html#cio) 引擎为例: + +```xml + + + io.ktor + ktor-client-cio-jvm + 合适且较新的Ktor版本 + + + runtime + +``` + +或者如果 Java 版本 `>= Java11`, 可以使用 [`Java`](https://ktor.io/docs/http-client-engines.html#java) 引擎: + +```xml + + + io.ktor + ktor-client-java + 合适且较新的Ktor版本 + + + runtime + +``` + + + + ## BOT配置 接下来,在项目**资源文件**目录下的 `simbot-bots` 文件夹中创建一个用于配置bot的配置文件 `xxx.bot.json` ( 文件名随意,扩展名应为 `.bot` 或 `.bot.json` ) 。 diff --git a/website/docs/quick-start/stdlib.md b/website/docs/quick-start/stdlib.md index ae6cf8b0..71a47b19 100644 --- a/website/docs/quick-start/stdlib.md +++ b/website/docs/quick-start/stdlib.md @@ -21,16 +21,40 @@ stdlib标准库模块基于 **KMP** 构建项目,支持 **JVM、JS、Native** +`Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin): + +{` +// 使用 Gradle 的 kotlin 插件来允许自动选择依赖的对应平台,比如JVM或JS等。 +plugin { +kotlin("jvm") version "合适且较新的版本" +// 或 multiplatform, 如果你使用多平台的话 +// 如果你使用 Java,也最好添加此插件,因此它可以帮助你自动选择 -jvm 的依赖,而不需要主动添加此后缀 +} +`.trim()} + +依赖: + {` -// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。 implementation("love.forte.simbot.component:simbot-component-kook-stdlib:${version}") // 版本参考下文所述的 Releases `.trim()} +`Gradle` 的 [`Kotlin` 插件](https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin): + +{` +// 使用 Gradle 的 kotlin 插件来允许自动选择依赖的对应平台,比如JVM或JS等。 +plugin { +id 'org.jetbrains.kotlin.jvm' version '合适且较新的版本' +// 或 org.jetbrains.kotlin.multiplatform, 如果你使用多平台的话 +// 如果你使用 Java,也最好添加此插件,因此它可以帮助你自动选择 -jvm 的依赖,而不需要主动添加此后缀 +} +`.trim()} + +依赖: + {` -// 不要忘记使用 Gradle 的 kotlin 插件来允许自动选择对应平台,比如JVM或JS等。 implementation 'love.forte.simbot.component:simbot-component-kook-stdlib:${version}' // 版本参考下文所述的 Releases `.trim()} @@ -39,11 +63,11 @@ implementation 'love.forte.simbot.component:simbot-component-kook-stdlib:${versi {` -love.forte.simbot.component - -simbot-component-kook-stdlib-jvm - -${version} + love.forte.simbot.component + + simbot-component-kook-stdlib-jvm + + ${version} `.trim()} @@ -56,7 +80,7 @@ implementation 'love.forte.simbot.component:simbot-component-kook-stdlib:${versi :::caution 限制条件 -**注意:** 你需要选择一个支持**HTTP 1.1**和**WS Client**的引擎。部分引擎可能仅能支持其中一个(例如不支持WS Client)。 +**注意:** 你需要选择一个支持**HTTP 1.1**和**WS Client**的引擎。部分引擎可能不支持WS Client,请注意区分。 各引擎实现的限制可参考 [Ktor文档](https://ktor.io/docs/http-client-engines.html#limitations)。 diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index bab6c0ac..81d91552 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -19,11 +19,11 @@ async function config() { // Set the production url of your site here // url: 'https://component-kook.simbot.forte.love', - url: 'https://simple-robot.github.io', + url: 'https://component-kook.simbot.forte.love', // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' - baseUrl: '/simbot-component-kook/', + baseUrl: '/', // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. diff --git a/website/static/CNAME b/website/static/CNAME new file mode 100644 index 00000000..a0533a72 --- /dev/null +++ b/website/static/CNAME @@ -0,0 +1 @@ +component-kook.simbot.forte.love