Bladeren bron

Migrate more transformers to `NoticeProcessorPipeline`

Him188 4 jaren geleden
bovenliggende
commit
9c272ebf1e

+ 74 - 10
mirai-core-utils/src/commonMain/kotlin/TypeSafeMap.kt

@@ -22,22 +22,86 @@ public value class TypeKey<out T>(public val name: String) {
     public inline infix fun <T> to(value: T): TypeSafeMap = buildTypeSafeMap { set(this@TypeKey, value) }
 }
 
-@JvmInline
-public value class TypeSafeMap(
-    private val map: MutableMap<TypeKey<*>, Any?> = ConcurrentHashMap()
-) {
-    public operator fun <T> get(key: TypeKey<T>): T =
-        map[key]?.uncheckedCast() ?: throw NoSuchElementException(key.toString())
+public interface TypeSafeMap {
+    public val size: Int
 
+    public operator fun <T> get(key: TypeKey<T>): T
     public operator fun <T> contains(key: TypeKey<T>): Boolean = get(key) != null
-    public operator fun <T> set(key: TypeKey<T>, value: T) {
+
+    public fun toMap(): Map<TypeKey<*>, Any?>
+
+    public companion object {
+        public val EMPTY: TypeSafeMap = TypeSafeMapImpl(emptyMap())
+    }
+}
+
+public operator fun TypeSafeMap.plus(other: TypeSafeMap): TypeSafeMap {
+    return when {
+        other.size == 0 -> this
+        this.size == 0 -> other
+        else -> buildTypeSafeMap {
+            setAll(this@plus)
+            setAll(other)
+        }
+    }
+}
+
+public interface MutableTypeSafeMap : TypeSafeMap {
+    public operator fun <T> set(key: TypeKey<T>, value: T)
+    public fun <T> remove(key: TypeKey<T>): T?
+    public fun setAll(other: TypeSafeMap)
+}
+
+
+internal open class TypeSafeMapImpl(
+    internal open val map: Map<TypeKey<*>, Any?> = ConcurrentHashMap()
+) : TypeSafeMap {
+    override val size: Int get() = map.size
+
+    override fun equals(other: Any?): Boolean {
+        return other is TypeSafeMapImpl && other.map == this.map
+    }
+
+    override fun hashCode(): Int {
+        return map.hashCode()
+    }
+
+    override operator fun <T> get(key: TypeKey<T>): T =
+        map[key]?.uncheckedCast() ?: throw NoSuchElementException(key.toString())
+
+    override operator fun <T> contains(key: TypeKey<T>): Boolean = get(key) != null
+
+    override fun toMap(): Map<TypeKey<*>, Any?> = map
+}
+
+@PublishedApi
+internal class MutableTypeSafeMapImpl(
+    override val map: MutableMap<TypeKey<*>, Any?> = ConcurrentHashMap()
+) : TypeSafeMap, MutableTypeSafeMap, TypeSafeMapImpl(map) {
+    override fun equals(other: Any?): Boolean {
+        return other is MutableTypeSafeMapImpl && other.map == this.map
+    }
+
+    override fun hashCode(): Int {
+        return map.hashCode()
+    }
+
+    override operator fun <T> set(key: TypeKey<T>, value: T) {
         map[key] = value
     }
 
-    public fun <T> remove(key: TypeKey<T>): T? = map.remove(key)?.uncheckedCast()
+    override fun setAll(other: TypeSafeMap) {
+        if (other is TypeSafeMapImpl) {
+            map.putAll(other.map)
+        } else {
+            map.putAll(other.toMap())
+        }
+    }
+
+    override fun <T> remove(key: TypeKey<T>): T? = map.remove(key)?.uncheckedCast()
 }
 
-public inline fun buildTypeSafeMap(block: TypeSafeMap.() -> Unit): TypeSafeMap {
+public inline fun buildTypeSafeMap(block: MutableTypeSafeMap.() -> Unit): MutableTypeSafeMap {
     contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
-    return TypeSafeMap().apply(block)
+    return MutableTypeSafeMapImpl().apply(block)
 }

+ 2 - 2
mirai-core/src/commonMain/kotlin/QQAndroidBot.kt

@@ -45,7 +45,7 @@ import net.mamoe.mirai.internal.network.notice.group.GroupOrMemberListNoticeProc
 import net.mamoe.mirai.internal.network.notice.group.GroupRecallProcessor
 import net.mamoe.mirai.internal.network.notice.priv.FriendNoticeProcessor
 import net.mamoe.mirai.internal.network.notice.priv.OtherClientNoticeProcessor
-import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageNoticeProcessor
+import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
 import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
 import net.mamoe.mirai.internal.utils.subLogger
 import net.mamoe.mirai.utils.BotConfiguration
@@ -169,7 +169,7 @@ internal open class QQAndroidBot constructor(
                 FriendNoticeProcessor(pipelineLogger.subLogger("FriendNoticeProcessor")),
                 GroupOrMemberListNoticeProcessor(pipelineLogger.subLogger("GroupOrMemberListNoticeProcessor")),
                 GroupMessageProcessor(pipelineLogger.subLogger("GroupMessageProcessor")),
-                PrivateMessageNoticeProcessor(),
+                PrivateMessageProcessor(),
                 OtherClientNoticeProcessor(),
                 UnconsumedNoticesAlerter(pipelineLogger.subLogger("UnconsumedNoticesAlerter")),
                 GroupRecallProcessor()

+ 29 - 18
mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt

@@ -15,8 +15,10 @@ import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.ParseErrorPacket
 import net.mamoe.mirai.internal.network.component.ComponentKey
 import net.mamoe.mirai.internal.network.component.ComponentStorage
+import net.mamoe.mirai.internal.network.notice.BotAware
 import net.mamoe.mirai.internal.network.notice.decoders.DecodedNotifyMsgBody
 import net.mamoe.mirai.internal.network.notice.decoders.MsgType0x2DC
+import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
 import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
@@ -27,10 +29,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcP
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushTransMsg
 import net.mamoe.mirai.internal.network.toPacket
 import net.mamoe.mirai.internal.utils.io.ProtocolStruct
-import net.mamoe.mirai.utils.TypeKey
-import net.mamoe.mirai.utils.TypeSafeMap
-import net.mamoe.mirai.utils.toDebugString
-import net.mamoe.mirai.utils.uncheckedCast
+import net.mamoe.mirai.utils.*
 import java.util.*
 import java.util.concurrent.ConcurrentLinkedQueue
 import kotlin.reflect.KClass
@@ -46,7 +45,11 @@ internal interface NoticeProcessorPipeline {
     /**
      * Process [data] into [Packet]s. Exceptions are wrapped into [ParseErrorPacket]
      */
-    suspend fun process(bot: QQAndroidBot, data: ProtocolStruct, attributes: TypeSafeMap = TypeSafeMap()): ProcessResult
+    suspend fun process(
+        bot: QQAndroidBot,
+        data: ProtocolStruct,
+        attributes: TypeSafeMap = TypeSafeMap.EMPTY
+    ): ProcessResult
 
     companion object : ComponentKey<NoticeProcessorPipeline> {
         val ComponentStorage.noticeProcessorPipeline get() = get(NoticeProcessorPipeline)
@@ -54,7 +57,7 @@ internal interface NoticeProcessorPipeline {
         @JvmStatic
         suspend inline fun QQAndroidBot.processPacketThroughPipeline(
             data: ProtocolStruct,
-            attributes: TypeSafeMap = TypeSafeMap(),
+            attributes: TypeSafeMap = TypeSafeMap.EMPTY,
         ): Packet {
             return components.noticeProcessorPipeline.process(this, data, attributes).toPacket()
         }
@@ -66,8 +69,8 @@ internal value class MutableProcessResult(
     val data: MutableCollection<Packet>
 )
 
-internal interface PipelineContext {
-    val bot: QQAndroidBot
+internal interface PipelineContext : BotAware {
+    override val bot: QQAndroidBot
 
     val attributes: TypeSafeMap
 
@@ -83,13 +86,13 @@ internal interface PipelineContext {
      * and throws a [contextualBugReportException] or logs something.
      */
     @ConsumptionMarker
-    fun NoticeProcessor.markAsConsumed()
+    fun NoticeProcessor.markAsConsumed(marker: Any = this)
 
     /**
      * Marks the input as not consumed, if it was marked by this [NoticeProcessor].
      */
     @ConsumptionMarker
-    fun NoticeProcessor.markNotConsumed()
+    fun NoticeProcessor.markNotConsumed(marker: Any = this)
 
     @DslMarker
     annotation class ConsumptionMarker // to give an explicit color.
@@ -116,13 +119,21 @@ internal interface PipelineContext {
     /**
      * Fire the [data] into the processor pipeline, and collect the results to current [collected].
      *
+     * @param attributes extra attributes
      * @return result collected from processors. This would also have been collected to this context (where you call [processAlso]).
      */
-    suspend fun processAlso(data: ProtocolStruct): ProcessResult
+    suspend fun processAlso(data: ProtocolStruct, attributes: TypeSafeMap = TypeSafeMap.EMPTY): ProcessResult
 
     companion object {
         val KEY_FROM_SYNC = TypeKey<Boolean>("fromSync")
+        val KEY_MSG_INFO = TypeKey<MsgInfo>("msgInfo")
+
         val PipelineContext.fromSync get() = attributes[KEY_FROM_SYNC]
+
+        /**
+         * 来自 [MsgInfo] 的数据, 即 [MsgType0x210], [MsgType0x2DC] 的处理过程之中可以使用
+         */
+        val PipelineContext.msgInfo get() = attributes[KEY_MSG_INFO]
     }
 }
 
@@ -142,15 +153,15 @@ internal open class NoticeProcessorPipelineImpl private constructor() : NoticePr
     inner class ContextImpl(
         override val bot: QQAndroidBot, override val attributes: TypeSafeMap,
     ) : PipelineContext {
-        private val consumers: Stack<NoticeProcessor> = Stack()
+        private val consumers: Stack<Any> = Stack()
 
         override val isConsumed: Boolean get() = consumers.isNotEmpty()
-        override fun NoticeProcessor.markAsConsumed() {
-            consumers.push(this)
+        override fun NoticeProcessor.markAsConsumed(marker: Any) {
+            consumers.push(marker)
         }
 
-        override fun NoticeProcessor.markNotConsumed() {
-            if (consumers.peek() === this) {
+        override fun NoticeProcessor.markNotConsumed(marker: Any) {
+            if (consumers.peek() === marker) {
                 consumers.pop()
             }
         }
@@ -165,8 +176,8 @@ internal open class NoticeProcessorPipelineImpl private constructor() : NoticePr
             this.collected.data.addAll(packets)
         }
 
-        override suspend fun processAlso(data: ProtocolStruct): ProcessResult {
-            return process(bot, data, attributes)
+        override suspend fun processAlso(data: ProtocolStruct, attributes: TypeSafeMap): ProcessResult {
+            return process(bot, data, this.attributes + attributes)
         }
     }
 

+ 44 - 0
mirai-core/src/commonMain/kotlin/network/notice/PrivateContactSupport.kt

@@ -0,0 +1,44 @@
+/*
+ * 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/dev/LICENSE
+ */
+
+package net.mamoe.mirai.internal.network.notice
+
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.contact.GroupImpl
+
+///////////////////////////////////////////////////////////////////////////
+// Extension interfaces ---- should convert to context receivers in the future.
+///////////////////////////////////////////////////////////////////////////
+
+internal interface BotAware : PrivateContactSupport {
+    override val bot: QQAndroidBot
+}
+
+internal interface GroupAware : GroupMemberSupport, BotAware {
+    override val group: GroupImpl
+    override val bot: QQAndroidBot get() = group.bot
+}
+
+internal interface PrivateContactSupport {
+    val bot: QQAndroidBot
+
+    fun Long.findFriend() = bot.friends[this]
+    fun Long.findStranger() = bot.strangers[this]
+    fun Long.findFriendOrStranger() = findFriend() ?: findStranger()
+    fun String.findFriend() = this.toLongOrNull()?.findFriend()
+    fun String.findStranger() = this.toLongOrNull()?.findStranger()
+    fun String.findFriendOrStranger() = this.toLongOrNull()?.findFriendOrStranger()
+}
+
+internal interface GroupMemberSupport {
+    val group: GroupImpl
+
+    fun Long.findMember() = group[this]
+    fun String.findMember() = this.toLongOrNull()?.findMember()
+}

+ 7 - 6
mirai-core/src/commonMain/kotlin/network/notice/decoders/MsgInfoDecoder.kt

@@ -15,9 +15,11 @@ import kotlinx.io.core.readUInt
 import net.mamoe.mirai.internal.contact.GroupImpl
 import net.mamoe.mirai.internal.contact.checkIsGroupImpl
 import net.mamoe.mirai.internal.network.components.PipelineContext
+import net.mamoe.mirai.internal.network.components.PipelineContext.Companion.KEY_MSG_INFO
 import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncController
 import net.mamoe.mirai.internal.network.components.syncOnlinePush
+import net.mamoe.mirai.internal.network.notice.GroupAware
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
 import net.mamoe.mirai.internal.network.protocol.data.jce.OnlinePushPack.SvcReqPushMsg
@@ -46,7 +48,7 @@ internal class MsgInfoDecoder(
         if (!bot.syncController.syncOnlinePush(data)) return
         when (data.shMsgType.toUShort().toInt()) {
             // 528
-            0x210 -> processAlso(data.vMsg.loadAs(MsgType0x210.serializer()))
+            0x210 -> processAlso(data.vMsg.loadAs(MsgType0x210.serializer()), KEY_MSG_INFO to data)
 
             // 732
             0x2dc -> {
@@ -57,7 +59,7 @@ internal class MsgInfoDecoder(
                     val kind = readByte().toInt()
                     discardExact(1)
 
-                    processAlso(MsgType0x2DC(kind, group, this.readBytes()))
+                    processAlso(MsgType0x2DC(kind, group, this.readBytes()), KEY_MSG_INFO to data)
                 }
             }
             else -> {
@@ -67,13 +69,12 @@ internal class MsgInfoDecoder(
     }
 }
 
-internal interface BaseMsgType0x2DC<V> {
+internal interface BaseMsgType0x2DC<V> : GroupAware {
     val kind: Int
-    val group: GroupImpl
+    override val group: GroupImpl
     val buf: V
 
-    fun Long.findMember() = group[this]
-    fun String.findMember() = this.toLongOrNull()?.let { group[it] }
+    override val bot get() = group.bot
 }
 
 internal data class MsgType0x2DC(

+ 2 - 2
mirai-core/src/commonMain/kotlin/network/notice/group/GroupMessageProcessor.kt

@@ -27,7 +27,7 @@ import net.mamoe.mirai.internal.network.components.PipelineContext
 import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncController
 import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor.MemberNick.Companion.generateMemberNickFromMember
-import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageNoticeProcessor
+import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgOnlinePush
@@ -37,7 +37,7 @@ import net.mamoe.mirai.message.data.MessageSourceKind
 import net.mamoe.mirai.utils.*
 
 /**
- * Handles [GroupMessageEvent]. For private message events, see [PrivateMessageNoticeProcessor]
+ * Handles [GroupMessageEvent]. For private message events, see [PrivateMessageProcessor]
  */
 internal class GroupMessageProcessor(
     private val logger: MiraiLogger,

+ 133 - 7
mirai-core/src/commonMain/kotlin/network/notice/group/GroupNotificationProcessor.kt

@@ -16,6 +16,7 @@ import net.mamoe.mirai.data.GroupHonorType
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.GroupImpl
+import net.mamoe.mirai.internal.contact.checkIsGroupImpl
 import net.mamoe.mirai.internal.contact.checkIsMemberImpl
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
@@ -23,15 +24,135 @@ import net.mamoe.mirai.internal.network.components.PipelineContext
 import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.notice.NewContactSupport
 import net.mamoe.mirai.internal.network.notice.decoders.MsgType0x2DC
+import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
+import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
+import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27
 import net.mamoe.mirai.internal.network.protocol.data.proto.TroopTips0x857
 import net.mamoe.mirai.internal.utils._miraiContentToString
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
-import net.mamoe.mirai.utils.context
-import net.mamoe.mirai.utils.currentTimeSeconds
-import net.mamoe.mirai.utils.debug
-import net.mamoe.mirai.utils.read
+import net.mamoe.mirai.utils.*
 
 internal class GroupNotificationProcessor : MixedNoticeProcessor(), NewContactSupport {
+
+    override suspend fun PipelineContext.processImpl(data: MsgType0x210) = data.context {
+        when (data.uSubMsgType) {
+            0x27L -> {
+                val body = vProtobuf.loadAs(Submsgtype0x27.SubMsgType0x27.SubMsgType0x27MsgBody.serializer())
+                for (msgModInfo in body.msgModInfos) {
+                    markAsConsumed(msgModInfo)
+                    when {
+                        msgModInfo.msgModGroupProfile != null -> handleGroupProfileChanged(msgModInfo.msgModGroupProfile)
+                        msgModInfo.msgModGroupMemberProfile != null -> handleGroupMemberProfileChanged(msgModInfo.msgModGroupMemberProfile)
+                        else -> markNotConsumed(msgModInfo)
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @see GroupNameChangeEvent
+     */
+    private fun PipelineContext.handleGroupProfileChanged(
+        modGroupProfile: Submsgtype0x27.SubMsgType0x27.ModGroupProfile
+    ) {
+        for (info in modGroupProfile.msgGroupProfileInfos) {
+            when (info.field) {
+                1 -> {
+                    // 群名
+                    val new = info.value.encodeToString()
+
+                    val group = bot.getGroup(modGroupProfile.groupCode) ?: continue
+                    group.checkIsGroupImpl()
+                    val old = group.name
+
+                    if (new == old) continue
+
+                    if (modGroupProfile.cmdUin == bot.id) continue
+                    val operator = group[modGroupProfile.cmdUin] ?: continue
+
+                    group.settings.nameField = new
+
+                    collect(GroupNameChangeEvent(old, new, group, operator))
+                }
+                2 -> {
+                    // 头像
+                    // top_package/akkz.java:3446
+                    /*
+                        var4 = var82.byteAt(0);
+                           short var3 = (short) (var82.byteAt(1) | var4 << 8);
+                           var85 = var18.method_77927(var7 + "");
+                           var85.troopface = var3;
+                           var85.hasSetNewTroopHead = true;
+                         */
+                    //                        bot.logger.debug(
+                    //                            contextualBugReportException(
+                    //                                "解析 Transformers528 0x27L ModGroupProfile 群头像修改",
+                    //                                forDebug = "this=${this._miraiContentToString()}"
+                    //                            )
+                    //                        )
+                }
+                3 -> { // troop.credit.data
+                    // top_package/akkz.java:3475
+                    // top_package/akkz.java:3498
+                    //                        bot.logger.debug(
+                    //                            contextualBugReportException(
+                    //                                "解析 Transformers528 0x27L ModGroupProfile 群 troop.credit.data",
+                    //                                forDebug = "this=${this._miraiContentToString()}"
+                    //                            )
+                    //                        )
+                }
+                else -> {
+                }
+            }
+        }
+    }
+
+    /**
+     * @see MemberCardChangeEvent
+     */
+    private fun PipelineContext.handleGroupMemberProfileChanged(
+        modGroupMemberProfile: Submsgtype0x27.SubMsgType0x27.ModGroupMemberProfile
+    ) {
+        for (info in modGroupMemberProfile.msgGroupMemberProfileInfos) {
+            when (info.field) {
+                1 -> { // name card
+                    val new = info.value
+                    val group = bot.getGroup(modGroupMemberProfile.groupCode) ?: continue
+                    group.checkIsGroupImpl()
+                    val member = group[modGroupMemberProfile.uin] ?: continue
+                    member.checkIsMemberImpl()
+
+                    val old = member.nameCard
+
+                    if (new == old) continue
+                    member._nameCard = new
+
+                    collect(MemberCardChangeEvent(old, new, member))
+                }
+                2 -> {
+                    if (info.value.singleOrNull()?.code != 0) {
+                        bot.logger.debug {
+                            "Unknown Transformers528 0x27L ModGroupMemberProfile, field=${info.field}, value=${info.value}"
+                        }
+                    }
+                    continue
+                }
+                else -> {
+                    bot.logger.debug {
+                        "Unknown Transformers528 0x27L ModGroupMemberProfile, field=${info.field}, value=${info.value}"
+                    }
+                    continue
+                }
+            }
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // MsgType0x2DC
+    ///////////////////////////////////////////////////////////////////////////
+
     override suspend fun PipelineContext.processImpl(data: MsgType0x2DC) {
         when (data.kind) {
             0x0C -> processMute(data)
@@ -164,16 +285,17 @@ internal class GroupNotificationProcessor : MixedNoticeProcessor(), NewContactSu
      * @see NudgeEvent
      * @see MemberHonorChangeEvent
      * @see GroupTalkativeChangeEvent
-     */
+     */ // gray tip: 聊天中的灰色小框系统提示信息
     private fun PipelineContext.processGrayTip(
         data: MsgType0x2DC,
     ) = data.context {
         val grayTip = buf.loadAs(TroopTips0x857.NotifyMsgBody.serializer(), 1).optGeneralGrayTip
         markAsConsumed()
         when (grayTip?.templId) {
-            // 戳一戳
+            // 戳一戳
             10043L, 1133L, 1132L, 1134L, 1135L, 1136L -> {
-                //预置数据,服务器将不会提供己方已知消息
+                // group nudge
+                // 预置数据,服务器将不会提供己方已知消息
                 val action = grayTip.msgTemplParam["action_str"].orEmpty()
                 val from = grayTip.msgTemplParam["uin_str1"]?.findMember() ?: group.botAsMember
                 val target = grayTip.msgTemplParam["uin_str2"]?.findMember() ?: group.botAsMember
@@ -211,3 +333,7 @@ internal class GroupNotificationProcessor : MixedNoticeProcessor(), NewContactSu
 }
 
 internal operator fun List<TroopTips0x857.TemplParam>.get(name: String) = this.findLast { it.name == name }?.value
+
+@JvmName("get2")
+internal operator fun List<Submsgtype0x122.Submsgtype0x122.TemplParam>.get(name: String) =
+    this.findLast { it.name == name }?.value

+ 83 - 0
mirai-core/src/commonMain/kotlin/network/notice/priv/FriendNoticeProcessor.kt

@@ -12,6 +12,9 @@ package net.mamoe.mirai.internal.network.notice.priv
 import kotlinx.io.core.discardExact
 import kotlinx.io.core.readUByte
 import kotlinx.io.core.readUShort
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.protobuf.ProtoNumber
+import net.mamoe.mirai.contact.User
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.contact.impl
 import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
@@ -19,17 +22,21 @@ import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
 import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
 import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
 import net.mamoe.mirai.internal.network.components.PipelineContext
+import net.mamoe.mirai.internal.network.components.PipelineContext.Companion.msgInfo
 import net.mamoe.mirai.internal.network.notice.NewContactSupport
+import net.mamoe.mirai.internal.network.notice.group.get
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
 import net.mamoe.mirai.internal.network.protocol.data.proto.FrdSysMsg
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x115.SubMsgType0x115
+import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
 import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
 import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x44.Submsgtype0x44
 import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0xb3.SubMsgType0xb3
 import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList.GetFriendGroupList
 import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
 import net.mamoe.mirai.internal.utils._miraiContentToString
+import net.mamoe.mirai.internal.utils.io.ProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
 import net.mamoe.mirai.utils.*
 
@@ -113,10 +120,67 @@ internal class FriendNoticeProcessor(
                 val body = vProtobuf.loadAs(SubMsgType0x115.MsgBody.serializer())
                 handleInputStatusChanged(body)
             }
+            0x122L -> {
+                val body = vProtobuf.loadAs(Submsgtype0x122.Submsgtype0x122.MsgBody.serializer())
+                when (body.templId) {
+                    //戳一戳
+                    1132L, 1133L, 1134L, 1135L, 1136L, 10043L -> handlePrivateNudge(body)
+                }
+            }
+            0x8AL -> {
+                val body = vProtobuf.loadAs(Sub8A.serializer())
+                processFriendRecall(body)
+            }
             else -> markNotConsumed()
         }
     }
 
+
+    @Serializable
+    private class Wording(
+        @ProtoNumber(1) val itemID: Int = 0,
+        @ProtoNumber(2) val itemName: String = "",
+    ) : ProtoBuf
+
+    @Serializable
+    private class Sub8AMsgInfo(
+        @ProtoNumber(1) val fromUin: Long,
+        @ProtoNumber(2) val botUin: Long,
+        @ProtoNumber(3) val srcId: Int,
+        @ProtoNumber(4) val srcInternalId: Long,
+        @ProtoNumber(5) val time: Long,
+        @ProtoNumber(6) val random: Int,
+        @ProtoNumber(7) val pkgNum: Int, // 1
+        @ProtoNumber(8) val pkgIndex: Int, // 0
+        @ProtoNumber(9) val devSeq: Int, // 0
+        @ProtoNumber(12) val flag: Int, // 1
+        @ProtoNumber(13) val wording: Wording,
+    ) : ProtoBuf
+
+    @Serializable
+    private class Sub8A(
+        @ProtoNumber(1) val msgInfo: List<Sub8AMsgInfo>,
+        @ProtoNumber(2) val appId: Int, // 1
+        @ProtoNumber(3) val instId: Int, // 1
+        @ProtoNumber(4) val longMessageFlag: Int, // 0
+        @ProtoNumber(5) val reserved: ByteArray? = null, // struct{ boolean(1), boolean(2) }
+    ) : ProtoBuf
+
+    private fun PipelineContext.processFriendRecall(body: Sub8A) {
+        for (info in body.msgInfo) {
+            if (info.botUin != bot.id) continue
+            collected += MessageRecallEvent.FriendRecall(
+                bot = bot,
+                messageIds = intArrayOf(info.srcId),
+                messageInternalIds = intArrayOf(info.srcInternalId.toInt()),
+                messageTime = info.time.toInt(),
+                operatorId = info.fromUin,
+                operator = bot.getFriend(info.fromUin) ?: continue,
+            )
+        }
+    }
+
+
     private fun PipelineContext.handleInputStatusChanged(body: SubMsgType0x115.MsgBody) {
         val friend = bot.getFriend(body.fromUin) ?: return
         val item = body.msgNotifyItem ?: return
@@ -203,4 +267,23 @@ internal class FriendNoticeProcessor(
         collect(FriendAddEvent(added))
         if (removed != null) collect(StrangerRelationChangeEvent.Friended(removed, added))
     }
+
+    private fun PipelineContext.handlePrivateNudge(body: Submsgtype0x122.Submsgtype0x122.MsgBody) {
+        val action = body.msgTemplParam["action_str"].orEmpty()
+        val from = body.msgTemplParam["uin_str1"]?.findFriendOrStranger() ?: bot.asFriend
+        val target = body.msgTemplParam["uin_str2"]?.findFriendOrStranger() ?: bot.asFriend
+        val suffix = body.msgTemplParam["suffix_str"].orEmpty()
+
+        val subject: User = bot.getFriend(msgInfo.lFromUin)
+            ?: bot.getStranger(msgInfo.lFromUin)
+            ?: return
+
+        collected += NudgeEvent(
+            from = if (from.id == bot.id) bot else from,
+            target = if (target.id == bot.id) bot else target,
+            action = action,
+            suffix = suffix,
+            subject = subject,
+        )
+    }
 }

+ 1 - 1
mirai-core/src/commonMain/kotlin/network/notice/priv/PrivateMessageNoticeProcessor.kt → mirai-core/src/commonMain/kotlin/network/notice/priv/PrivateMessageProcessor.kt

@@ -34,7 +34,7 @@ import net.mamoe.mirai.utils.context
  * @see GroupTempMessageEvent
  * @see GroupTempMessageSyncEvent
  */
-internal class PrivateMessageNoticeProcessor : SimpleNoticeProcessor<MsgComm.Msg>(type()) {
+internal class PrivateMessageProcessor : SimpleNoticeProcessor<MsgComm.Msg>(type()) {
     override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
         markAsConsumed()
         if (msgHead.fromUin == bot.id && fromSync) {

+ 2 - 2
mirai-core/src/commonMain/kotlin/network/protocol/data/proto/msgType0x210.kt

@@ -408,8 +408,8 @@ internal class Submsgtype0x122 {
 
         @Serializable
         internal class TemplParam(
-            @ProtoNumber(1) @JvmField val name: ByteArray = EMPTY_BYTE_ARRAY,
-            @ProtoNumber(2) @JvmField val value: ByteArray = EMPTY_BYTE_ARRAY,
+            @ProtoNumber(1) @JvmField val name: String = "",
+            @ProtoNumber(2) @JvmField val value: String = "",
         ) : ProtoBuf
     }
 }

+ 3 - 203
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt

@@ -10,36 +10,23 @@
 package net.mamoe.mirai.internal.network.protocol.packet.chat.receive
 
 import kotlinx.io.core.ByteReadPacket
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.protobuf.ProtoNumber
-import net.mamoe.mirai.contact.User
-import net.mamoe.mirai.event.events.GroupNameChangeEvent
-import net.mamoe.mirai.event.events.MemberCardChangeEvent
-import net.mamoe.mirai.event.events.MessageRecallEvent
-import net.mamoe.mirai.event.events.NudgeEvent
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.GroupImpl
-import net.mamoe.mirai.internal.contact.checkIsGroupImpl
-import net.mamoe.mirai.internal.contact.checkIsMemberImpl
 import net.mamoe.mirai.internal.network.MultiPacket
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.processPacketThroughPipeline
-import net.mamoe.mirai.internal.network.handler.logger
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
 import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
 import net.mamoe.mirai.internal.network.protocol.data.jce.OnlinePushPack
 import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
-import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
 import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.buildResponseUniPacket
 import net.mamoe.mirai.internal.utils._miraiContentToString
-import net.mamoe.mirai.internal.utils.io.ProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
 import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
 import net.mamoe.mirai.internal.utils.io.serialization.writeJceRequestPacket
 import net.mamoe.mirai.utils.debug
-import net.mamoe.mirai.utils.encodeToString
 
 
 //0C 01 B1 89 BE 09 5E 3D 72 A6 00 01 73 68 FC 06 00 00 00 3C
@@ -206,37 +193,6 @@ internal inline fun lambda528(crossinline block: suspend MsgType0x210.(QQAndroid
     }
 }
 
-@Serializable
-private class Wording(
-    @ProtoNumber(1) val itemID: Int = 0,
-    @ProtoNumber(2) val itemName: String = "",
-) : ProtoBuf
-
-@Serializable
-private class Sub8AMsgInfo(
-    @ProtoNumber(1) val fromUin: Long,
-    @ProtoNumber(2) val botUin: Long,
-    @ProtoNumber(3) val srcId: Int,
-    @ProtoNumber(4) val srcInternalId: Long,
-    @ProtoNumber(5) val time: Long,
-    @ProtoNumber(6) val random: Int,
-    @ProtoNumber(7) val pkgNum: Int, // 1
-    @ProtoNumber(8) val pkgIndex: Int, // 0
-    @ProtoNumber(9) val devSeq: Int, // 0
-    @ProtoNumber(12) val flag: Int, // 1
-    @ProtoNumber(13) val wording: Wording,
-) : ProtoBuf
-
-@Serializable
-private class Sub8A(
-    @ProtoNumber(1) val msgInfo: List<Sub8AMsgInfo>,
-    @ProtoNumber(2) val appId: Int, // 1
-    @ProtoNumber(3) val instId: Int, // 1
-    @ProtoNumber(4) val longMessageFlag: Int, // 0
-    @ProtoNumber(5) val reserved: ByteArray? = null, // struct{ boolean(1), boolean(2) }
-) : ProtoBuf
-
-
 // uSubMsgType to vProtobuf
 // 138 or 139: top_package/akln.java:1568
 // 66: top_package/nhz.java:269
@@ -247,18 +203,7 @@ private class Sub8A(
 internal object Transformers528 : Map<Long, Lambda528> by mapOf(
 
     0x8AL to lambda528 { bot ->
-
-        return@lambda528 vProtobuf.loadAs(Sub8A.serializer()).msgInfo.asSequence()
-            .filter { it.botUin == bot.id }.mapNotNull { info ->
-                MessageRecallEvent.FriendRecall(
-                    bot = bot,
-                    messageIds = intArrayOf(info.srcId),
-                    messageInternalIds = intArrayOf(info.srcInternalId.toInt()),
-                    messageTime = info.time.toInt(),
-                    operatorId = info.fromUin,
-                    operator = bot.getFriend(info.fromUin) ?: return@mapNotNull null,
-                )
-            }
+        TODO("removed")
     },
 
     //戳一戳信息等
@@ -267,45 +212,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
         when (body.templId) {
             //戳一戳
             1132L, 1133L, 1134L, 1135L, 1136L, 10043L -> {
-                //预置数据,服务器将不会提供己方已知消息
-                var from: User? = null
-                var action = ""
-                var target: User? = null
-                var suffix = ""
-                body.msgTemplParam.asSequence().map { param ->
-                    param.name.decodeToString() to param.value.decodeToString()
-                }.forEach { (key, value) ->
-                    when (key) {
-                        "action_str" -> action = value
-                        "uin_str1" -> from = bot.getFriend(value.toLong()) ?: bot.getStranger(value.toLong())
-                                ?: return@lambda528 emptySequence()
-                        "uin_str2" -> target = bot.getFriend(value.toLong()) ?: bot.getStranger(value.toLong())
-                                ?: return@lambda528 emptySequence()
-                        "suffix_str" -> suffix = value
-                    }
-                }
-
-                val subject: User = bot.getFriend(msgInfo.lFromUin)
-                    ?: bot.getStranger(msgInfo.lFromUin)
-                    ?: return@lambda528 emptySequence()
-
-                sequenceOf(
-                    when {
-                        target == null && from == null || target?.id == from?.id && from?.id == bot.id -> {
-                            //机器人自己戳自己
-                            NudgeEvent(from = bot, target = bot, subject = subject, action, suffix)
-                        }
-                        target == null || target!!.id == bot.id -> {
-                            //机器人自身为目标
-                            NudgeEvent(from = subject, target = bot, subject = subject, action, suffix)
-                        }
-                        from == null || from!!.id == bot.id -> {
-                            //机器人自身为发起者
-                            NudgeEvent(from = bot, target = subject, subject = subject, action, suffix)
-                        }
-                        else -> NudgeEvent(from = subject, target = subject, subject = subject, action, suffix)
-                    },
-                )
+                TODO("removed")
             }
             else -> {
                 bot.logger.debug {
@@ -317,113 +224,6 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
     },
     // 群相关,  ModFriendRemark, DelFriend, ModGroupProfile
     0x27L to lambda528 { bot ->
-        fun ModGroupProfile.transform(bot: QQAndroidBot): Sequence<Packet> {
-            return this.msgGroupProfileInfos.asSequence().mapNotNull { info ->
-                when (info.field) {
-                    1 -> {
-                        // 群名
-                        val new = info.value.encodeToString()
-
-                        val group = bot.getGroup(this.groupCode) ?: return@mapNotNull null
-                        group.checkIsGroupImpl()
-                        val old = group.name
-
-                        if (new == old) return@mapNotNull null
-
-                        val operator = if (this.cmdUin == bot.id) null
-                        else group[this.cmdUin] ?: return@mapNotNull null
-
-                        group.settings.nameField = new
-
-                        return@mapNotNull GroupNameChangeEvent(old, new, group, operator)
-                    }
-                    2 -> {
-                        // 头像
-                        // top_package/akkz.java:3446
-                        /*
-                        var4 = var82.byteAt(0);
-                           short var3 = (short) (var82.byteAt(1) | var4 << 8);
-                           var85 = var18.method_77927(var7 + "");
-                           var85.troopface = var3;
-                           var85.hasSetNewTroopHead = true;
-                         */
-                        //                        bot.logger.debug(
-                        //                            contextualBugReportException(
-                        //                                "解析 Transformers528 0x27L ModGroupProfile 群头像修改",
-                        //                                forDebug = "this=${this._miraiContentToString()}"
-                        //                            )
-                        //                        )
-                        null
-                    }
-                    3 -> { // troop.credit.data
-                        // top_package/akkz.java:3475
-                        // top_package/akkz.java:3498
-                        //                        bot.logger.debug(
-                        //                            contextualBugReportException(
-                        //                                "解析 Transformers528 0x27L ModGroupProfile 群 troop.credit.data",
-                        //                                forDebug = "this=${this._miraiContentToString()}"
-                        //                            )
-                        //                        )
-                        null
-                    }
-
-                    else -> null
-                }
-            }
-        }
-
-        fun ModGroupMemberProfile.transform(bot: QQAndroidBot): Sequence<Packet> {
-            return this.msgGroupMemberProfileInfos.asSequence().mapNotNull { info ->
-                when (info.field) {
-                    1 -> { // name card
-                        val new = info.value
-                        val group = bot.getGroup(this.groupCode) ?: return@mapNotNull null
-                        group.checkIsGroupImpl()
-                        val member = group[this.uin] ?: return@mapNotNull null
-                        member.checkIsMemberImpl()
-
-                        val old = member.nameCard
-
-                        if (new == old) return@mapNotNull null
-                        member._nameCard = new
-
-                        return@mapNotNull MemberCardChangeEvent(old, new, member)
-                    }
-                    2 -> {
-                        if (info.value.singleOrNull()?.code != 0) {
-                            bot.logger.debug {
-                                "Unknown Transformers528 0x27L ModGroupMemberProfile, field=${info.field}, value=${info.value}"
-                            }
-                        }
-                        return@mapNotNull null
-                    }
-                    else -> {
-                        bot.logger.debug {
-                            "Unknown Transformers528 0x27L ModGroupMemberProfile, field=${info.field}, value=${info.value}"
-                        }
-                        return@mapNotNull null
-                    }
-                }
-            }
-        }
-
-        return@lambda528 vProtobuf.loadAs(SubMsgType0x27MsgBody.serializer()).msgModInfos.asSequence()
-            .flatMap {
-                when {
-                    it.msgModFriendRemark != null -> TODO("removed")
-                    it.msgDelFriend != null -> TODO("removed")
-                    it.msgModGroupProfile != null -> it.msgModGroupProfile.transform(bot)
-                    it.msgModGroupMemberProfile != null -> it.msgModGroupMemberProfile.transform(bot)
-                    it.msgModCustomFace != null -> TODO("removed")
-                    it.msgModProfile != null -> TODO("removed")
-                    else -> {
-                        bot.network.logger.debug {
-                            "Transformers528 0x27L: new data: ${it._miraiContentToString()}"
-                        }
-                        emptySequence()
-                    }
-                }
-            }
-        // 0A 1C 10 28 4A 18 0A 16 08 00 10 A2 FF 8C F0 03 1A 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B
+        TODO("removed")
     },
 )