diff --git a/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt b/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt index 1b6e470df..5da5ab64c 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/NoticeProcessorPipeline.kt @@ -42,6 +42,8 @@ internal typealias ProcessResult = Collection * Centralized processor pipeline for [MessageSvcPbGetMsg] and [OnlinePushPbPushTransMsg] */ internal interface NoticeProcessorPipeline { + val processors: Collection + fun interface DisposableRegistry : Closeable { fun dispose() @@ -193,11 +195,11 @@ private val traceLogging: MiraiLogger by lazy { .withSwitch(systemProp("mirai.network.notice.pipeline.log.full", false)) } -internal open class NoticeProcessorPipelineImpl private constructor() : NoticeProcessorPipeline { +internal open class NoticeProcessorPipelineImpl protected constructor() : NoticeProcessorPipeline { /** * Must be ordered */ - private val processors = ConcurrentLinkedQueue() + override val processors = ConcurrentLinkedQueue() override fun registerProcessor(processor: NoticeProcessor): NoticeProcessorPipeline.DisposableRegistry { processors.add(processor) diff --git a/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt b/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt index 20aaf3900..a5c22ef2e 100644 --- a/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt +++ b/mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt @@ -9,6 +9,8 @@ package net.mamoe.mirai.internal.notice.processors +import kotlinx.serialization.SerializationStrategy +import kotlinx.serialization.serializer import net.mamoe.mirai.Bot import net.mamoe.mirai.Mirai import net.mamoe.mirai.contact.* @@ -22,14 +24,13 @@ import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.info.GroupInfoImpl import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl -import net.mamoe.mirai.internal.network.components.LoggingPacketHandlerAdapter +import net.mamoe.mirai.internal.network.components.* import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.noticeProcessorPipeline -import net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl -import net.mamoe.mirai.internal.network.components.PacketLoggingStrategyImpl -import net.mamoe.mirai.internal.network.components.ProcessResult import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket +import net.mamoe.mirai.internal.utils.io.JceStruct import net.mamoe.mirai.internal.utils.io.ProtocolStruct +import net.mamoe.mirai.internal.utils.io.serialization.tars.Tars import net.mamoe.mirai.utils.TypeSafeMap import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.currentTimeSeconds @@ -47,20 +48,39 @@ internal abstract class AbstractNoticeProcessorTest : AbstractNettyNHTest(), Gro protected object UseTestContext { val EMPTY_BYTE_ARRAY get() = net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY fun String.hexToBytes() = hexToUBytes().toByteArray() + + internal inline fun T.toByteArray( + serializer: SerializationStrategy = serializer(), + ): ByteArray = Tars.UTF_8.encodeToByteArray(serializer, this) + } protected suspend inline fun use( attributes: TypeSafeMap = TypeSafeMap(), + pipeline: NoticeProcessorPipeline = bot.components.noticeProcessorPipeline, block: UseTestContext.() -> ProtocolStruct ): ProcessResult { val handler = LoggingPacketHandlerAdapter(PacketLoggingStrategyImpl(bot), bot.logger) - return bot.components.noticeProcessorPipeline.process(bot, block(UseTestContext), attributes).also { list -> + return pipeline.process(bot, block(UseTestContext), attributes).also { list -> for (packet in list) { handler.handlePacket(IncomingPacket("test", packet)) } } } + protected suspend inline fun use( + attributes: TypeSafeMap = TypeSafeMap(), + crossinline createContext: NoticeProcessorPipelineImpl.(bot: QQAndroidBot, attributes: TypeSafeMap) -> NoticeProcessorPipelineImpl.ContextImpl, + block: UseTestContext.() -> ProtocolStruct + ): ProcessResult = use(attributes, pipeline = object : NoticeProcessorPipelineImpl() { + init { + bot.components.noticeProcessorPipeline.processors.forEach { registerProcessor(it) } + } + + override fun createContext(bot: QQAndroidBot, attributes: TypeSafeMap): NoticePipelineContext = + createContext(this, bot, attributes) + }, block) + fun setBot(id: Long): QQAndroidBot { bot = createBot(BotAccount(id, "a")) return bot diff --git a/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt b/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt new file mode 100644 index 000000000..e5f145f9b --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/notice/processors/BotInvitedJoinTest.kt @@ -0,0 +1,152 @@ +/* + * 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 + */ + +@file:JvmBlockingBridge + +package net.mamoe.mirai.internal.notice.processors + +import net.mamoe.kjbb.JvmBlockingBridge +import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent +import net.mamoe.mirai.event.events.BotJoinGroupEvent +import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.GroupImpl +import net.mamoe.mirai.internal.network.components.NoticeProcessorPipelineImpl +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs + +internal class BotInvitedJoinTest : AbstractNoticeProcessorTest() { + @Test + suspend fun `invited join`() { + suspend fun runTest() = use { + + net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.StructMsg( + version = 1, + msgType = 2, + msgSeq = 1630, + msgTime = 1630, + reqUin = 1230, + msg = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsg( + subType = 1, + msgTitle = "邀请加群", + msgDescribe = "邀请你加入 %group_name%", + actions = mutableListOf( + net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction( + name = "拒绝", + result = "已拒绝", + actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo( + type = 12, + groupCode = 2230203, + ), + detailName = "拒绝", + ), net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction( + name = "同意", + result = "已同意", + actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo( + type = 11, + groupCode = 2230203, + ), + detailName = "同意", + ), net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgAction( + name = "忽略", + result = "已忽略", + actionInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.SystemMsgActionInfo( + type = 14, + groupCode = 2230203, + ), + detailName = "忽略", + ) + ), + groupCode = 2230203, + actionUin = 1230001, + groupMsgType = 2, + groupInviterRole = 1, + groupInfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.GroupInfo( + appPrivilegeFlag = 67698880, + ), + msgInviteExtinfo = net.mamoe.mirai.internal.network.protocol.data.proto.Structmsg.MsgInviteExt( + ), + reqUinNick = "user3", + groupName = "testtest", + actionUinNick = "user1", + groupExtFlag = 1075905600, + actionUinQqNick = "user1", + reqUinGender = 255, + c2cInviteJoinGroupFlag = 1, + ), + ) + } + + setBot(1230003) + + runTest().toList().run { + assertEquals(1, size, toString()) + get(0).run { + assertIs(this) + assertEquals(1230001, invitorId) + assertEquals("user1", invitorNick) + assertEquals(2230203, groupId) + assertEquals("testtest", groupName) + assertEquals(1630, eventId) + } + } + + } + + @Test + suspend fun `invitation accepted`() { + suspend fun runTest() = + use(createContext = { bot, attributes -> + object : NoticeProcessorPipelineImpl.ContextImpl(bot, attributes) { + override suspend fun QQAndroidBot.addNewGroupByUin(groupUin: Long): GroupImpl { + assertEquals(204230203, groupUin) // uin of 2230203 + return bot.addGroup(2230203, 1230002, name = "testtest").apply { + addMember(1230001, permission = MemberPermission.MEMBER) + } + } + } + }) { + net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.Msg( + msgHead = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.MsgHead( + fromUin = 2230203, + toUin = 1230003, + msgType = 33, + msgSeq = 61485, + msgTime = 1630, + msgUid = 1441, + authUin = 1230003, + authNick = "user3", + extGroupKeyInfo = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.ExtGroupKeyInfo( + curMaxSeq = 1631, + curTime = 1630, + ), + ), + contentHead = net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm.ContentHead( + ), + msgBody = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.MsgBody( + richText = net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody.RichText( + ), + msgContent = "00 22 07 BB 01 00 12 C4 B3 03 00 12 C4 B1 00 00 30 34 32 42 39 44 46 43 34 39 45 42 34 30 46 41 42 45 45 32 33 36 34 37 45 46 39 35 31 44 44 42 31 31 32 36 31 31 38 44 43 46 44 32 37 42 30 42 45".hexToBytes(), + ), + ) + } + + setBot(1230003) + + runTest().toList().run { + assertEquals(1, size, toString()) + get(0).run { + assertIs(this) + assertEquals(1230001, invitor.id) + assertEquals(2230203, group.id) + } + } + } +} \ No newline at end of file