Skip to content

Commit 2341686

Browse files
committed
hold events, call handlers after real connected
1 parent 58a3a4c commit 2341686

File tree

15 files changed

+112
-46
lines changed

15 files changed

+112
-46
lines changed

docs/configuration.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@
44

55
## overflow.json
66

7-
|| 默认值 | 注释 |
8-
|---------------------------|-----------------------|------------------------------------------------------------------------------------------------------|
9-
| `ws_host` | `ws://127.0.0.1:3001` | 正向WebSocket连接地址 |
10-
| `reversed_ws_port` | `-1` | 反向WebSocket服务器端口,`-1` 为不开启反向WS。开启反向WS将会禁用正向WS连接 |
11-
| `token` | | 鉴权令牌,留空则不进行鉴权 |
12-
| `no_platform` | `false` | 是否禁止 Overflow 调用需要账号凭证的网络接口,如获取分享Key、群活跃等。在**非QQ平台****无法获取账号凭证**的平台 (如 Gensokyo) 使用 Overflow 请开启该选项 |
13-
| `use_cq_code` | `false` | 发送消息时,是否使用 CQ 码格式 |
14-
| `retry_times` | `5` | 正向WS断开连接后重连尝试次数,设为 `-1` 禁用自动重连 |
15-
| `retry_wait_mills` | `5000` | 每次重连之间的间隔时间 (毫秒) |
16-
| `retry_rest_mills` | `60000` | 重连次数用完后,等待多长时间 (毫秒) 后,重置次数再进行重连。设为 `-1` 禁用此功能 |
17-
| `heartbeat_check_seconds` | `60` | WebSocket 心跳策略检查时间 (秒),设为 `0` 关闭心跳策略 |
18-
| `resource_cache` | - | 媒体消息(图片、语音、短视频)自动下载缓存配置,更详细的信息请见下方 |
7+
|| 默认值 | 注释 |
8+
|--------------------------------|-----------------------|------------------------------------------------------------------------------------------------------|
9+
| `ws_host` | `ws://127.0.0.1:3001` | 正向WebSocket连接地址 |
10+
| `reversed_ws_port` | `-1` | 反向WebSocket服务器端口,`-1` 为不开启反向WS。开启反向WS将会禁用正向WS连接 |
11+
| `token` | | 鉴权令牌,留空则不进行鉴权 |
12+
| `no_platform` | `false` | 是否禁止 Overflow 调用需要账号凭证的网络接口,如获取分享Key、群活跃等。在**非QQ平台****无法获取账号凭证**的平台 (如 Gensokyo) 使用 Overflow 请开启该选项 |
13+
| `use_cq_code` | `false` | 发送消息时,是否使用 CQ 码格式 |
14+
| `retry_times` | `5` | 正向WS断开连接后重连尝试次数,设为 `-1` 禁用自动重连 |
15+
| `retry_wait_mills` | `5000` | 每次重连之间的间隔时间 (毫秒) |
16+
| `retry_rest_mills` | `60000` | 重连次数用完后,等待多长时间 (毫秒) 后,重置次数再进行重连。设为 `-1` 禁用此功能 |
17+
| `heartbeat_check_seconds` | `60` | WebSocket 心跳策略检查时间 (秒),设为 `0` 关闭心跳策略 |
18+
| `resource_cache` | - | 媒体消息(图片、语音、短视频)自动下载缓存配置,更详细的信息请见下方 |
19+
| `drop_events_before_connected` | `true` | 是否抛弃所有在Bot成功连接之前传入的事件。比如 go-cqhttp 会在连接之后,在 Overflow 获取到 Bot 信息之前,推送以前未收到的消息。如果开启此项,则丢弃这些消息 |
1920

2021
## resource_cache
2122

