Migrate more transformers to NoticeProcessorPipeline

This commit is contained in:
Him188 2021-08-14 17:51:12 +08:00
parent edf1bc9a2e
commit 9c272ebf1e
11 changed files with 380 additions and 251 deletions

View File

@ -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 =
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 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())
public operator fun <T> contains(key: TypeKey<T>): Boolean = get(key) != null
public operator fun <T> set(key: TypeKey<T>, value: T) {
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)
}

View File

@ -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()

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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(

View File

@ -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,

View File

@ -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

View File

@ -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,
)
}
}

View File

@ -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) {

View File

@ -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
}
}

View File

@ -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")
},
)