Skip to content

Commit 681cf45

Browse files
committed
support to connect multi onebot on startup
#184
1 parent 030c768 commit 681cf45

2 files changed

Lines changed: 220 additions & 29 deletions

File tree

Lines changed: 213 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
package top.mrxiaom.overflow.internal
22

3+
import kotlinx.coroutines.Job
34
import kotlinx.serialization.SerialName
45
import kotlinx.serialization.Serializable
6+
import kotlinx.serialization.json.Json
7+
import kotlinx.serialization.json.JsonElement
8+
import kotlinx.serialization.json.buildJsonObject
9+
import kotlinx.serialization.json.jsonObject
10+
import kotlinx.serialization.json.jsonPrimitive
11+
import kotlinx.serialization.json.put
12+
import net.mamoe.mirai.Bot
13+
import net.mamoe.mirai.utils.MiraiLogger
14+
import org.slf4j.Logger
15+
import top.mrxiaom.overflow.BotBuilder
16+
import top.mrxiaom.overflow.internal.utils.SLF4JAdapterLogger
17+
18+
private val JSON = Json {
19+
ignoreUnknownKeys = true
20+
isLenient = true
21+
}
522

623
@Serializable
724
data class Config(
8-
@SerialName("no_log___DO_NOT_REPORT_IF_YOU_SWITCH_THIS_ON___开启此选项时不接受漏洞反馈")
25+
@SerialName("no_log___DO_NOT_REPORT_IF_YOU_SWITCH_THIS_ON")
926
var noLogDoNotReportIfYouSwitchThisOn: Boolean = false,
10-
@SerialName("ws_host")
11-
var wsHost: String = "ws://127.0.0.1:3001",
12-
@SerialName("reversed_ws_port")
13-
var reversedWSPort: Int = -1,
14-
@SerialName("token")
15-
var token: String = "",
27+
@SerialName("connections")
28+
var connectionsRaw: List<JsonElement> = listOf(
29+
buildJsonObject {
30+
put("enable", false)
31+
put("type", "websocket")
32+
put("host", "ws://127.0.0.1:3001")
33+
put("token", "")
34+
},
35+
buildJsonObject {
36+
put("enable", false)
37+
put("type", "websocket-reverse")
38+
put("port", 3002)
39+
put("token", "")
40+
},
41+
),
1642
@SerialName("no_platform")
17-
val noPlatform: Boolean = false,
43+
var noPlatform: Boolean = false,
1844
@SerialName("use_cq_code")
19-
val useCQCode: Boolean = false,
45+
var useCQCode: Boolean = false,
2046
@SerialName("retry_times")
2147
var retryTimes: Int = 5,
2248
@SerialName("retry_wait_mills")
@@ -31,11 +57,188 @@ data class Config(
3157
var resourceCache: CacheConfig = CacheConfig(),
3258
@SerialName("drop_events_before_connected")
3359
var dropEventsBeforeConnected: Boolean = true,
34-
)
60+
) {
61+
internal val connections: List<IConnection> by lazy {
62+
connectionsRaw.map { element ->
63+
val type = element.jsonObject["type"]?.jsonPrimitive?.content
64+
?: throw IllegalArgumentException("配置项缺少 type 字段")
65+
66+
return@map when (type) {
67+
"websocket" -> JSON.decodeFromJsonElement(ConnWebSocket.serializer(), element).invoke(this)
68+
"websocket-reverse" -> JSON.decodeFromJsonElement(ConnWebSocketReverse.serializer(), element).invoke(this)
69+
else -> throw IllegalArgumentException("未知的连接类型 $type")
70+
}
71+
}
72+
}
73+
}
3574
@Serializable
3675
data class CacheConfig (
3776
@SerialName("enabled")
3877
var enabled: Boolean = false,
3978
@SerialName("keep_duration_hours")
4079
var keepDurationHours: Long = 168L,
4180
)
81+
82+
internal interface IConnection {
83+
val enabled: Boolean
84+
suspend fun connect(
85+
printInfo: Boolean = false,
86+
overrideLogger: Logger? = null,
87+
job: Job? = null,
88+
): Bot?
89+
}
90+
91+
internal abstract class AbstractConnection(
92+
config: Config,
93+
enable: Boolean,
94+
noPlatform: Boolean?,
95+
useCQCode: Boolean?,
96+
retryTimes: Int?,
97+
retryWaitMills: Long?,
98+
retryRestMills: Long?,
99+
heartbeatCheckSeconds: Int?,
100+
useGroupUploadEventForFileMessage: Boolean?,
101+
dropEventsBeforeConnected: Boolean?,
102+
) : IConnection {
103+
override val enabled: Boolean = enable
104+
private val noLog = config.noLogDoNotReportIfYouSwitchThisOn
105+
private val noPlatform = noPlatform ?: config.noPlatform
106+
private val useCQCode = useCQCode ?: config.useCQCode
107+
private val retryTimes = retryTimes ?: config.retryTimes
108+
private val retryWaitMills = retryWaitMills ?: config.retryWaitMills
109+
private val retryRestMills = retryRestMills ?: config.retryRestMills
110+
private val heartbeatCheckSeconds = heartbeatCheckSeconds ?: config.heartbeatCheckSeconds
111+
private val useGroupUploadEventForFileMessage = useGroupUploadEventForFileMessage ?: config.useGroupUploadEventForFileMessage
112+
private val dropEventsBeforeConnected = dropEventsBeforeConnected ?: config.dropEventsBeforeConnected
113+
114+
override suspend fun connect(
115+
printInfo: Boolean,
116+
overrideLogger: Logger?,
117+
job: Job?
118+
): Bot? {
119+
val builder = botBuilder()
120+
121+
if (noPlatform) builder.noPlatform()
122+
if (useCQCode) builder.useCQCode()
123+
builder.retryTimes(retryTimes)
124+
builder.retryWaitMills(retryWaitMills)
125+
builder.retryRestMills(retryRestMills)
126+
builder.heartbeatCheckSeconds(heartbeatCheckSeconds)
127+
if (useGroupUploadEventForFileMessage) builder.useGroupUploadEventForFileMessage()
128+
if (!dropEventsBeforeConnected) builder.keepEventsBeforeConnected()
129+
130+
if (!printInfo) builder.noPrintInfo()
131+
if (noLog) {
132+
val miraiLogger = MiraiLogger.Factory.create(Overflow::class, "Onebot")
133+
builder.overrideLogger(SLF4JAdapterLogger(miraiLogger))
134+
} else if (overrideLogger != null) {
135+
builder.overrideLogger(overrideLogger)
136+
}
137+
138+
builder.parentJob(job)
139+
140+
return builder.connect()
141+
}
142+
143+
abstract fun botBuilder(): BotBuilder
144+
}
145+
146+
@Serializable
147+
internal data class ConnWebSocket(
148+
@SerialName("enable")
149+
var enable: Boolean,
150+
@SerialName("host")
151+
var host: String,
152+
@SerialName("token")
153+
var token: String = "",
154+
// 以下为通用参数
155+
@SerialName("no_platform")
156+
var noPlatform: Boolean? = null,
157+
@SerialName("use_cq_code")
158+
var useCQCode: Boolean? = null,
159+
@SerialName("retry_times")
160+
var retryTimes: Int? = null,
161+
@SerialName("retry_wait_mills")
162+
var retryWaitMills: Long? = null,
163+
@SerialName("retry_rest_mills")
164+
var retryRestMills: Long? = null,
165+
@SerialName("heartbeat_check_seconds")
166+
var heartbeatCheckSeconds: Int? = null,
167+
@SerialName("use_group_upload_event_for_file_message")
168+
var useGroupUploadEventForFileMessage: Boolean? = null,
169+
@SerialName("drop_events_before_connected")
170+
var dropEventsBeforeConnected: Boolean? = null,
171+
): (Config) -> IConnection {
172+
override fun invoke(config: Config) = Impl(config, this)
173+
174+
class Impl(
175+
config: Config,
176+
private val conn: ConnWebSocket,
177+
) : AbstractConnection(
178+
config, conn.enable,
179+
conn.noPlatform,
180+
conn.useCQCode,
181+
conn.retryTimes,
182+
conn.retryWaitMills,
183+
conn.retryRestMills,
184+
conn.heartbeatCheckSeconds,
185+
conn.useGroupUploadEventForFileMessage,
186+
conn.dropEventsBeforeConnected,
187+
) {
188+
override fun botBuilder(): BotBuilder {
189+
val builder = BotBuilder.positive(conn.host)
190+
if (conn.token.isNotBlank()) builder.token(conn.token)
191+
return builder
192+
}
193+
}
194+
}
195+
196+
@Serializable
197+
internal data class ConnWebSocketReverse(
198+
@SerialName("enable")
199+
var enable: Boolean,
200+
@SerialName("port")
201+
var port: Int,
202+
@SerialName("token")
203+
var token: String = "",
204+
// 以下为通用参数
205+
@SerialName("no_platform")
206+
var noPlatform: Boolean? = null,
207+
@SerialName("use_cq_code")
208+
var useCQCode: Boolean? = null,
209+
@SerialName("retry_times")
210+
var retryTimes: Int? = null,
211+
@SerialName("retry_wait_mills")
212+
var retryWaitMills: Long? = null,
213+
@SerialName("retry_rest_mills")
214+
var retryRestMills: Long? = null,
215+
@SerialName("heartbeat_check_seconds")
216+
var heartbeatCheckSeconds: Int? = null,
217+
@SerialName("use_group_upload_event_for_file_message")
218+
var useGroupUploadEventForFileMessage: Boolean? = null,
219+
@SerialName("drop_events_before_connected")
220+
var dropEventsBeforeConnected: Boolean? = null,
221+
): (Config) -> IConnection {
222+
override fun invoke(config: Config) = Impl(config, this)
223+
224+
class Impl(
225+
config: Config,
226+
private val conn: ConnWebSocketReverse,
227+
) : AbstractConnection(
228+
config, conn.enable,
229+
conn.noPlatform,
230+
conn.useCQCode,
231+
conn.retryTimes,
232+
conn.retryWaitMills,
233+
conn.retryRestMills,
234+
conn.heartbeatCheckSeconds,
235+
conn.useGroupUploadEventForFileMessage,
236+
conn.dropEventsBeforeConnected,
237+
) {
238+
override fun botBuilder(): BotBuilder {
239+
val builder = BotBuilder.reversed(conn.port)
240+
if (conn.token.isNotBlank()) builder.token(conn.token)
241+
return builder
242+
}
243+
}
244+
}

