Add UnconsumedNoticesAlerter and cleanup

Co-authored-by: Karlatemp <karlatemp@vip.qq.com>
This commit is contained in:
Him188 2021-06-27 18:28:43 +08:00
parent 56cbe2d8a2
commit 09265190e9
16 changed files with 272 additions and 354 deletions

View File

@ -34,10 +34,10 @@ public value class TypeSafeMap(
map[key] = value
}
public fun <T> remove(key: TypeKey<T>): T? = map.remove(key).uncheckedCast()
public fun <T> remove(key: TypeKey<T>): T? = map.remove(key)?.uncheckedCast()
}
public inline fun buildTypeSafeMap(block: TypeSafeMap.() -> Unit): TypeSafeMap {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return TypeSafeMap().apply(block)
}
}

View File

@ -38,6 +38,8 @@ import net.mamoe.mirai.internal.network.handler.state.safe
import net.mamoe.mirai.internal.network.impl.netty.ForceOfflineException
import net.mamoe.mirai.internal.network.impl.netty.NettyNetworkHandlerFactory
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.internal.network.notice.*
import net.mamoe.mirai.internal.network.notice.decoders.MsgInfoDecoder
import net.mamoe.mirai.internal.utils.subLogger
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiLogger
@ -149,7 +151,20 @@ internal open class QQAndroidBot constructor(
// There's no need to interrupt a broadcasting event when network handler closed.
set(EventDispatcher, EventDispatcherImpl(bot.coroutineContext, logger.subLogger("EventDispatcher")))
set(NoticeProcessorPipeline, NoticeProcessorPipelineImpl(networkLogger.subLogger("NoticeProcessorPipeline")))
val pipelineLogger = networkLogger.subLogger("NoticeProcessor") // shorten name
set(
NoticeProcessorPipeline,
NoticeProcessorPipelineImpl().apply {
registerProcessor(MsgInfoDecoder())
registerProcessor(FriendNoticeProcessor(pipelineLogger))
registerProcessor(GroupListNoticeProcessor(pipelineLogger))
registerProcessor(GroupMessageProcessor())
registerProcessor(PrivateMessageNoticeProcessor())
registerProcessor(OtherClientNoticeProcessor())
registerProcessor(UnconsumedNoticesAlerter(pipelineLogger))
},
)
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
@ -164,34 +179,35 @@ internal open class QQAndroidBot constructor(
set(ContactUpdater, ContactUpdaterImpl(bot, components, networkLogger.subLogger("ContactUpdater")))
set(
BdhSessionSyncer,
BdhSessionSyncerImpl(configuration, components, networkLogger.subLogger("BotSessionSyncer"))
BdhSessionSyncerImpl(configuration, components, networkLogger.subLogger("BotSessionSyncer")),
)
set(
MessageSvcSyncer,
MessageSvcSyncerImpl(bot, bot.coroutineContext, networkLogger.subLogger("MessageSvcSyncer"))
MessageSvcSyncerImpl(bot, bot.coroutineContext, networkLogger.subLogger("MessageSvcSyncer")),
)
set(
EcdhInitialPublicKeyUpdater,
EcdhInitialPublicKeyUpdaterImpl(bot, networkLogger.subLogger("ECDHInitialPublicKeyUpdater"))
EcdhInitialPublicKeyUpdaterImpl(bot, networkLogger.subLogger("ECDHInitialPublicKeyUpdater")),
)
set(ServerList, ServerListImpl(networkLogger.subLogger("ServerList")))
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
set(
PacketHandler, PacketHandlerChain(
PacketHandler,
PacketHandlerChain(
LoggingPacketHandlerAdapter(get(PacketLoggingStrategy), networkLogger),
EventBroadcasterPacketHandler(components),
CallPacketFactoryPacketHandler(bot)
)
CallPacketFactoryPacketHandler(bot),
),
)
set(PacketCodec, PacketCodecImpl())
set(
OtherClientUpdater,
OtherClientUpdaterImpl(bot, components, networkLogger.subLogger("OtherClientUpdater"))
OtherClientUpdaterImpl(bot, components, networkLogger.subLogger("OtherClientUpdater")),
)
set(ConfigPushSyncer, ConfigPushSyncerImpl())
set(
AccountSecretsManager,
configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager"))
configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager")),
)
}
@ -213,13 +229,13 @@ internal open class QQAndroidBot constructor(
val context = NetworkHandlerContextImpl(
bot,
networkLogger,
createNetworkLevelComponents()
createNetworkLevelComponents(),
)
NettyNetworkHandlerFactory.create(
context,
context[ServerList].pollAny().toSocketAddress()
context[ServerList].pollAny().toSocketAddress(),
)
}
},
) // We can move the factory to configuration but this is not necessary for now.
}

View File

