diff --git a/buildSrc/src/main/kotlin/P.kt b/buildSrc/src/main/kotlin/P.kt index 70e3c1b..5e5bd27 100644 --- a/buildSrc/src/main/kotlin/P.kt +++ b/buildSrc/src/main/kotlin/P.kt @@ -41,7 +41,7 @@ object P { override val homepage: String get() = HOMEPAGE - private val baseVersion = v(0, 6, 0) + private val baseVersion = v(0, 7, 0) val snapshotVersion = baseVersion - Version.SNAPSHOT override val version = if (isSnapshot()) snapshotVersion else baseVersion diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6c86dc7..29c5786 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,6 +71,9 @@ ktor-client-winhttp = { group = "io.ktor", name = "ktor-client-winhttp", version # see https://ktor.io/docs/http-client-engines.html#darwin ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" } +ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor" } +ktor-server-ws = { module = "io.ktor:ktor-server-websockets", version.ref = "ktor" } + # log4j log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" } log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" } diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/build.gradle.kts b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/build.gradle.kts index cc24753..a8b9e11 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/build.gradle.kts +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/build.gradle.kts @@ -100,6 +100,8 @@ kotlin { implementation(libs.kotlinPoet) implementation(libs.kotlinx.coroutines.reactor) api(libs.ktor.client.java) + implementation(libs.ktor.server.netty) + implementation(libs.ktor.server.ws) } } } diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/bot/internal/OneBotBotImpl.kt b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/bot/internal/OneBotBotImpl.kt index 8c7299b..fa725a4 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/bot/internal/OneBotBotImpl.kt +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-core/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/core/bot/internal/OneBotBotImpl.kt @@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonPrimitive @@ -369,7 +370,11 @@ internal class OneBotBotImpl( } } - receiveEvent(currentSession) + kotlin.runCatching { + receiveEvent(currentSession) + }.onFailure { ex -> + logger.error("Event reception is interrupted: {}", ex.message, ex) + } // The Session is done or dead, // or the job is done. @@ -448,6 +453,8 @@ internal class OneBotBotImpl( } } ?: continue + logger.debug("Received raw event: {}", eventRaw) + val event = kotlin.runCatching { resolveRawEvent(eventRaw) }.getOrElse { e -> @@ -460,9 +467,9 @@ internal class OneBotBotImpl( ) // 接收的事件解析出现错误, // 这应该是预期外的情况, - // 直接终止 session 和 Bot + // 直接终止 session, 但是不终止 Bot, + // 只有当重连次数用尽才考虑终止 Bot。 session.closeExceptionally(ex) - job.cancel(exMsg, ex) throw ex } @@ -489,10 +496,10 @@ internal class OneBotBotImpl( val subTypeFieldName = resolveEventSubTypeFieldName(postType) ?: "${postType}_type" val subType = obj[subTypeFieldName]?.jsonPrimitive?.content - fun toUnknown(): UnknownEvent { + fun toUnknown(reason: Throwable? = null): UnknownEvent { val time = obj["time"]?.jsonPrimitive?.long ?: -1L val selfId = obj["self_id"]?.jsonPrimitive?.long?.ID ?: 0L.ID - return UnknownEvent(time, selfId, postType, text) + return UnknownEvent(time, selfId, postType, text, obj, reason) } if (subType == null) { @@ -501,7 +508,29 @@ internal class OneBotBotImpl( } resolveEventSerializer(postType, subType)?.let { - return OneBot11.DefaultJson.decodeFromJsonElement(it, obj) + return try { + OneBot11.DefaultJson.decodeFromJsonElement(it, obj) + } catch (serEx: SerializationException) { + logger.error( + "Received raw event '{}' decode failed because of serialization: {}" + + "It will be pushed as an UnknownEvent", + text, + serEx.message, + serEx + ) + + toUnknown(serEx) + } catch (argEx: IllegalArgumentException) { + logger.error( + "Received raw event '{}' decode failed because of illegal argument: {}" + + "It will be pushed as an UnknownEvent", + text, + argEx.message, + argEx + ) + + toUnknown(argEx) + } } ?: run { return toUnknown() } 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 a0583f0..b1ba4de 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 @@ -61,6 +61,7 @@ kotlin { commonMain.dependencies { implementation(libs.simbot.api) implementation(libs.simbot.common.annotations) + implementation(libs.kotlinx.serialization.json) implementation(project(":simbot-component-onebot-common")) api(project(":simbot-component-onebot-v11:simbot-component-onebot-v11-common")) diff --git a/simbot-component-onebot-v11/simbot-component-onebot-v11-event/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/event/UnknownEvent.kt b/simbot-component-onebot-v11/simbot-component-onebot-v11-event/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/event/UnknownEvent.kt index bc3fc30..b41c4e8 100644 --- a/simbot-component-onebot-v11/simbot-component-onebot-v11-event/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/event/UnknownEvent.kt +++ b/simbot-component-onebot-v11/simbot-component-onebot-v11-event/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/event/UnknownEvent.kt @@ -17,9 +17,11 @@ package love.forte.simbot.component.onebot.v11.event +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.JsonObject import love.forte.simbot.annotations.FragileSimbotAPI import love.forte.simbot.common.id.LongID - +import love.forte.simbot.component.onebot.common.annotations.InternalOneBotAPI /** * 用于“兜底”的 [RawEvent] 类型实现。 @@ -28,6 +30,15 @@ import love.forte.simbot.common.id.LongID * * [UnknownEvent] 要求事件体必须包括 [time], [selfId] 和 [postType]。 * + * 如果 [UnknownEvent] 是由于某些异常而产生(例如原本事件进行序列化但是失败了), + * 那么失败的原因则会通过 [reason] 提供。 + * + * ### 内部构造 + * + * [UnknownEvent] 应当始终由内部使用、构造, + * 不要在其他地方自行构造 [UnknownEvent], + * 它的构造函数不保证任何源码或二进制兼容。 + * * ### FragileAPI * * 这是一个具有**特殊规则**的事件类型。 @@ -37,12 +48,41 @@ import love.forte.simbot.common.id.LongID * @author ForteScarlet */ @FragileSimbotAPI -public data class UnknownEvent( +public class UnknownEvent @InternalOneBotAPI constructor( override val time: Long, override val selfId: LongID, override val postType: String, /** - * 原始的JSON字符串 + * 原始的JSON字符串, + * 也是判断 [UnknownEvent] 之间是否相同的**唯一依据**。 */ public val raw: String, -) : RawEvent + + /** + * [raw] 对应解析的 [JsonObject] 对象。 + */ + public val rawJson: JsonObject, + + /** + * 如果是由于异常而产生,则此处为异常的原因。 + * 通常会是 [SerializationException]。 + */ + public val reason: Throwable? = null, + +) : RawEvent { + override fun toString(): String = + "UnknownEvent(time=$time, selfId=$selfId, postType='$postType')" + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is UnknownEvent) return false + + if (raw != other.raw) return false + + return true + } + + override fun hashCode(): Int { + return raw.hashCode() + } +}