overflow-core/src/main/kotlin/top/mrxiaom/overflow/internal/Overflow.kt

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import net.mamoe.mirai.data.MemberInfo
2222
import net.mamoe.mirai.data.StrangerInfo
2323
import net.mamoe.mirai.data.UserProfile
2424
import net.mamoe.mirai.event.Event
25-
import net.mamoe.mirai.event.broadcast
2625
import net.mamoe.mirai.event.events.*
2726
import net.mamoe.mirai.internal.event.EventChannelToEventDispatcherAdapter
2827
import net.mamoe.mirai.internal.event.InternalEventMechanism
@@ -111,6 +110,7 @@ class Overflow : IMirai, CoroutineScope, LowLevelApiAccessor, OverflowAPI {
111110
var config: Config? = null
112111
if (configFile.exists()) try {
113112
config = json.decodeFromString(Config.serializer(), configFile.readText().replace("\r", ""))
113+
config.connections
114114
} catch (t: Throwable) {
115115
val bak = File(configFile.parentFile, "${configFile.name}.old_${System.currentTimeMillis()}.bak")
116116
configFile.copyTo(bak, true)
@@ -209,24 +209,12 @@ class Overflow : IMirai, CoroutineScope, LowLevelApiAccessor, OverflowAPI {
209209
logger: Logger = LoggerFactory.getLogger("Onebot"),
210210
job: Job? = null
211211
): Boolean {
212-
return start0(
213-
BotConfig(
214-
url = config.wsHost,
215-
reversedPort = config.reversedWSPort,
216-
token = config.token,
217-
isAccessToken = config.token.isNotBlank(),
218-
noPlatform = config.noPlatform,
219-
useCQCode = config.useCQCode,
220-
retryTimes = config.retryTimes,
221-
retryWaitMills = config.retryWaitMills,
222-
retryRestMills = config.retryRestMills,
223-
heartbeatCheckSeconds = config.heartbeatCheckSeconds,
224-
useGroupUploadEventForFileMessage = config.useGroupUploadEventForFileMessage,
225-
parentJob = job ?: defaultJob,
226-
),
227-
printInfo = printInfo,
228-
logger = logger
229-
) != null
212+
for (botConfig in config.connections) {
213+
if (botConfig.enabled) {
214+
botConfig.connect(printInfo, logger, job ?: defaultJob)
215+
}
216+
}
217+
return true
230218
}
231219

232220
// 反向 WebSocket 已存在的服务器列表

0 commit comments

Comments
 (0)