@ -54,7 +54,7 @@ internal class StrangerImpl(
}
bot.network.run {
StrangerList.DelStranger(bot.client, this@StrangerImpl)
.sendAndExpect<StrangerList.DelStranger.Response>().also {
.sendAndExpect().also {
check(it.isSuccess) { "delete Stranger failed: ${it.result}" }
}
}

View File

@ -24,9 +24,10 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans.PbMs
import net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetMsg
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushTransMsg
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.TypeKey
import net.mamoe.mirai.utils.TypeSafeMap
import net.mamoe.mirai.utils.uncheckedCast
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
@ -54,14 +55,24 @@ internal interface PipelineContext {
val isConsumed: Boolean
/**
* Mark the input as consumed so that there will not be warnings like 'Unknown type xxx'. This will not stop the pipeline.
* Marks the input as consumed so that there will not be warnings like 'Unknown type xxx'. This will not stop the pipeline.
*
* If this is executed, make sure you provided all information important for debugging.
*
* You need to invoke [markAsConsumed] if your implementation includes some `else` branch which covers all situations,
* and throws a [contextualBugReportException] or logs something.
*/
fun markAsConsumed()
@ConsumptionMarker
fun NoticeProcessor.markAsConsumed()
/**
* Marks the input as not consumed, if it was marked by this [NoticeProcessor].
*/
@ConsumptionMarker
fun NoticeProcessor.markNotConsumed()
@DslMarker
annotation class ConsumptionMarker // to give an explicit color.
val collected: Collection<Packet>
@ -89,13 +100,16 @@ internal interface PipelineContext {
* @return result collected from processors. This would also have been collected to this context (where you call [fire]).
*/
suspend fun fire(data: Any?): Collection<Packet>
companion object {
val KEY_FROM_SYNC = TypeKey<Boolean>("fromSync")
val PipelineContext.fromSync get() = attributes[KEY_FROM_SYNC]
}
}
internal inline val PipelineContext.context get() = this
internal class NoticeProcessorPipelineImpl(
private val logger: MiraiLogger,
) : NoticeProcessorPipeline {
internal class NoticeProcessorPipelineImpl : NoticeProcessorPipeline {
private val processors = ArrayList<NoticeProcessor>()
private val processorsLock = ReentrantReadWriteLock()
@ -110,9 +124,17 @@ internal class NoticeProcessorPipelineImpl(
override val bot: QQAndroidBot, override val attributes: TypeSafeMap,
) : PipelineContext {
override var isConsumed: Boolean = false
override fun markAsConsumed() {
isConsumed = true
private val consumers: Stack<NoticeProcessor> = Stack()
override val isConsumed: Boolean = consumers.isNotEmpty()
override fun NoticeProcessor.markAsConsumed() {
consumers.push(this)
}
override fun NoticeProcessor.markNotConsumed() {
if (consumers.peek() === this) {
consumers.pop()
}
}
override val collected = ConcurrentLinkedQueue<Packet>()

View File

@ -1,45 +0,0 @@
/*
* 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.notice
import net.mamoe.mirai.internal.message.contextualBugReportException
import net.mamoe.mirai.internal.network.components.PipelineContext
import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans.PbMsgInfo
import net.mamoe.mirai.internal.utils._miraiContentToString
import net.mamoe.mirai.utils.read
internal class BinaryMessageProcessor : SimpleNoticeProcessor<PbMsgInfo>(type()), NewContactSupport {
override suspend fun PipelineContext.processImpl(data: PbMsgInfo) {
data.msgData.read<Unit> {
when (data.msgType) {
44 -> {
TODO("removed")
}
34 -> {
TODO("removed")
}
else -> {
when {
data.msgType == 529 && data.msgSubtype == 9 -> {
TODO("removed")
}
}
throw contextualBugReportException(
"解析 OnlinePush.PbPushTransMsg, msgType=${data.msgType}",
data._miraiContentToString(),
null,
"并描述此时机器人是否被踢出, 或是否有成员列表变更等动作."
)
}
}
}
}
}

View File

@ -86,6 +86,7 @@ internal class FriendNoticeProcessor(
}
override suspend fun PipelineContext.processImpl(data: MsgType0x210) = data.context {
markAsConsumed()
when (data.uSubMsgType) {
0xB3L -> {
// 08 01 12 52 08 A2 FF 8C F0 03 10 00 1D 15 3D 90 5E 22 2E E6 88 91 E4 BB AC E5 B7 B2 E7 BB 8F E6 98 AF E5 A5 BD E5 8F 8B E5 95 A6 EF BC 8C E4 B8 80 E8 B5 B7 E6 9D A5 E8 81 8A E5 A4 A9 E5 90 A7 21 2A 09 48 69 6D 31 38 38 6D 6F 65 30 07 38 03 48 DD F1 92 B7 07
@ -111,9 +112,8 @@ internal class FriendNoticeProcessor(
val body = vProtobuf.loadAs(SubMsgType0x115.MsgBody.serializer())
handleInputStatusChanged(body)
}
else -> return
else -> markNotConsumed()
}
markAsConsumed()
}
private fun PipelineContext.handleInputStatusChanged(body: SubMsgType0x115.MsgBody) {

View File

@ -60,6 +60,7 @@ internal class GroupListNoticeProcessor(
override suspend fun PipelineContext.processImpl(data: MsgType0x210) {
if (data.uSubMsgType != 0x44L) return
markAsConsumed()
val msg = data.vProtobuf.loadAs(Submsgtype0x44.Submsgtype0x44.MsgBody.serializer())
if (msg.msgGroupMsgSync == null) return
@ -328,34 +329,7 @@ internal class GroupListNoticeProcessor(
handleLeave(target, kind, operator, groupUin)
}
}
else -> {
when {
data.msgType == 529 && data.msgSubtype == 9 -> {
/*
PbMsgInfo#1773430973 {
fromUin=0x0000000026BA1173(649728371)
generalFlag=0x00000001(1)
msgData=0A 07 70 72 69 6E 74 65 72 10 02 1A CD 02 0A 1F 53 61 6D 73 75 6E 67 20 4D 4C 2D 31 38 36 30 20 53 65 72 69 65 73 20 28 55 53 42 30 30 31 29 0A 16 4F 6E 65 4E 6F 74 65 20 66 6F 72 20 57 69 6E 64 6F 77 73 20 31 30 0A 19 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 20 74 6F 20 45 76 65 72 6E 6F 74 65 0A 11 4F 6E 65 4E 6F 74 65 20 28 44 65 73 6B 74 6F 70 29 0A 1D 4D 69 63 72 6F 73 6F 66 74 20 58 50 53 20 44 6F 63 75 6D 65 6E 74 20 57 72 69 74 65 72 0A 16 4D 69 63 72 6F 73 6F 66 74 20 50 72 69 6E 74 20 74 6F 20 50 44 46 0A 15 46 6F 78 69 74 20 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 65 72 0A 03 46 61 78 32 09 0A 03 6A 70 67 10 01 18 00 32 0A 0A 04 6A 70 65 67 10 01 18 00 32 09 0A 03 70 6E 67 10 01 18 00 32 09 0A 03 67 69 66 10 01 18 00 32 09 0A 03 62 6D 70 10 01 18 00 32 09 0A 03 64 6F 63 10 01 18 01 32 0A 0A 04 64 6F 63 78 10 01 18 01 32 09 0A 03 74 78 74 10 00 18 00 32 09 0A 03 70 64 66 10 01 18 01 32 09 0A 03 70 70 74 10 01 18 01 32 0A 0A 04 70 70 74 78 10 01 18 01 32 09 0A 03 78 6C 73 10 01 18 01 32 0A 0A 04 78 6C 73 78 10 01 18 01
msgSeq=0x00001AFF(6911)
msgSubtype=0x00000009(9)
msgTime=0x5FDF21A3(1608458659)
msgType=0x00000211(529)
msgUid=0x010000005FDEE04C(72057595646369868)
realMsgTime=0x5FDF21A3(1608458659)
svrIp=0x3E689409(1047041033)
toUin=0x0000000026BA1173(649728371)
}
*/
return
}
}
throw contextualBugReportException(
"解析 OnlinePush.PbPushTransMsg, msgType=${data.msgType}",
data._miraiContentToString(),
null,
"并描述此时机器人是否被踢出, 或是否有成员列表变更等动作."
)
}
else -> markNotConsumed()
}
}
@ -476,4 +450,52 @@ toUin=0x0000000026BA1173(649728371)
}
}
}
// backup, copied from old code
/*
34 -> { // 主动入群
// 回答了问题, 还需要管理员审核
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 82 00 30 45 41 31 30 35 35 42 44 39 39 42 35 37 46 44 31 41 31 46 36 42 43 42 43 33 43 42 39 34 34 38 31 33 34 42 36 31 46 38 45 43 39 38 38 43 39 37 33
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 02 00 30 44 44 41 43 44 33 35 43 31 39 34 30 46 42 39 39 34 46 43 32 34 43 39 32 33 39 31 45 42 35 32 33 46 36 30 37 35 42 41 38 42 30 30 37 42 36 42 41
// 回答正确问题, 直接加入
// 27 0B 60 E7 01 76 E4 B8 DD 82 00 30 43 37 37 39 41 38 32 44 38 33 30 35 37 38 31 33 37 45 42 39 35 43 42 45 36 45 43 38 36 34 38 44 34 35 44 42 33 44 45 37 34 41 36 30 33 37 46 45
// 提交验证消息加入, 需要审核
// 被踢了??
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 46 46 32 33 36 39 35 33 31 37 42 44 46 37 43 36 39 34 37 41 45 38 39 43 45 43 42 46 33 41 37 35 39 34 39 45 36 37 33 37 31 41 39 44 33 33 45 33
/*
// 搜索后直接加入群
soutv 17:43:32 : 33类型的content = 27 0B 60 E7 01 07 6E 47 BA 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 32 30 39 39 42 39 41 46 32 39 41 35 42 33 46 34 32 30 44 36 44 36 39 35 44 38 45 34 35 30 46 30 45 30 38 45 31 41 39 42 46 46 45 32 30 32 34 35
soutv 17:43:32 : 主动入群content = 2A 3D F5 69 01 35 D7 10 EA 83 4C EF 4F DD 06 B9 DC C0 ED D4 B1 00 30 37 41 39 31 39 34 31 41 30 37 46 38 32 31 39 39 43 34 35 46 39 30 36 31 43 37 39 37 33 39 35 43 34 44 36 31 33 43 31 35 42 37 32 45 46 43 43 36
*/
val group = bot.getGroupByUinOrNull(msgHead.fromUin)
group ?: return
msgBody.msgContent.soutv("主动入群content")
if (msgBody.msgContent.read {
discardExact(4) // group code
discardExact(1) // 1
discardExact(4) // requester uin
readByte().toInt().and(0xff)
// 0x02: 回答正确问题直接加入
// 0x82: 回答了问题, 或者有验证消息, 需要管理员审核
// 0x83: 回答正确问题直接加入
} != 0x82) {
if (group.members.contains(msgHead.authUin)) {
return
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
return MemberJoinEvent.Active(group.newMember(getNewMemberInfo())
.also { group.members.delegate.addLast(it) })
} else return
}
*/
}

