Jelajahi Sumber

Fix MessageSource.id from offline quotations

Him188 6 tahun lalu
induk
melakukan
3a8b2dd6d2

+ 5 - 1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt

@@ -255,6 +255,10 @@ internal class OfflineMessageSourceImplBySourceMsg( // from others' quotation
     override val bot: Bot,
     groupIdOrZero: Long
 ) : OfflineMessageSource(), MessageSourceImpl {
+    init {
+        println(delegate._miraiContentToString())
+    }
+
     override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND
 
     private val isRecalled: AtomicBoolean = atomic(false)
@@ -276,7 +280,7 @@ internal class OfflineMessageSourceImplBySourceMsg( // from others' quotation
 
     override val id: Int
         get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt()
-            ?: error("在读取 OfflineMessageSourceImplBySourceMsg.id 时找不到 origUids, delegate=${delegate._miraiContentToString()}")
+            ?: 0
 
     // override val sourceMessage: MessageChain get() = delegate.toMessageChain()
     override val fromId: Long get() = delegate.senderUin

+ 68 - 102
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt

@@ -30,6 +30,7 @@ import net.mamoe.mirai.qqandroid.contact.GroupImpl
 import net.mamoe.mirai.qqandroid.contact.QQImpl
 import net.mamoe.mirai.qqandroid.contact.singleLine
 import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopNum
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
 import net.mamoe.mirai.qqandroid.network.protocol.packet.*
 import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl
@@ -189,8 +190,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
      * Don't use concurrently
      */
     suspend fun reloadFriendList() {
-        // 不要用 fun, 不要 join declaration, 不要用 val, 编译失败警告
-        logger.info("开始加载好友信息")
+        logger.info { "开始加载好友信息" }
         var currentFriendCount = 0
         var totalFriendCount: Short
         while (true) {
@@ -221,6 +221,58 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         logger.info { "好友列表加载完成, 共 ${currentFriendCount}个" }
     }
 
+    suspend fun StTroopNum.reloadGroup() {
+        retryCatching(3) {
+            bot.groups.delegate.addLast(
+                @Suppress("DuplicatedCode")
+                GroupImpl(
+                    bot = bot,
+                    coroutineContext = bot.coroutineContext,
+                    id = groupCode,
+                    groupInfo = bot._lowLevelQueryGroupInfo(groupCode).apply {
+                        this as GroupInfoImpl
+
+                        if (this.delegate.groupName == null) {
+                            this.delegate.groupName = groupName
+                        }
+
+                        if (this.delegate.groupMemo == null) {
+                            this.delegate.groupMemo = groupMemo
+                        }
+
+                        if (this.delegate.groupUin == null) {
+                            this.delegate.groupUin = groupUin
+                        }
+
+                        this.delegate.groupCode = [email protected]
+                    },
+                    members = bot._lowLevelQueryGroupMemberList(
+                        groupUin,
+                        groupCode,
+                        dwGroupOwnerUin
+                    )
+                )
+            )
+        }.getOrThrow()
+    }
+
+    suspend fun reloadGroupList() {
+        logger.info { "开始加载群组列表与群成员列表" }
+        val troopListData = FriendList.GetTroopListSimplify(bot.client)
+            .sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 3)
+
+        troopListData.groups.chunked(50).forEach { chunk ->
+            coroutineScope {
+                chunk.forEach {
+                    launch {
+                        retryCatching(3) { it.reloadGroup() }.getOrThrow()
+                    }
+                }
+            }
+        }
+        logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}个" }
+    }
+
     @OptIn(MiraiExperimentalAPI::class, ExperimentalTime::class)
     override suspend fun init(): Unit = coroutineScope {
         check(bot.isActive) { "bot is dead therefore network can't init" }
@@ -236,92 +288,16 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
             _pendingEnabled.value = true
         }
 
-        supervisorScope {
-            this.launch { reloadFriendList() }
-
-            launch {
-                try {
-                    logger.info("开始加载群组列表与群成员列表")
-                    val troopListData = FriendList.GetTroopListSimplify(bot.client)
-                        .sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 3)
-
-                    troopListData.groups.chunked(50).forEach { chunk ->
-                        supervisorScope {
-                            chunk.forEach { troopNum ->
-                                // 别用 fun, 别 val, 编译失败警告
-                                lateinit var loadGroup: suspend () -> Unit
-
-                                loadGroup = suspend {
-                                    retryCatching(3) {
-                                        bot.groups.delegate.addLast(
-                                            @Suppress("DuplicatedCode")
-                                            (GroupImpl(
-                                                bot = bot,
-                                                coroutineContext = bot.coroutineContext,
-                                                id = troopNum.groupCode,
-                                                groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply {
-                                                    this as GroupInfoImpl
-
-                                                    if (this.delegate.groupName == null) {
-                                                        this.delegate.groupName = troopNum.groupName
-                                                    }
-
-                                                    if (this.delegate.groupMemo == null) {
-                                                        this.delegate.groupMemo = troopNum.groupMemo
-                                                    }
-
-                                                    if (this.delegate.groupUin == null) {
-                                                        this.delegate.groupUin = troopNum.groupUin
-                                                    }
-
-                                                    this.delegate.groupCode = troopNum.groupCode
-                                                },
-                                                members = bot._lowLevelQueryGroupMemberList(
-                                                    troopNum.groupUin,
-                                                    troopNum.groupCode,
-                                                    troopNum.dwGroupOwnerUin
-                                                )
-                                            ))
-                                        )
-                                    }.exceptionOrNull()?.let {
-                                        logger.error { "群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" }
-                                        logger.error(it)
-                                        [email protected] {
-                                            delay(10_000)
-                                            loadGroup()
-                                        }
-                                    }
-                                    Unit // 别删, 编译失败警告
-                                }
-                                launch {
-                                    loadGroup()
-                                }
-                            }
-                        }
-                    }
-                    logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}个" }
-                } catch (e: Exception) {
-                    logger.error { "加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表" }
-                    logger.error(e)
-                }
-            }
+        coroutineScope {
+            launch { reloadFriendList() }
+            launch { reloadGroupList() }
         }
 