overflow-core-api/src/main/kotlin/top/mrxiaom/overflow/BotBuilder.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class BotBuilder private constructor(
2525
private var noPlatform: Boolean = false,
2626
private var useCQCode: Boolean = false,
2727
private var useGroupUploadEventForFileMessage: Boolean = false,
28+
private var dropEventsBeforeConnected: Boolean = true,
2829
private var logger: Logger? = null,
2930
private var parentJob: Job? = null,
3031
private var configuration: BotConfiguration = BotConfiguration {
@@ -120,6 +121,15 @@ public class BotBuilder private constructor(
120121
this.useGroupUploadEventForFileMessage = true
121122
}
122123

124+
/**
125+
* 是否保留所有在Bot成功连接之前传入的事件。
126+
*
127+
* 比如 go-cqhttp 会在连接之后,在 Overflow 获取到 Bot 信息之前,推送以前未收到的消息。如果不开启此项,则这些消息会被抛弃,反之会在瞬时接收到很多消息
128+
*/
129+
public fun keepEventsBeforeConnected(): BotBuilder = apply {
130+
this.dropEventsBeforeConnected = false
131+
}
132+
123133
/**
124134
* 覆写用于 Onebot 的日志记录器
125135
*/
@@ -178,6 +188,7 @@ public class BotBuilder private constructor(
178188
noPlatform = noPlatform,
179189
useCQCode = useCQCode,
180190
useGroupUploadEventForFileMessage = useGroupUploadEventForFileMessage,
191+
dropEventsBeforeConnected = dropEventsBeforeConnected,
181192
logger = logger,
182193
parentJob = parentJob,
183194
configuration = configuration,
@@ -216,6 +227,7 @@ interface IBotStarter {
216227
noPlatform: Boolean,
217228
useCQCode: Boolean,
218229
useGroupUploadEventForFileMessage: Boolean,
230+
dropEventsBeforeConnected: Boolean,
219231
logger: Logger?,
220232
parentJob: Job?,
221233
configuration: BotConfiguration,

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/config/BotConfig.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ class BotConfig(
5555
* 是否不接收群聊的 file 消息,使用 group_upload 事件作为群文件消息
5656
*/
5757
val useGroupUploadEventForFileMessage: Boolean = false,
58+
/**
59+
* 是否抛弃所有在Bot成功连接之前传入的事件。
60+
*
61+
* 比如 go-cqhttp 会在连接之后,在 Overflow 获取到 Bot 信息之前,推送以前未收到的消息。如果开启此项,则丢弃这些消息
62+
*/
63+
val dropEventsBeforeConnected: Boolean = true,
5864
val parentJob: Job? = null
5965
) {
6066
val isInReverseMode get() = reversedPort in 1..65535

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/connection/ConnectFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import java.net.URI
1919
*
2020
* @param config 配置
2121
*/
22-
class ConnectFactory private constructor(
22+
internal class ConnectFactory private constructor(
2323
private val config: BotConfig,
2424
private val parent: Job?,
2525
private val logger: Logger,

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/connection/IAdapter.kt

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cn.evolvefield.onebot.client.connection
22

33
import cn.evolvefield.onebot.client.handler.ActionHandler
44
import cn.evolvefield.onebot.client.handler.EventBus
5+
import cn.evolvefield.onebot.client.handler.EventHolder
56
import cn.evolvefield.onebot.client.util.ActionSendRequest
67
import cn.evolvefield.onebot.client.util.OnebotException
78
import cn.evolvefield.onebot.sdk.util.ignorable
@@ -12,12 +13,14 @@ import kotlinx.coroutines.launch
1213
import kotlinx.coroutines.sync.Mutex
1314
import kotlinx.coroutines.sync.withLock
1415
import kotlinx.coroutines.withTimeoutOrNull
16+
import net.mamoe.mirai.Bot
1517
import org.slf4j.Logger
1618

17-
interface IAdapter {
19+
internal interface IAdapter {
1820
val scope: CoroutineScope
1921
val actionHandler: ActionHandler
2022
val logger: Logger
23+
val eventsHolder: MutableMap<Long, MutableList<EventHolder>>
2124

2225
fun onReceiveMessage(message: String) {
2326
try {
@@ -27,15 +30,19 @@ interface IAdapter {
2730

2831
if (json.has(API_RESULT_KEY)) { // 接口回调
2932
actionHandler.onReceiveActionResp(json)
30-
} else scope.launch { // 处理事件
31-
mutex.withLock {
32-
withTimeoutOrNull(processTimeout) {
33-
runCatching {
34-
EventBus.onReceive(message)
35-
}.onFailure {
36-
logger.error("处理 Onebot 事件时出现异常: ", it)
33+
} else {
34+
val holder = EventBus.matchHandlers(message)
35+
val botId = holder.event.selfId
36+
if (Bot.findInstance(botId) == null) {
37+
val list = eventsHolder[botId] ?: run {
38+
mutableListOf<EventHolder>().also {
39+
eventsHolder[botId] = it
3740
}
38-
} ?: throw IllegalStateException("事件处理超时: $message")
41+
}
42+
list.add(holder)
43+
return
44+
} else scope.launch { // 处理事件
45+
handleEvent(holder)
3946
}
4047
}
4148
}
@@ -46,6 +53,26 @@ interface IAdapter {
4653
}
4754
}
4855

56+
fun afterLoginInfoFetch(bot: cn.evolvefield.onebot.client.core.Bot) {
57+
val events = eventsHolder.remove(bot.id) ?: return
58+
if (bot.config.dropEventsBeforeConnected) return
59+
for (holder in events) scope.launch {
60+
handleEvent(holder)
61+
}
62+
}
63+
64+
private suspend fun handleEvent(holder: EventHolder) { // 处理事件
65+
mutex.withLock {
66+
withTimeoutOrNull(processTimeout) {
67+
runCatching {
68+
holder.onReceive()
69+
}.onFailure {
70+
logger.error("处理 Onebot 事件时出现异常: ", it)
71+
}
72+
} ?: throw IllegalStateException("事件处理超时: ${holder.event.json}")
73+
}
74+
}
75+
4976
fun unlockMutex() {
5077
runCatching {
5178
if (mutex.isLocked) mutex.unlock()

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/connection/WSClient.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cn.evolvefield.onebot.client.connection
33
import cn.evolvefield.onebot.client.config.BotConfig
44
import cn.evolvefield.onebot.client.core.Bot
55
import cn.evolvefield.onebot.client.handler.ActionHandler
6+
import cn.evolvefield.onebot.client.handler.EventHolder
67
import kotlinx.coroutines.*
78
import org.java_websocket.client.WebSocketClient
89
import org.java_websocket.handshake.ServerHandshake
@@ -15,7 +16,7 @@ import java.net.URI
1516
* Date: 2023/4/4 2:20
1617
* Description:
1718
*/
18-
class WSClient(
19+
internal class WSClient(
1920
override val scope: CoroutineScope,
2021
private val config: BotConfig,
2122
uri: URI,
@@ -27,6 +28,7 @@ class WSClient(
2728
header: Map<String, String> = mapOf(),
2829
) : WebSocketClient(uri, header), IAdapter {
2930
internal var botConsumer: suspend (Bot) -> Unit = {}
31+
override val eventsHolder: MutableMap<Long, MutableList<EventHolder>> = mutableMapOf()
3032
private var retryCount = 0
3133
private var scheduleClose = false
3234

@@ -43,7 +45,7 @@ class WSClient(
4345
}
4446

4547
suspend fun createBot(): Bot {
46-
val bot = Bot(this, config, actionHandler)
48+
val bot = Bot(this, this, config, actionHandler)
4749
botConsumer.invoke(bot)
4850
return bot
4951
}

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/connection/WSServer.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cn.evolvefield.onebot.client.connection
33
import cn.evolvefield.onebot.client.config.BotConfig
44
import cn.evolvefield.onebot.client.core.Bot
55
import cn.evolvefield.onebot.client.handler.ActionHandler
6+
import cn.evolvefield.onebot.client.handler.EventHolder
67
import kotlinx.coroutines.CompletableDeferred
78
import kotlinx.coroutines.CoroutineScope
89
import kotlinx.coroutines.channels.Channel
@@ -28,7 +29,7 @@ import kotlin.time.Duration
2829
* Description:
2930
*/
3031
val random = Random(System.currentTimeMillis())
31-
class WSServer(
32+
internal class WSServer(
3233
override val scope: CoroutineScope,
3334
private val config: BotConfig,
3435
address: InetSocketAddress,
@@ -52,6 +53,7 @@ class WSServer(
5253
}
5354

5455
internal var botConsumer: suspend (Bot) -> Unit = {}
56+
override val eventsHolder: MutableMap<Long, MutableList<EventHolder>> = mutableMapOf()
5557
private val bots: MutableList<Bot> = mutableListOf()
5658
// 通过使 ConnectionBox 互不相等,使得当 bot 重新上线时,botChannel 推送成功。
5759
private val botChannel = Channel<ConnectionBox>()
@@ -117,7 +119,7 @@ class WSServer(
117119
logger.info("▌ 反向 WebSocket 客户端 ${conn.remoteSocketAddress} 已连接 ┈━═☆")
118120
scope.launch {
119121
val bot = muteX.withLock {
120-
Bot(conn, config, actionHandler).also { it.conn = conn }.apply {
122+
Bot(conn, this@WSServer, config, actionHandler).also { it.conn = conn }.apply {
121123
connectDef.complete(this)
122124
}
123125
}

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/connection/platform-connection.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import cn.evolvefield.onebot.client.core.Bot
44
import kotlinx.coroutines.withTimeout
55
import kotlin.time.Duration
66

7-
interface OneBotProducer {
7+
internal interface OneBotProducer {
88
fun invokeOnClose(block: () -> Unit)
99
fun close()
1010
fun setBotConsumer(consumer: suspend (Bot) -> Unit)
1111
suspend fun awaitNewBotConnection(duration: Duration = Duration.INFINITE): Bot?
1212
}
1313

14-
class PositiveOneBotProducer(
14+
internal class PositiveOneBotProducer(
1515
private val client: WSClient
1616
): OneBotProducer {
1717
override fun invokeOnClose(block: () -> Unit) = TODO("客户端暂不支持断线重连")
@@ -31,7 +31,7 @@ class PositiveOneBotProducer(
3131
}
3232
}
3333

34-
class ReversedOneBotProducer(
34+
internal class ReversedOneBotProducer(
3535
private val server: WSServer
3636
): OneBotProducer {
3737
override fun invokeOnClose(block: () -> Unit) {

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/core/Bot.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cn.evolvefield.onebot.client.core
22

33
import cn.evolvefield.onebot.client.config.BotConfig
4+
import cn.evolvefield.onebot.client.connection.IAdapter
45
import cn.evolvefield.onebot.client.handler.ActionHandler
56
import cn.evolvefield.onebot.sdk.action.ActionData
67
import cn.evolvefield.onebot.sdk.action.ActionList
@@ -20,6 +21,7 @@ import cn.evolvefield.onebot.sdk.response.group.*
2021
import cn.evolvefield.onebot.sdk.response.misc.*
2122
import cn.evolvefield.onebot.sdk.util.*
2223
import com.google.gson.*
24+
import kotlinx.coroutines.launch
2325
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
2426
import org.java_websocket.WebSocket
2527
import top.mrxiaom.overflow.action.ActionContext
@@ -45,8 +47,9 @@ typealias Context = ActionContext.Builder.() -> Unit
4547
* @param actionHandler [ActionHandler]
4648
*/
4749
@Suppress("unused")
48-
class Bot(
50+
internal class Bot(
4951
internal var conn: WebSocket,
52+
internal val adapter: IAdapter,
5053
val config: BotConfig,
5154
val actionHandler: ActionHandler
5255
) {
@@ -537,7 +540,10 @@ class Bot(
537540
val action = context.build(ActionPathEnum.GET_LOGIN_INFO)
538541
val result = actionHandler.action(this, action)
539542
return result.withToken<ActionData<LoginInfoResp>>().also {
540-
it.data?.userId?.also { id -> idInternal = id }
543+
it.data?.userId?.also { id ->
544+
idInternal = id
545+
adapter.afterLoginInfoFetch(this@Bot)
546+
}
541547
}
542548
}
543549

overflow-core/src/main/kotlin/cn/evolvefield/onebot/client/handler/ActionHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import java.util.concurrent.ConcurrentHashMap
1616
* Date: 2022/9/14 15:05
1717
* Version: 1.0
1818
*/
19-
class ActionHandler(
19+
internal class ActionHandler(
2020
private val parent: Job?,
2121
private val logger: Logger
2222
) {

0 commit comments

Comments
 (0)