View File

@ -109,8 +109,14 @@ internal class OtherClientNoticeProcessor : MixedNoticeProcessor() {
*/
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
if (msgHead.msgType != 529) return
// top_package/awbk.java:3765
markAsConsumed() // todo check
if (msgHead.c2cCmd != 7) return
if (msgHead.c2cCmd != 7) {
// 各种垃圾
// 08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A
return
}
val body = msgBody.msgContent.loadAs(SubMsgType0x7.MsgBody.serializer())
val textMsg =

View File

@ -15,9 +15,9 @@ import net.mamoe.mirai.internal.contact.*
import net.mamoe.mirai.internal.getGroupByUin
import net.mamoe.mirai.internal.message.toMessageChainOnline
import net.mamoe.mirai.internal.network.components.PipelineContext
import net.mamoe.mirai.internal.network.components.PipelineContext.Companion.fromSync
import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
import net.mamoe.mirai.internal.network.components.SsoProcessor
import net.mamoe.mirai.internal.network.notice.SystemMessageProcessor.Companion.fromSync
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.utils.context
@ -35,6 +35,7 @@ import net.mamoe.mirai.utils.context
*/
internal class PrivateMessageNoticeProcessor : SimpleNoticeProcessor<MsgComm.Msg>(type()) {
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
markAsConsumed()
if (msgHead.fromUin == bot.id && fromSync) {
// Bot send message to himself? or from other client? I am not the implementer.
bot.client.sendFriendMessageSeq.updateIfSmallerThan(msgHead.msgSeq)
@ -47,7 +48,6 @@ internal class PrivateMessageNoticeProcessor : SimpleNoticeProcessor<MsgComm.Msg
208, // friend ptt, maybe also support stranger
-> {
handlePrivateMessage(data, bot.getFriend(senderUin) ?: bot.getStranger(senderUin) ?: return)
markAsConsumed()
}
141, // group temp
@ -55,7 +55,9 @@ internal class PrivateMessageNoticeProcessor : SimpleNoticeProcessor<MsgComm.Msg
val tmpHead = msgHead.c2cTmpMsgHead ?: return
val group = bot.getGroupByUin(tmpHead.groupUin) ?: return
handlePrivateMessage(data, group[senderUin] ?: return)
markAsConsumed()
}
else -> {
markNotConsumed()
}
}

View File

@ -1,161 +0,0 @@
/*
* 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.notice
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.internal.network.components.ContactUpdater
import net.mamoe.mirai.internal.network.components.MsgCommonMsgProcessor
import net.mamoe.mirai.internal.network.components.PipelineContext
import net.mamoe.mirai.internal.network.components.SsoProcessor
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.packet.chat.NewContact
import net.mamoe.mirai.utils.TypeKey
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.toUHexString
internal class SystemMessageProcessor : MsgCommonMsgProcessor(), NewContactSupport {
companion object {
val KEY_FROM_SYNC = TypeKey<Boolean>("fromSync")
val PipelineContext.fromSync get() = attributes[KEY_FROM_SYNC]
}
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg): Unit = data.run {
// TODO: 2021/6/26 extract logic into multiple processors
when (msgHead.msgType) {
33 -> bot.components[ContactUpdater].groupListModifyLock.withLock {
}
34 -> { // 与 33 重复
return
}
38 -> bot.components[ContactUpdater].groupListModifyLock.withLock { // 建群
TODO("removed")
}
85 -> bot.components[ContactUpdater].groupListModifyLock.withLock { // 其他客户端入群
TODO("removed")
}
/*
34 -> { // 主动入群
// 回答了问题, 还需要管理员审核
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 82 00 30 45 41 31 30 35 35 42 44 39 39 42 35 37 46 44 31 41 31 46 36 42 43 42 43 33 43 42 39 34 34 38 31 33 34 42 36 31 46 38 45 43 39 38 38 43 39 37 33
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 02 00 30 44 44 41 43 44 33 35 43 31 39 34 30 46 42 39 39 34 46 43 32 34 43 39 32 33 39 31 45 42 35 32 33 46 36 30 37 35 42 41 38 42 30 30 37 42 36 42 41
// 回答正确问题, 直接加入
// 27 0B 60 E7 01 76 E4 B8 DD 82 00 30 43 37 37 39 41 38 32 44 38 33 30 35 37 38 31 33 37 45 42 39 35 43 42 45 36 45 43 38 36 34 38 44 34 35 44 42 33 44 45 37 34 41 36 30 33 37 46 45
// 提交验证消息加入, 需要审核
// 被踢了??
// msgContent=27 0B 60 E7 01 76 E4 B8 DD 83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 46 46 32 33 36 39 35 33 31 37 42 44 46 37 43 36 39 34 37 41 45 38 39 43 45 43 42 46 33 41 37 35 39 34 39 45 36 37 33 37 31 41 39 44 33 33 45 33
/*
// 搜索后直接加入群
soutv 17:43:32 : 33类型的content = 27 0B 60 E7 01 07 6E 47 BA 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 32 30 39 39 42 39 41 46 32 39 41 35 42 33 46 34 32 30 44 36 44 36 39 35 44 38 45 34 35 30 46 30 45 30 38 45 31 41 39 42 46 46 45 32 30 32 34 35
soutv 17:43:32 : 主动入群content = 2A 3D F5 69 01 35 D7 10 EA 83 4C EF 4F DD 06 B9 DC C0 ED D4 B1 00 30 37 41 39 31 39 34 31 41 30 37 46 38 32 31 39 39 43 34 35 46 39 30 36 31 43 37 39 37 33 39 35 43 34 44 36 31 33 43 31 35 42 37 32 45 46 43 43 36
*/
val group = bot.getGroupByUinOrNull(msgHead.fromUin)
group ?: return
msgBody.msgContent.soutv("主动入群content")
if (msgBody.msgContent.read {
discardExact(4) // group code
discardExact(1) // 1
discardExact(4) // requester uin
readByte().toInt().and(0xff)
// 0x02: 回答正确问题直接加入
// 0x82: 回答了问题, 或者有验证消息, 需要管理员审核
// 0x83: 回答正确问题直接加入
} != 0x82) {
if (group.members.contains(msgHead.authUin)) {
return
}
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
return MemberJoinEvent.Active(group.newMember(getNewMemberInfo())
.also { group.members.delegate.addLast(it) })
} else return
}
*/
//167 单向好友
166, 167 -> {
TODO("removed")
}
208 -> {
// friend ptt
TODO("removed")
}
529 -> {
// top_package/awbk.java:3765
when (msgHead.c2cCmd) {
// other client sync
7 -> {
TODO("removed")
}
}
// 各种垃圾
// 08 04 12 1E 08 E9 07 10 B7 F7 8B 80 02 18 E9 07 20 00 28 DD F1 92 B7 07 30 DD F1 92 B7 07 48 02 50 03 32 1E 08 88 80 F8 92 CD 84 80 80 10 10 01 18 00 20 01 2A 0C 0A 0A 08 01 12 06 E5 95 8A E5 95 8A
}
141 -> {
if (!bot.components[SsoProcessor].firstLoginSucceed || msgHead.fromUin == bot.id && !fromSync) {
return
}
TODO("removed")
}
84, 87 -> { // 请求入群验证 和 被要求入群
bot.network.run {
NewContact.SystemMsgNewGroup(bot.client).sendWithoutExpect()
}
return
}
187 -> { // 请求加好友验证
bot.network.run {
NewContact.SystemMsgNewFriend(bot.client).sendWithoutExpect()
}
return
}
732 -> {
// unknown
// 前 4 byte 是群号
return
}
//陌生人添加信息
191 -> {
TODO("removed")
}
// 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58
// 732: 27 0B 60 E7 11 00 40 08 07 20 E7 C1 AD B8 02 5A 36 08 B4 E7 E0 F0 09 1A 1A 08 9C D4 16 10 F7 D2 D8 F5 05 18 D0 E2 85 F4 06 20 00 28 00 30 B4 E7 E0 F0 09 2A 0E 08 00 12 0A 08 9C D4 16 10 00 18 01 20 00 30 00 38 00
// 732: 27 0B 60 E7 11 00 33 08 07 20 E7 C1 AD B8 02 5A 29 08 EE 97 85 E9 01 1A 19 08 EE D6 16 10 FF F2 D8 F5 05 18 E9 E7 A3 05 20 00 28 00 30 EE 97 85 E9 01 2A 02 08 00 30 00 38 00
else -> {
bot.network.logger.debug { "unknown PbGetMsg type ${msgHead.msgType}, data=${msgBody.msgContent.toUHexString()}" }
return
}
}
}
// kotlin bug, don't remove
private inline fun kotlinx.atomicfu.AtomicInt.loop(action: (Int) -> Unit): Nothing {
while (true) {
action(value)
}
}
}