-        runCatching {
-            withTimeoutOrNull(30000) {
-                lateinit var listener: Listener<PacketReceivedEvent>
-                listener = this.subscribeAlways {
-                    if (it.packet is MessageSvc.PbGetMsg.GetMsgSuccess) {
-                        listener.complete()
-                    }
-                }
+        withTimeoutOrNull(30000) {
+            launch { subscribingGet<MessageSvc.PbGetMsg.GetMsgSuccess, Unit> { Unit } }
+            MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>()
+        } ?: error("timeout syncing friend message history")
 
-                MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>()
-            } ?: error("timeout syncing friend message history")
-        }.exceptionOrNull()?.let {
-            logger.error("exception while loading syncing friend message history: ${it.message}")
-            logger.error(it)
-        }
         bot.firstLoginSucceed = true
 
         _pendingEnabled.value = false
@@ -568,11 +544,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         check(bot.isActive) { "bot is dead therefore can't send any packet" }
         check([email protected]) { "network is dead therefore can't send any packet" }
         logger.verbose("Send: ${this.commandName}")
-        withContext([email protected] + CoroutineName("Packet sender")) {
-            PacketLogger.debug { "Channel sending: $commandName" }
-            channel.send(delegate)
-            PacketLogger.debug { "Channel send done: $commandName" }
-        }
+        channel.send(delegate)
     }
 
     class TimeoutException(override val message: String?) : Exception()
@@ -588,19 +560,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         check([email protected]) { "network is dead therefore can't send any packet" }
 
         suspend fun doSendAndReceive(handler: PacketListener, data: Any, length: Int): E {
-            withTimeoutOrNull(3000) {
-                withContext([email protected] + CoroutineName("Packet sender")) {
-                    PacketLogger.debug { "Channel sending: $commandName" }
-                    when (data) {
-                        is ByteArray -> channel.send(data, 0, length)
-                        is ByteReadPacket -> channel.send(data)
-                        else -> error("Internal error: unexpected data type: ${data::class.simpleName}")
-                    }
-                    PacketLogger.debug { "Channel send done: $commandName" }
-                }
-            } ?: throw TimeoutException("timeout sending packet $commandName")
+            when (data) {
+                is ByteArray -> channel.send(data, 0, length)
+                is ByteReadPacket -> channel.send(data)
+                else -> error("Internal error: unexpected data type: ${data::class.simpleName}")
+            }
 
-            logger.verbose("Send done: $commandName")
+            logger.verbose { "Send done: $commandName" }
 
             @Suppress("UNCHECKED_CAST")
             return withTimeoutOrNull(timeoutMillis) {

+ 3 - 1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt

@@ -23,6 +23,7 @@ import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.contact.MemberPermission
 import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.data.MemberInfo
+import net.mamoe.mirai.event.Event
 import net.mamoe.mirai.event.events.BotJoinGroupEvent
 import net.mamoe.mirai.event.events.BotOfflineEvent
 import net.mamoe.mirai.event.events.MemberJoinEvent
@@ -116,7 +117,8 @@ internal class MessageSvc {
         }
 
         @OptIn(MiraiInternalAPI::class)
-        open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate) {
+        open class GetMsgSuccess(delegate: List<Packet>) : Response(MsgSvc.SyncFlag.STOP, delegate), Event,
+            Packet.NoLog {
             override fun toString(): String = "MessageSvc.PbGetMsg.GetMsgSuccess(messages=<Iterable>))"
         }
 

+ 9 - 1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt

@@ -56,6 +56,8 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<OnlineMes
 
     /**
      * 消息 id.
+     * 当 [OnlineMessageSource] 时为随机数.
+     * 当 [OfflineMessageSource] 时可能为 0, 取决于服务器是否提供这个值.
      */
     abstract val id: Int // random
 
@@ -235,7 +237,7 @@ inline fun MessageSource.isAboutGroup(): Boolean {
 }
 
 inline fun MessageSource.isAboutTemp(): Boolean {
-    return when(this) {
+    return when (this) {
         is OnlineMessageSource -> subject is Member
         is OfflineMessageSource -> kind == OfflineMessageSource.Kind.TEMP
     }
@@ -302,6 +304,12 @@ abstract class OfflineMessageSource : MessageSource() {
      */
     abstract val kind: Kind
 
+    /**
+     * 消息 id.
+     * 服务器不一定提供 id. 因此此值可能为 0
+     */
+    abstract override val id: Int
+
     // final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)"
 }