Skip to content

Commit

Permalink
Merge pull request #53 from simple-robot/dev/main
Browse files Browse the repository at this point in the history
Release: v0.7.0
  • Loading branch information
ForteScarlet authored Jun 20, 2024
2 parents 2e48a8d + e9da669 commit b756652
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .changelog/v0.7.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
> 对应核心版本: [**v4.0.1**](https://github.com/simple-robot/simpler-robot/releases/tag/v4.0.1)

我们欢迎并期望着您的的[反馈](https://github.com/simple-robot/simbot-component-onebot/issues)[协助](https://github.com/simple-robot/simbot-component-onebot/pulls)
感谢您的贡献与支持!

也欢迎您为我们献上一颗 `star`,这是对我们最大的鼓励与认可!
4 changes: 2 additions & 2 deletions Writerside/v.list
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<var name="jb" value="阻塞"/>
<var name="ja" value="异步"/>
<var name="jr" value="响应式"/>
<var name="version" value="0.6.0"/>
<var name="version" value="0.7.0"/>
<var name="d-group" value="love.forte.simbot.component"/>
<var name="d-ob11-id" value="simbot-component-onebot-v11"/>
<var name="minimum-core-version" value="4.0.0"/>
<var name="minimum-core-version" value="4.0.1"/>
</vars>
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/P.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ktor = "2.3.11"
openjdk-jmh = "1.35"
log4j = "2.20.0"
# simbot
simbot = "4.0.0"
simbot = "4.0.1"
suspendTransform = "0.9.0"
gradleCommon = "0.4.0"
# ksp
Expand Down Expand Up @@ -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" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -448,6 +453,8 @@ internal class OneBotBotImpl(
}
} ?: continue

logger.debug("Received raw event: {}", eventRaw)

val event = kotlin.runCatching {
resolveRawEvent(eventRaw)
}.getOrElse { e ->
Expand All @@ -460,9 +467,9 @@ internal class OneBotBotImpl(
)
// 接收的事件解析出现错误,
// 这应该是预期外的情况,
// 直接终止 session 和 Bot
// 直接终止 session, 但是不终止 Bot,
// 只有当重连次数用尽才考虑终止 Bot。
session.closeExceptionally(ex)
job.cancel(exMsg, ex)

throw ex
}
Expand All @@ -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) {
Expand All @@ -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()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] 类型实现。
Expand All @@ -28,6 +30,15 @@ import love.forte.simbot.common.id.LongID
*
* [UnknownEvent] 要求事件体必须包括 [time], [selfId] 和 [postType]。
*
* 如果 [UnknownEvent] 是由于某些异常而产生(例如原本事件进行序列化但是失败了),
* 那么失败的原因则会通过 [reason] 提供。
*
* ### 内部构造
*
* [UnknownEvent] 应当始终由内部使用、构造,
* 不要在其他地方自行构造 [UnknownEvent],
* 它的构造函数不保证任何源码或二进制兼容。
*
* ### FragileAPI
*
* 这是一个具有**特殊规则**的事件类型。
Expand All @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import love.forte.simbot.resource.toStringResource
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic

/**
* 将事件中接收到的 [OneBotMessageSegment] 解析为 [Message.Element]。
Expand All @@ -57,6 +58,7 @@ public fun OneBotMessageSegment.resolveToMessageElement(): Message.Element {
* @see resolveToOneBotSegment
*/
@InternalOneBotAPI
@JvmSynthetic
public suspend fun Message.resolveToOneBotSegmentList(): List<OneBotMessageSegment> {
return when (this) {
is Message.Element -> resolveToOneBotSegment()
Expand All @@ -71,6 +73,7 @@ public suspend fun Message.resolveToOneBotSegmentList(): List<OneBotMessageSegme
* 将一个 [Message.Element] 转化为用于API请求的 [OneBotMessageSegment]。
*/
@InternalOneBotAPI
@JvmSynthetic
public suspend fun Message.Element.resolveToOneBotSegment(): OneBotMessageSegment? {
return when (this) {
// OB组件的 segment 类型,直接使用
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
requires simbot.component.onebot.common;
requires static simbot.common.annotations;
requires transitive kotlinx.serialization.core;
requires simbot.common.suspendrunner;
requires kotlinx.coroutines.core;

exports love.forte.simbot.component.onebot.v11.message;
exports love.forte.simbot.component.onebot.v11.message.segment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,100 @@

package love.forte.simbot.component.onebot.v11.message

import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import love.forte.simbot.annotations.Api4J
import love.forte.simbot.annotations.InternalSimbotAPI
import love.forte.simbot.component.onebot.common.annotations.InternalOneBotAPI
import love.forte.simbot.component.onebot.v11.message.segment.OneBotImage
import love.forte.simbot.component.onebot.v11.message.segment.OneBotMessageSegment
import love.forte.simbot.message.JvmOfflineImageValueResolver
import love.forte.simbot.message.Message
import love.forte.simbot.message.OfflineImage
import love.forte.simbot.message.OfflineImageValueResolver
import love.forte.simbot.resource.Resource
import love.forte.simbot.resource.URIResource
import love.forte.simbot.resource.toResource
import love.forte.simbot.suspendrunner.reserve.SuspendReserve
import love.forte.simbot.suspendrunner.reserve.suspendReserve
import love.forte.simbot.suspendrunner.runInAsync
import love.forte.simbot.suspendrunner.runInNoScopeBlocking
import java.io.File
import java.net.URI
import java.nio.file.Path
import java.util.concurrent.CompletableFuture
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume

/**
* 将 [Message] 解析为一用于API请求的 [OneBotMessageSegment] 列表。
*
* @see resolveToOneBotSegmentList
*/
@InternalOneBotAPI
@Api4J
public fun Message.resolveToOneBotSegmentListBlocking(): List<OneBotMessageSegment> =
runInNoScopeBlocking { resolveToOneBotSegmentList() }

/**
* 将 [Message] 解析为一用于API请求的 [OneBotMessageSegment] 列表。
*
* @see resolveToOneBotSegmentList
*/
@OptIn(InternalSimbotAPI::class)
@InternalOneBotAPI
@Api4J
public fun Message.resolveToOneBotSegmentListAsync(): CompletableFuture<out List<OneBotMessageSegment>> =
runInAsync { resolveToOneBotSegmentList() }

/**
* 将 [Message] 解析为一用于API请求的 [OneBotMessageSegment] 列表。
*
* @see resolveToOneBotSegmentList
*/
@OptIn(InternalSimbotAPI::class, DelicateCoroutinesApi::class)
@InternalOneBotAPI
@Api4J
public fun Message.resolveToOneBotSegmentListReserve(): SuspendReserve<List<OneBotMessageSegment>> =
suspendReserve(
GlobalScope,
EmptyCoroutineContext
) { resolveToOneBotSegmentList() }

/**
* 将一个 [Message.Element] 转化为用于API请求的 [OneBotMessageSegment]。
* @see resolveToOneBotSegment
*/
@InternalOneBotAPI
@Api4J
public fun Message.Element.resolveToOneBotSegmentBlocking(): OneBotMessageSegment? =
runInNoScopeBlocking { resolveToOneBotSegment() }

/**
* 将一个 [Message.Element] 转化为用于API请求的 [OneBotMessageSegment]。
* @see resolveToOneBotSegment
*/
@OptIn(InternalSimbotAPI::class)
@InternalOneBotAPI
@Api4J
public fun Message.Element.resolveToOneBotSegmentAsync(): CompletableFuture<out OneBotMessageSegment?> =
runInAsync { resolveToOneBotSegment() }

/**
* 将一个 [Message.Element] 转化为用于API请求的 [OneBotMessageSegment]。
* @see resolveToOneBotSegment
*/
@OptIn(DelicateCoroutinesApi::class, InternalSimbotAPI::class)
@InternalOneBotAPI
@Api4J
public fun Message.Element.resolveToOneBotSegmentReserve(): SuspendReserve<OneBotMessageSegment?> =
suspendReserve(
GlobalScope,
EmptyCoroutineContext
) { resolveToOneBotSegment() }


internal actual fun offlineImageResolver(): OfflineImageValueResolver<Continuation<OneBotMessageSegment?>> =
object : JvmOfflineImageValueResolver<Continuation<OneBotMessageSegment?>>() {
override fun resolveUnknownInternal(image: OfflineImage, context: Continuation<OneBotMessageSegment?>) {
Expand Down

0 comments on commit b756652

Please sign in to comment.