View File

@ -0,0 +1,135 @@
/*
* 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.notice
import net.mamoe.mirai.internal.message.contextualBugReportException
import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
import net.mamoe.mirai.internal.network.components.PipelineContext
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
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgOnlinePush
import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans
import net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
import net.mamoe.mirai.internal.utils._miraiContentToString
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.toUHexString
internal class UnconsumedNoticesAlerter(
private val logger: MiraiLogger,
) : MixedNoticeProcessor() {
override suspend fun PipelineContext.processImpl(data: MsgInfo) {
if (isConsumed) return
logger.debug { "Unknown kind ${data.shMsgType.toInt()}, data=${data.vMsg.toUHexString()}" }
}
override suspend fun PipelineContext.processImpl(data: MsgType0x210) {
if (isConsumed) return
when (data.uSubMsgType) {
0x26L, // VIP 进群提示
0x111L, // 提示共同好友
0xD4L, // bot 在其他客户端被踢或主动退出而同步情况
-> {
// Network(1994701021) 16:03:54 : unknown group 528 type 0x0000000000000026, data: 08 01 12 40 0A 06 08 F4 EF BB 8F 04 10 E7 C1 AD B8 02 18 01 22 2C 10 01 1A 1A 18 B4 DC F8 9B 0C 20 E7 C1 AD B8 02 28 06 30 02 A2 01 04 08 93 D6 03 A8 01 08 20 00 28 00 32 08 18 01 20 FE AF AF F5 05 28 00
}
0xE2L -> {
// unknown
// 0A 35 08 00 10 A2 FF 8C F0 03 1A 1B E5 90 8C E6 84 8F E4 BD A0 E7 9A 84 E5 8A A0 E5 A5 BD E5 8F 8B E8 AF B7 E6 B1 82 22 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B 28 01
// vProtobuf.loadAs(Msgtype0x210.serializer())
}
}
logger.debug { "Unknown group 528 type 0x${data.uSubMsgType.toUHexString("")}, data: " + data.vProtobuf.toUHexString() }
}
override suspend fun PipelineContext.processImpl(data: MsgType0x2DC) {
if (isConsumed) return
logger.debug { "Unknown group 732 type ${data.kind}, data: " + data.buf.toUHexString() }
}
override suspend fun PipelineContext.processImpl(data: OnlinePushTrans.PbMsgInfo) {
if (isConsumed) return
when {
data.msgType == 529 && data.msgSubtype == 9 -> {
/*
PbMsgInfo#1773430973 {
fromUin=0x0000000026BA1173(649728371)
generalFlag=0x00000001(1)
msgData=0A 07 70 72 69 6E 74 65 72 10 02 1A CD 02 0A 1F 53 61 6D 73 75 6E 67 20 4D 4C 2D 31 38 36 30 20 53 65 72 69 65 73 20 28 55 53 42 30 30 31 29 0A 16 4F 6E 65 4E 6F 74 65 20 66 6F 72 20 57 69 6E 64 6F 77 73 20 31 30 0A 19 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 20 74 6F 20 45 76 65 72 6E 6F 74 65 0A 11 4F 6E 65 4E 6F 74 65 20 28 44 65 73 6B 74 6F 70 29 0A 1D 4D 69 63 72 6F 73 6F 66 74 20 58 50 53 20 44 6F 63 75 6D 65 6E 74 20 57 72 69 74 65 72 0A 16 4D 69 63 72 6F 73 6F 66 74 20 50 72 69 6E 74 20 74 6F 20 50 44 46 0A 15 46 6F 78 69 74 20 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 65 72 0A 03 46 61 78 32 09 0A 03 6A 70 67 10 01 18 00 32 0A 0A 04 6A 70 65 67 10 01 18 00 32 09 0A 03 70 6E 67 10 01 18 00 32 09 0A 03 67 69 66 10 01 18 00 32 09 0A 03 62 6D 70 10 01 18 00 32 09 0A 03 64 6F 63 10 01 18 01 32 0A 0A 04 64 6F 63 78 10 01 18 01 32 09 0A 03 74 78 74 10 00 18 00 32 09 0A 03 70 64 66 10 01 18 01 32 09 0A 03 70 70 74 10 01 18 01 32 0A 0A 04 70 70 74 78 10 01 18 01 32 09 0A 03 78 6C 73 10 01 18 01 32 0A 0A 04 78 6C 73 78 10 01 18 01
msgSeq=0x00001AFF(6911)
msgSubtype=0x00000009(9)
msgTime=0x5FDF21A3(1608458659)
msgType=0x00000211(529)
msgUid=0x010000005FDEE04C(72057595646369868)
realMsgTime=0x5FDF21A3(1608458659)
svrIp=0x3E689409(1047041033)
toUin=0x0000000026BA1173(649728371)
}
*/
return
}
}
throw contextualBugReportException(
"解析 OnlinePush.PbPushTransMsg, msgType=${data.msgType}",
data._miraiContentToString(),
null,
"并描述此时机器人是否被踢出, 或是否有成员列表变更等动作.",
)
}
override suspend fun PipelineContext.processImpl(data: MsgOnlinePush.PbPushMsg) {
if (isConsumed) return
}
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) {
if (isConsumed) return
when (data.msgHead.msgType) {
732 -> {
// 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58
// 732: 27 0B 60 E7 11 00 40 08 07 20 E7 C1 AD B8 02 5A 36 08 B4 E7 E0 F0 09 1A 1A 08 9C D4 16 10 F7 D2 D8 F5 05 18 D0 E2 85 F4 06 20 00 28 00 30 B4 E7 E0 F0 09 2A 0E 08 00 12 0A 08 9C D4 16 10 00 18 01 20 00 30 00 38 00
// 732: 27 0B 60 E7 11 00 33 08 07 20 E7 C1 AD B8 02 5A 29 08 EE 97 85 E9 01 1A 19 08 EE D6 16 10 FF F2 D8 F5 05 18 E9 E7 A3 05 20 00 28 00 30 EE 97 85 E9 01 2A 02 08 00 30 00 38 00
// unknown
// 前 4 byte 是群号
}
84, 87 -> { // 请求入群验证 和 被要求入群
bot.network.run {
NewContact.SystemMsgNewGroup(bot.client).sendWithoutExpect()
}
}
187 -> { // 请求加好友验证
bot.network.run {
NewContact.SystemMsgNewFriend(bot.client).sendWithoutExpect()
}
}
else -> {
logger.debug { "unknown PbGetMsg type ${data.msgHead.msgType}, data=${data.msgBody.msgContent.toUHexString()}" }
}
}
}
override suspend fun PipelineContext.processImpl(data: Structmsg.StructMsg) {
if (isConsumed) return
TODO("Not yet implemented")
}
override suspend fun PipelineContext.processImpl(data: RequestPushStatus) {
if (isConsumed) return
TODO("Not yet implemented")
}
}

