소스 검색

Improve `syncMessageSvc`:
- do not suspend logon and postpone suspension until sending message
- add MessageSvcSyncer

Fix #1253

Him188 4 년 전
부모
커밋
9f466c882e

+ 4 - 0
mirai-core/src/commonMain/kotlin/QQAndroidBot.kt

@@ -138,6 +138,10 @@ internal open class QQAndroidBot constructor(
                 BdhSessionSyncer,
                 BdhSessionSyncer,
                 BdhSessionSyncerImpl(configuration, components, networkLogger.subLogger("BotSessionSyncer"))
                 BdhSessionSyncerImpl(configuration, components, networkLogger.subLogger("BotSessionSyncer"))
             )
             )
+            set(
+                MessageSvcSyncer,
+                MessageSvcSyncerImpl(bot, bot.coroutineContext, networkLogger.subLogger("MessageSvcSyncer"))
+            )
             set(ServerList, ServerListImpl(networkLogger.subLogger("ServerList")))
             set(ServerList, ServerListImpl(networkLogger.subLogger("ServerList")))
             set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
             set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
             set(
             set(

+ 2 - 0
mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt

@@ -19,6 +19,7 @@ import net.mamoe.mirai.internal.asQQAndroidBot
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.QQAndroidClient
 import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.components.MessageSvcSyncer
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
@@ -119,6 +120,7 @@ internal abstract class SendMessageHandler<C : Contact> {
         finalMessage: MessageChain,
         finalMessage: MessageChain,
         step: SendMessageStep,
         step: SendMessageStep,
     ): MessageReceipt<C> {
     ): MessageReceipt<C> {
+        bot.components[MessageSvcSyncer].joinSync()
 
 
         val group = contact
         val group = contact
 
 

+ 5 - 19
mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt

@@ -10,8 +10,10 @@
 package net.mamoe.mirai.internal.network.components
 package net.mamoe.mirai.internal.network.components
 
 
 import kotlinx.atomicfu.atomic
 import kotlinx.atomicfu.atomic
-import kotlinx.coroutines.*
-import net.mamoe.mirai.event.nextEvent
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.supervisorScope
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.component.ComponentKey
 import net.mamoe.mirai.internal.network.component.ComponentKey
 import net.mamoe.mirai.internal.network.component.ComponentStorage
 import net.mamoe.mirai.internal.network.component.ComponentStorage
@@ -19,11 +21,7 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler
 import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
 import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
 import net.mamoe.mirai.internal.network.handler.state.JobAttachStateObserver
 import net.mamoe.mirai.internal.network.handler.state.JobAttachStateObserver
 import net.mamoe.mirai.internal.network.handler.state.StateObserver
 import net.mamoe.mirai.internal.network.handler.state.StateObserver
-import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
-import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetMsg
-import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.mirai.utils.MiraiLogger
-import net.mamoe.mirai.utils.info
 
 
 
 
 /**
 /**
@@ -62,8 +60,8 @@ internal class BotInitProcessorImpl(
             context[SsoProcessor].registerResp ?: error("Internal error: registerResp is not yet available.")
             context[SsoProcessor].registerResp ?: error("Internal error: registerResp is not yet available.")
 
 
         // do them parallel.
         // do them parallel.
+        context[MessageSvcSyncer].startSync()
         supervisorScope {
         supervisorScope {
-            launch { syncMessageSvc() }
             launch { context[BdhSessionSyncer].loadFromCache() }
             launch { context[BdhSessionSyncer].loadFromCache() }
             launch { context[OtherClientUpdater].update() }
             launch { context[OtherClientUpdater].update() }
             launch { context[ContactUpdater].loadAll(registerResp.origin) }
             launch { context[ContactUpdater].loadAll(registerResp.origin) }
@@ -72,17 +70,5 @@ internal class BotInitProcessorImpl(
         bot.components[SsoProcessor].firstLoginSucceed = true
         bot.components[SsoProcessor].firstLoginSucceed = true
     }
     }
 
 
-    private suspend fun syncMessageSvc() {
-        logger.info { "Syncing friend message history..." }
-        withTimeoutOrNull(30000) {
-            launch(CoroutineName("Syncing friend message history")) {
-                nextEvent<MessageSvcPbGetMsg.GetMsgSuccess> {
-                    it.bot == this@BotInitProcessorImpl.bot
-                }
-            }
-            MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, null).sendAndExpect(bot)
-        } ?: error("timeout syncing friend message history.")
-        logger.info { "Syncing friend message history: Success." }
-    }
 }
 }
 
 

+ 72 - 0
mirai-core/src/commonMain/kotlin/network/components/MessageSvcSyncer.kt

@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
+ *
+ *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.internal.network.components
+
+import kotlinx.coroutines.*
+import net.mamoe.mirai.event.nextEvent
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.component.ComponentKey
+import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
+import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetMsg
+import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
+import net.mamoe.mirai.utils.MiraiLogger
+import net.mamoe.mirai.utils.addNameHierarchically
+import net.mamoe.mirai.utils.childScope
+import net.mamoe.mirai.utils.info
+import kotlin.coroutines.CoroutineContext
+
+internal interface MessageSvcSyncer {
+    fun startSync()
+    suspend fun joinSync()
+
+    companion object : ComponentKey<MessageSvcSyncer>
+}
+
+internal class MessageSvcSyncerImpl(
+    private val bot: QQAndroidBot,
+    private val parentContext: CoroutineContext,
+    private val logger: MiraiLogger,
+) : MessageSvcSyncer {
+
+    @Volatile
+    private var scope: CoroutineScope? = null
+
+    @Volatile
+    private var job: Job? = null
+
+    private fun initScope() {
+        scope = parentContext.addNameHierarchically("MessageSvcSyncerImpl").childScope()
+    }
+
+    @Synchronized
+    override fun startSync() {
+        scope?.cancel()
+        initScope()
+        job = scope!!.launch { syncMessageSvc() }
+    }
+
+    private suspend fun syncMessageSvc() {
+        logger.info { "Syncing friend message history..." }
+        withTimeoutOrNull(30000) {
+            launch(CoroutineName("Syncing friend message history")) {
+                nextEvent<MessageSvcPbGetMsg.GetMsgSuccess> {
+                    it.bot == this@MessageSvcSyncerImpl.bot
+                }
+            }
+            MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, null).sendAndExpect(bot)
+        } ?: error("timeout syncing friend message history.")
+        logger.info { "Syncing friend message history: Success." }
+    }
+
+    @Synchronized
+    override suspend fun joinSync() {
+        job?.join()
+    }
+}