View File

@ -19,18 +19,14 @@ import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
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.utils.io.serialization.loadAs
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.read
import net.mamoe.mirai.utils.toUHexString
/**
* Decodes [MsgInfo] and re-fire [MsgType0x210] or [MsgType0x2DC]
*/
internal class MsgInfoDecoder(
private val logger: MiraiLogger,
) : SimpleNoticeProcessor<MsgInfo>(type()) {
internal class MsgInfoDecoder : SimpleNoticeProcessor<MsgInfo>(type()) {
override suspend fun PipelineContext.processImpl(data: MsgInfo) {
markAsConsumed()
when (data.shMsgType.toUShort().toInt()) {
// 528
0x210 -> fire(data.vMsg.loadAs(MsgType0x210.serializer()))
@ -47,10 +43,7 @@ internal class MsgInfoDecoder(
fire(MsgType0x2DC(kind, group, this.readBytes()))
}
}
else -> {
logger.debug { "Unknown kind ${data.shMsgType.toInt()}, data=${data.vMsg.toUHexString()}" }
}
else -> markNotConsumed()
}
}
}
@ -58,5 +51,5 @@ internal class MsgInfoDecoder(
internal class MsgType0x2DC(
val kind: Int, // inner kind, read from vMsg
val group: GroupImpl,
val buf: ByteArray
val buf: ByteArray,
)

View File

@ -1,25 +0,0 @@
/*
* 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.notice.decoders
import net.mamoe.mirai.internal.network.components.PipelineContext
import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
internal class MsgType0x210Decoder : SimpleNoticeProcessor<MsgType0x210>(type()) {
override suspend fun PipelineContext.processImpl(data: MsgType0x210) {
when (data.uSubMsgType) {
0x8AL -> {
}
else -> {
}
}
}
}

View File

@ -24,8 +24,7 @@ import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.MultiPacket
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.QQAndroidClient
import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.noticeProcessorPipeline
import net.mamoe.mirai.internal.network.notice.SystemMessageProcessor
import net.mamoe.mirai.internal.network.components.PipelineContext.Companion.KEY_FROM_SYNC
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
@ -152,14 +151,12 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
QQAndroidClient.MessageSvcSyncData.PbGetMessageSyncId(
uid = msg.msgHead.msgUid,
sequence = msg.msgHead.msgSeq,
time = msg.msgHead.msgTime
)
time = msg.msgHead.msgTime,
),
)
}
.flatMapConcat { msg ->
bot.components.noticeProcessorPipeline
.process(bot, msg, SystemMessageProcessor.KEY_FROM_SYNC to false)
.asFlow()
.map { msg ->
bot.processPacketThroughPipeline(msg, KEY_FROM_SYNC to false)
}
val list: List<Packet> = messages.toList()

View File

@ -13,7 +13,7 @@ import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.noticeProcessorPipeline
import net.mamoe.mirai.internal.network.notice.SystemMessageProcessor
import net.mamoe.mirai.internal.network.components.PipelineContext.Companion.KEY_FROM_SYNC
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgOnlinePush
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.internal.network.toPacket
@ -26,7 +26,7 @@ internal object PbC2CMsgSync : IncomingPacketFactory<Packet>(
return bot.components.noticeProcessorPipeline.process(
bot = bot,
data = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer()).msg,
attributes = SystemMessageProcessor.KEY_FROM_SYNC to true
attributes = KEY_FROM_SYNC to true,
).toPacket()
}
}

View File

@ -446,8 +446,6 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
}
)
internal val ignoredLambda528: Lambda528 = lambda528 { _, _ -> emptySequence() }
internal interface Lambda528 {
suspend operator fun invoke(msg: MsgType0x210, bot: QQAndroidBot, msgInfo: MsgInfo): Sequence<Packet>
}
@ -526,44 +524,6 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
}
},
// Network(1994701021) 16:03:54 : unknown group 528 type 0x0000000000000026, data: 08 01 12 40 0A 06 08 F4 EF BB 8F 04 10 E7 C1 AD B8 02 18 01 22 2C 10 01 1A 1A 18 B4 DC F8 9B 0C 20 E7 C1 AD B8 02 28 06 30 02 A2 01 04 08 93 D6 03 A8 01 08 20 00 28 00 32 08 18 01 20 FE AF AF F5 05 28 00
// VIP 进群提示
0x26L to ignoredLambda528,
// 提示共同好友
0x111L to ignoredLambda528,
// 新好友
0xB3L to lambda528 { bot ->
TODO("removed")
},
0xE2L to lambda528 { _ ->
// TODO: unknown. maybe messages.
// 0A 35 08 00 10 A2 FF 8C F0 03 1A 1B E5 90 8C E6 84 8F E4 BD A0 E7 9A 84 E5 8A A0 E5 A5 BD E5 8F 8B E8 AF B7 E6 B1 82 22 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B 28 01
// vProtobuf.loadAs(Msgtype0x210.serializer())
return@lambda528 emptySequence()
},
0x44L to lambda528 { bot ->
TODO("removed")
},
// bot 在其他客户端被踢或主动退出而同步情况
0xD4L to lambda528 { _ ->
// this.soutv("0x210")
/* @Serializable
data class SubD4(
// ok
val uin: Long
) : ProtoBuf
val uin = vProtobuf.loadAs(SubD4.serializer()).uin
val group = bot.getGroupByUinOrNull(uin) ?: bot.getGroupOrNull(uin)
return@lambda528 if (group != null && bot.groups.delegate.remove(group)) {
group.cancel(CancellationException("Being kicked"))
sequenceOf(BotLeaveEvent.Active(group))
} else emptySequence()*/
//ignore
return@lambda528 emptySequence()
},
//戳一戳信息等
0x122L to lambda528 { bot, msgInfo ->
val body = vProtobuf.loadAs(Submsgtype0x122.Submsgtype0x122.MsgBody.serializer())
@ -618,10 +578,6 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
}
}
},
//好友输入状态
0x115L to lambda528 { bot ->
TODO("removed")
},
// 群相关, ModFriendRemark, DelFriend, ModGroupProfile
0x27L to lambda528 { bot ->
fun ModGroupProfile.transform(bot: QQAndroidBot): Sequence<Packet> {