From 0d8e481efc8eae342b1a1655386ca00e16fad08f Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 09:15:53 +0800 Subject: [PATCH 01/16] Fix build --- .../src/jvmTest/kotlin/androidPacketTests/serverToClient.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt index e9232e147..5d9797ab9 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt @@ -249,7 +249,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori } else { } - return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, data.toReadPacket()) + return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, data.toReadPacket(), commandName) } @@ -291,7 +291,7 @@ private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP println("找不到包 PacketFactory") PacketLogger.verbose("传递给 PacketFactory 的数据 = ${input.readBytes().toUHexString()}") } - return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, input) + return KnownPacketFactories.IncomingPacket(packetFactory, ssoSequenceId, input, commandName) } private inline fun inline(block: () -> R): R = block() From bfc516f350f446944e51c6be70f60cd7f00f45f9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 09:16:43 +0800 Subject: [PATCH 02/16] senderId, sourceMessage, groupId are now accessible from MessageSource --- .../mirai/qqandroid/message/MessageQQA.kt | 25 +++++++++++--- .../qqandroid/message/MessageSourceFromMsg.kt | 15 +++++--- .../kotlin/net.mamoe.mirai/contact/Group.kt | 34 ++++++++++++++----- .../message/data/MessageSource.kt | 15 ++++++++ 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index e6fe6a870..0dce62349 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -274,12 +274,30 @@ internal class NotOnlineImageFromServer( @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) internal fun MsgComm.Msg.toMessageChain(): MessageChain { - val elems = this.msgBody.richText.elems + val elements = this.msgBody.richText.elems - val message = MessageChain(initialCapacity = elems.size + 1) + val message = MessageChain(initialCapacity = elements.size + 1) message.add(MessageSourceFromMsg(delegate = this)) + elements.joinToMessageChain(message) + return message +} - elems.forEach { +// These two functions are not the same. + +@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) +internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain { + val elements = this.elems!! + + val message = MessageChain(initialCapacity = elements.size + 1) + message.add(MessageSourceFromServer(delegate = this)) + elements.joinToMessageChain(message) + return message +} + + +@UseExperimental(MiraiInternalAPI::class) +internal fun List.joinToMessageChain(message: MessageChain) { + this.forEach { when { it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg))) it.notOnlineImage != null -> message.add(NotOnlineImageFromServer(it.notOnlineImage)) @@ -296,5 +314,4 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain { } } - return message } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt index be9d4521e..c8e77f7d3 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt @@ -10,6 +10,7 @@ package net.mamoe.mirai.qqandroid.message import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.qqandroid.io.serialization.loadAs import net.mamoe.mirai.qqandroid.io.serialization.toByteArray @@ -20,8 +21,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SourceMsg internal inline class MessageSourceFromServer( val delegate: ImMsgBody.SourceMsg ) : MessageSource { - override val messageUid: Long - get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!! + override val messageUid: Long get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!! + override val sourceMessage: MessageChain get() = delegate.toMessageChain() + override val senderId: Long get() = delegate.senderUin + override val groupId: Long get() = Group.calculateGroupCodeByGroupUin(delegate.toUin) override fun toString(): String = "" } @@ -29,12 +32,14 @@ internal inline class MessageSourceFromServer( internal inline class MessageSourceFromMsg( val delegate: MsgComm.Msg ) : MessageSource { - override val messageUid: Long - get() = delegate.msgBody.richText.attr!!.random.toLong() + override val messageUid: Long get() = delegate.msgBody.richText.attr!!.random.toLong() + override val sourceMessage: MessageChain get() = delegate.toMessageChain() + override val senderId: Long get() = delegate.msgHead.fromUin + override val groupId: Long get() = delegate.msgHead.groupInfo!!.groupCode fun toJceData(): ImMsgBody.SourceMsg { - val groupUin = Group.calculateGroupIdByGroupCode(delegate.msgHead.groupInfo!!.groupCode) + val groupUin = Group.calculateGroupUinByGroupCode(delegate.msgHead.groupInfo!!.groupCode) return ImMsgBody.SourceMsg( origSeqs = listOf(delegate.msgHead.msgSeq), diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 9f4ca0679..128b63a19 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -111,21 +111,37 @@ interface Group : Contact, CoroutineScope { /** * by @kar98k */ - fun calculateGroupIdByGroupCode(groupCode: Long): Long { + fun calculateGroupUinByGroupCode(groupCode: Long): Long { var left: Long = groupCode / 1000000L - when { - left <= 10 -> left += 202 - left <= 19 -> left += 480 - 11 - left <= 66 -> left += 2100 - 20 - left <= 156 -> left += 2010 - 67 - left <= 209 -> left += 2147 - 157 - left <= 309 -> left += 4100 - 210 - left <= 499 -> left += 3800 - 310 + when (left) { + in 0..10 -> left += 202 + in 11..19 -> left += 480 - 11 + in 20..66 -> left += 2100 - 20 + in 67..156 -> left += 2010 - 67 + in 157..209 -> left += 2147 - 157 + in 210..309 -> left += 4100 - 210 + in 310..499 -> left += 3800 - 310 } return left * 1000000L + groupCode % 1000000L } + + fun calculateGroupCodeByGroupUin(groupUin: Long): Long { + var left: Long = groupUin / 1000000L + + when (left) { + in 0 + 202..10 + 202 -> left -= 202 + in 11 + 480 - 11..19 + 480 - 11 -> left -= 480 - 11 + in 20 + 2100 - 20..66 + 2100 - 20 -> left -= 2100 - 20 + in 67 + 2010 - 67..156 + 2010 - 67 -> left -= 2010 - 67 + in 157 + 2147 - 157..209 + 2147 - 157 -> left -= 2147 - 157 + in 210 + 4100 - 210..309 + 4100 - 210 -> left -= 4100 - 210 + in 310 + 3800 - 310..499 + 3800 - 310 -> left -= 3800 - 310 + } + + return left * 1000000L + groupUin % 1000000L + } } @MiraiExperimentalAPI diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt index 535af6681..c133938a8 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -23,6 +23,21 @@ interface MessageSource : Message { */ val messageUid: Long + /** + * 发送人号码 + */ + val senderId: Long + + /** + * 群号码 + */ + val groupId: Long + + /** + * 原消息内容 + */ + val sourceMessage: MessageChain + /** * 固定返回空字符串 ("") */ From 7891ffc136d2c9f07f8bfe5526085602477273f4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 11:56:42 +0800 Subject: [PATCH 03/16] Make `interface Event` the base type of a event, remove `interface Subscribable` --- .../mirai/qqandroid/message/MessageQQA.kt | 2 +- .../network/QQAndroidBotNetworkHandler.kt | 9 +- .../network/protocol/packet/PacketFactory.kt | 7 +- .../net.mamoe.mirai/data/EventPacket.kt | 6 +- .../kotlin/net.mamoe.mirai/data/Packet.kt | 1 + .../net.mamoe.mirai/event/Subscribable.kt | 39 ++---- .../net.mamoe.mirai/event/Subscribers.kt | 28 ++--- .../net.mamoe.mirai/event/events/BotEvents.kt | 112 ++++++++++++------ .../event/events/ForceOfflineEvent.kt | 13 -- .../{data => event/events}/MuteEvent.kt | 3 +- .../event/internal/InternalEventListeners.kt | 24 ++-- .../net.mamoe.mirai/message/data/Message.kt | 6 +- .../net/mamoe/mirai/event/SubscribersJvm.kt | 2 +- .../net/mamoe/mirai/event/EventTests.kt | 5 +- .../src/main/kotlin/demo/gentleman/Main.kt | 6 +- 15 files changed, 135 insertions(+), 128 deletions(-) delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ForceOfflineEvent.kt rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/{data => event/events}/MuteEvent.kt (96%) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index 0dce62349..d14f2d942 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -295,7 +295,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain { } -@UseExperimental(MiraiInternalAPI::class) +@UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class) internal fun List.joinToMessageChain(message: MessageChain) { this.forEach { when { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 7126e9ebb..abbd8c892 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -21,10 +21,13 @@ import kotlinx.io.core.use import net.mamoe.mirai.contact.ContactList import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.event.events.ForceOfflineEvent import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.* +import net.mamoe.mirai.event.BroadcastControllable +import net.mamoe.mirai.event.Event +import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.events.ForceOfflineEvent +import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.qqandroid.GroupImpl import net.mamoe.mirai.qqandroid.MemberImpl @@ -350,7 +353,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler // broadcast - if (packet is Subscribable) { + if (packet is Event) { if (packet is BroadcastControllable) { if (packet.shouldBroadcast) packet.broadcast() } else { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index 7af45776b..7906b0adb 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -12,7 +12,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet import kotlinx.io.core.* import kotlinx.io.pool.useInstance import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.Subscribable +import net.mamoe.mirai.event.Event import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore @@ -20,7 +20,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList -import net.mamoe.mirai.qqandroid.network.protocol.packet.login.* import net.mamoe.mirai.qqandroid.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc @@ -59,7 +58,7 @@ internal abstract class OutgoingPacketFactory( final override val receivingCommandName: String get() = commandName /** - * **解码**服务器的回复数据包. 返回的包若是 [Subscribable], 则会 broadcast. + * **解码**服务器的回复数据包. 返回的包若是 [Event], 则会 broadcast. */ abstract suspend fun ByteReadPacket.decode(bot: QQAndroidBot): TPacket @@ -85,7 +84,7 @@ internal abstract class IncomingPacketFactory( val responseCommandName: String = "" ) : PacketFactory() { /** - * **解码**服务器的回复数据包. 返回的包若是 [Subscribable], 则会 broadcast. + * **解码**服务器的回复数据包. 返回的包若是 [Event], 则会 broadcast. */ abstract suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): TPacket diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt index e5f707aa3..630db03e1 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt @@ -9,11 +9,11 @@ package net.mamoe.mirai.data -import net.mamoe.mirai.event.Subscribable +import net.mamoe.mirai.event.Event /** * 事件包. 可被监听. * - * @see Subscribable + * @see Event */ -interface EventPacket : Subscribable, Packet \ No newline at end of file +interface EventPacket : Event, Packet \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/Packet.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/Packet.kt index 32ebf3f08..958118257 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/Packet.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/Packet.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.data /** * 从服务器收到的包解析之后的结构化数据. + * 它是一个数据包工厂的处理的返回值. */ interface Packet { /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt index 3cd8e11dc..20db2c2c9 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt @@ -17,61 +17,44 @@ import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.utils.MiraiInternalAPI /** - * 可被监听的. + * 可被监听的类, 可以是任何 class 或 object. * - * 可以是任何 class 或 object. + * 若监听这个类, 监听器将会接收所有事件的广播. * * @see subscribeAlways * @see subscribeWhile * * @see subscribeMessages - */ -interface Subscribable - -/** - * 所有事件的基类. - * 若监听这个类, 监听器将会接收所有事件的广播. * * @see [broadcast] 广播事件 * @see [subscribe] 监听事件 */ -abstract class Event : Subscribable { +interface Event +/** + * 可被取消的事件 + */ +abstract class CancellableEvent : Event { /** - * 事件是否已取消. 事件需实现 [Cancellable] 才可以被取消, 否则这个字段为常量值 false + * 事件是否已取消. */ val cancelled: Boolean get() = _cancelled private var _cancelled: Boolean = false - get() = field.takeIf { this is Cancellable } ?: false - private set(value) = - if (this is Cancellable) field = value - else throw UnsupportedOperationException() /** - * 取消事件. 事件需实现 [Cancellable] 才可以被取消 - * - * @throws UnsupportedOperationException 如果事件没有实现 [Cancellable] + * 取消事件. */ fun cancel() { _cancelled = true } } -/** - * 实现这个接口的事件([Event])可以被取消. 在广播中取消不会影响广播过程. - */ -interface Cancellable : Subscribable { - val cancelled: Boolean - - fun cancel() -} - /** * 广播一个事件的唯一途径. */ @UseExperimental(MiraiInternalAPI::class) -suspend fun E.broadcast(): E = apply { +suspend fun E.broadcast(): E = apply { if (this is BotEvent && !(this.bot as BotImpl<*>).onEvent(this)) { return@apply } @@ -81,7 +64,7 @@ suspend fun E.broadcast(): E = apply { /** * 可控制是否需要广播这个事件包 */ -interface BroadcastControllable : Subscribable { +interface BroadcastControllable : Event { val shouldBroadcast: Boolean get() = true } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt index 9395d7fd4..0b3437afc 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt @@ -39,7 +39,7 @@ enum class ListeningStatus { * 事件监听器. * 由 [subscribe] 等方法返回. */ -interface Listener : CompletableJob { +interface Listener : CompletableJob { suspend fun onEvent(event: E): ListeningStatus } @@ -47,7 +47,7 @@ interface Listener : CompletableJob { /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Subscribable.broadcast] 时, [handler] 都会被执行. + * 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行. * * 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听. * 或 [Listener] complete 时结束. @@ -57,7 +57,7 @@ interface Listener : CompletableJob { * 例如: * ```kotlin * runBlocking { // this: CoroutineScope - * subscribe { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob + * subscribe { /* 一些处理 */ } // 返回 Listener, 即 CompletableJob * } * foo() * ``` @@ -66,7 +66,7 @@ interface Listener : CompletableJob { * * 要创建一个全局都存在的监听, 即守护协程, 请在 [GlobalScope] 下调用本函数: * ```kotlin - * GlobalScope.subscribe { /* 一些处理 */ } + * GlobalScope.subscribe { /* 一些处理 */ } * ``` * * @@ -75,52 +75,52 @@ interface Listener : CompletableJob { * bot.subscribe { /* 一些处理 */ } * ``` */ -inline fun CoroutineScope.subscribe(crossinline handler: suspend E.(E) -> ListeningStatus): Listener = +inline fun CoroutineScope.subscribe(crossinline handler: suspend E.(E) -> ListeningStatus): Listener = E::class.subscribeInternal(Handler { it.handler(it) }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Subscribable.broadcast] 时, [listener] 都会被执行. + * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行. * * 仅当 [Listener] complete 时结束. * * @see subscribe 获取更多说明 */ -inline fun CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener = +inline fun CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener = E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.LISTENING }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 仅在第一次 [事件广播][Subscribable.broadcast] 时, [listener] 会被执行. + * 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行. * * 在这之前, 可通过 [Listener.complete] 来停止监听. * * @see subscribe 获取更多说明 */ -inline fun CoroutineScope.subscribeOnce(crossinline listener: suspend E.(E) -> Unit): Listener = +inline fun CoroutineScope.subscribeOnce(crossinline listener: suspend E.(E) -> Unit): Listener = E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.STOPPED }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Subscribable.broadcast] 时, [listener] 都会被执行, 直到 [listener] 的返回值 [equals] 于 [valueIfStop] + * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行, 直到 [listener] 的返回值 [equals] 于 [valueIfStop] * * 可在任意时刻通过 [Listener.complete] 来停止监听. * * @see subscribe 获取更多说明 */ -inline fun CoroutineScope.subscribeUntil(valueIfStop: T, crossinline listener: suspend E.(E) -> T): Listener = +inline fun CoroutineScope.subscribeUntil(valueIfStop: T, crossinline listener: suspend E.(E) -> T): Listener = E::class.subscribeInternal(Handler { if (it.listener(it) == valueIfStop) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Subscribable.broadcast] 时, [listener] 都会被执行, + * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行, * 如果 [listener] 的返回值 [equals] 于 [valueIfContinue], 则继续监听, 否则停止 * * 可在任意时刻通过 [Listener.complete] 来停止监听. * * @see subscribe 获取更多说明 */ -inline fun CoroutineScope.subscribeWhile(valueIfContinue: T, crossinline listener: suspend E.(E) -> T): Listener = +inline fun CoroutineScope.subscribeWhile(valueIfContinue: T, crossinline listener: suspend E.(E) -> T): Listener = E::class.subscribeInternal(Handler { if (it.listener(it) != valueIfContinue) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) // endregion @@ -146,7 +146,7 @@ inline fun CoroutineScope.subscribeWhile(valueIfCo */ @ListenersBuilderDsl @Suppress("MemberVisibilityCanBePrivate", "unused") -inline class ListenerBuilder( +inline class ListenerBuilder( @PublishedApi internal inline val handlerConsumer: CoroutineCoroutineScope.(Listener) -> Unit ) { fun CoroutineCoroutineScope.handler(listener: suspend E.(E) -> ListeningStatus) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 807373b3c..be65b8625 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -13,86 +13,120 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.Event -import net.mamoe.mirai.utils.WeakRef -import kotlin.properties.Delegates - -abstract class BotEvent : Event { - private lateinit var _bot: Bot - open val bot: Bot get() = _bot - - constructor(bot: Bot) : super() { - this._bot = bot - } - - constructor() : super() +/** + * 有关一个 [Bot] 的事件 + */ +interface BotEvent : Event { + val bot: Bot } -class BotLoginSucceedEvent(bot: Bot) : BotEvent(bot) +/** + * [Bot] 登录完成, 好友列表, 群组列表初始化完成 + */ +data class BotLoginSucceedEvent(override val bot: Bot) : BotEvent -class BotOfflineEvent(bot: Bot) : BotEvent(bot) +/** + * [Bot] 离线. + */ +data class BotOfflineEvent(override val bot: Bot) : BotEvent -class BotReadyEvent(bot: Bot) : BotEvent(bot) +/** + * 被挤下线 + */ +data class ForceOfflineEvent( + override val bot: Bot, + val title: String, + val tips: String +) : BotEvent, Packet -interface GroupEvent { +/** + * 有关群的事件 + */ +interface GroupEvent : BotEvent { val group: Group + override val bot: Bot + get() = group.bot } -class AddGroupEvent(bot: Bot, override val group: Group) : BotEvent(bot), GroupEvent +data class AddGroupEvent(override val group: Group) : BotEvent, GroupEvent -class RemoveGroupEvent(bot: Bot, override val group: Group) : BotEvent(bot), GroupEvent +data class RemoveGroupEvent(override val group: Group) : BotEvent, GroupEvent -class BotGroupPermissionChangeEvent( - bot: Bot, +data class BotGroupPermissionChangeEvent( override val group: Group, val origin: MemberPermission, val new: MemberPermission -) : BotEvent(bot), GroupEvent +) : BotEvent, GroupEvent + interface GroupSettingChangeEvent : GroupEvent { + val operator: Member val origin: T val new: T + + override val group: Group + get() = operator.group } -class GroupNameChangeEvent( - bot: Bot, - override val group: Group, +data class GroupNameChangeEvent( + override val operator: Member, override val origin: String, override val new: String -) : BotEvent(bot), GroupSettingChangeEvent +) : BotEvent, GroupSettingChangeEvent -class GroupMuteAllEvent( - bot: Bot, - override val group: Group, +/** + * 群 "全员禁言" 功能开启 + */ +data class GroupMuteAllEvent( + override val operator: Member, override val origin: Boolean, override val new: Boolean -) : BotEvent(bot), GroupSettingChangeEvent +) : BotEvent, GroupSettingChangeEvent -class GroupConfessTalkEvent( - bot: Bot, - override val group: Group, +data class GroupConfessTalkEvent( + override val operator: Member, override val origin: Boolean, override val new: Boolean -) : BotEvent(bot), GroupSettingChangeEvent +) : BotEvent, GroupSettingChangeEvent + +/** + * 有关群成员的事件 + */ interface GroupMemberEvent : GroupEvent { val member: Member override val group: Group get() = member.group } -class MemberJoinEvent(bot: Bot, override val member: Member) : BotEvent(bot), GroupMemberEvent +/** + * 成员加入群的事件 + */ +data class MemberJoinEvent(override val member: Member) : BotEvent, GroupMemberEvent -class MemberLeftEvent(bot: Bot, override val member: Member) : BotEvent(bot), GroupMemberEvent +/** + * 成员离开群的事件 + */ +sealed class MemberLeftEvent : BotEvent, GroupMemberEvent { + /** + * 成员被踢出群 + */ + data class Kick(override val member: Member, val operator: Member) : MemberLeftEvent() -class MemberMuteEvent(bot: Bot, override val member: Member) : BotEvent(bot), GroupMemberEvent + /** + * 成员主动离开 + */ + data class Quit(override val member: Member) : MemberLeftEvent() +} -class MemberPermissionChangeEvent( - bot: Bot, +data class MemberPermissionChangeEvent( + override val bot: Bot, override val member: Member, val origin: MemberPermission, val new: MemberPermission -) : BotEvent(bot), GroupMemberEvent +) : BotEvent, GroupMemberEvent diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ForceOfflineEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ForceOfflineEvent.kt deleted file mode 100644 index 0d1f6f7cf..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ForceOfflineEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package net.mamoe.mirai.event.events - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.data.Packet - -/** - * 被挤下线 - */ -data class ForceOfflineEvent( - override val bot: Bot, - val title: String, - val tips: String -) : BotEvent(), Packet \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MuteEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt similarity index 96% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MuteEvent.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt index ef4089007..a17823f38 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MuteEvent.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt @@ -7,10 +7,11 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.data +package net.mamoe.mirai.event.events import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.data.EventPacket // region mute diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt index 708eec787..366ce9d02 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt @@ -10,9 +10,9 @@ package net.mamoe.mirai.event.internal import kotlinx.coroutines.* +import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Listener import net.mamoe.mirai.event.ListeningStatus -import net.mamoe.mirai.event.Subscribable import net.mamoe.mirai.utils.LockFreeLinkedList import net.mamoe.mirai.utils.MiraiDebugAPI import net.mamoe.mirai.utils.MiraiLogger @@ -29,14 +29,14 @@ import kotlin.reflect.KClass var EventDisabled = false @PublishedApi -internal fun , E : Subscribable> KClass.subscribeInternal(listener: L): L { +internal fun , E : Event> KClass.subscribeInternal(listener: L): L { this.listeners().addLast(listener) return listener } @PublishedApi @Suppress("FunctionName") -internal fun CoroutineScope.Handler(handler: suspend (E) -> ListeningStatus): Handler { +internal fun CoroutineScope.Handler(handler: suspend (E) -> ListeningStatus): Handler { return Handler(coroutineContext[Job], coroutineContext, handler) } @@ -45,7 +45,7 @@ private inline fun inline(block: () -> Unit) = block() * 事件处理器. */ @PublishedApi -internal class Handler +internal class Handler @PublishedApi internal constructor(parentJob: Job?, private val subscriberContext: CoroutineContext, @JvmField val handler: suspend (E) -> ListeningStatus) : Listener, CompletableJob by Job(parentJob) { @@ -79,21 +79,21 @@ internal class Handler /** * 这个事件类的监听器 list */ -internal fun KClass.listeners(): EventListeners = EventListenerManager.get(this) +internal fun KClass.listeners(): EventListeners = EventListenerManager.get(this) -internal class EventListeners : LockFreeLinkedList>() +internal class EventListeners : LockFreeLinkedList>() /** * 管理每个事件 class 的 [EventListeners]. * [EventListeners] 是 lazy 的: 它们只会在被需要的时候才创建和存储. */ internal object EventListenerManager { - private data class Registry(val clazz: KClass, val listeners: EventListeners) + private data class Registry(val clazz: KClass, val listeners: EventListeners) private val registries = LockFreeLinkedList>() @Suppress("UNCHECKED_CAST") - internal fun get(clazz: KClass): EventListeners { + internal fun get(clazz: KClass): EventListeners { return registries.filteringGetOrAdd({ it.clazz == clazz }) { Registry( clazz, @@ -105,7 +105,7 @@ internal object EventListenerManager { // inline: NO extra Continuation @Suppress("UNCHECKED_CAST") -internal suspend inline fun Subscribable.broadcastInternal() { +internal suspend inline fun Event.broadcastInternal() { if (EventDisabled) return callAndRemoveIfRequired(this::class.listeners()) @@ -113,18 +113,18 @@ internal suspend inline fun Subscribable.broadcastInternal() { var supertypes = this::class.supertypes while (true) { val superSubscribableType = supertypes.firstOrNull { - it.classifier as? KClass != null + it.classifier as? KClass != null } superSubscribableType?.let { - callAndRemoveIfRequired((it.classifier as KClass).listeners()) + callAndRemoveIfRequired((it.classifier as KClass).listeners()) } supertypes = (superSubscribableType?.classifier as? KClass<*>)?.supertypes ?: return } } -private suspend inline fun E.callAndRemoveIfRequired(listeners: EventListeners) { +private suspend inline fun E.callAndRemoveIfRequired(listeners: EventListeners) { // atomic foreach listeners.forEach { if (it.onEvent(this) == ListeningStatus.STOPPED) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index 799c190c5..274020408 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -59,14 +59,14 @@ interface Message { infix fun eq(other: Message): Boolean = this == other /** - * 将 [stringValue] 与 [other] 比较 + * 将 [toString] 与 [other] 比较 */ infix fun eq(other: String): Boolean = this.toString() == other operator fun contains(sub: String): Boolean = false /** - * 把 [this] 连接到 [tail] 的头部. 类似于字符串相加. + * 把 `this` 连接到 [tail] 的头部. 类似于字符串相加. * * 例: * ```kotlin @@ -92,7 +92,7 @@ interface Message { override fun toString(): String operator fun plus(another: Message): MessageChain = this.followedBy(another) - operator fun plus(another: String): MessageChain = this.followedBy(another.toString().toMessage()) + operator fun plus(another: String): MessageChain = this.followedBy(another.toMessage()) // `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)` operator fun plus(another: CharSequence): MessageChain = this.followedBy(another.toString().toMessage()) } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt index c1a1fe888..9282eec6b 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt @@ -17,6 +17,6 @@ package net.mamoe.mirai.event object Events { /* @JvmStatic - fun subscribe(type: Class, handler: suspend (E) -> ListeningStatus) = + fun subscribe(type: Class, handler: suspend (E) -> ListeningStatus) = runBlocking { type.kotlin.subscribe(handler) }*/ } diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt index 172cbac9c..53d456c2d 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt @@ -12,12 +12,11 @@ package net.mamoe.mirai.event import kotlinx.coroutines.CompletableJob import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.runBlocking -import net.mamoe.mirai.test.shouldBeEqualTo import kotlin.system.exitProcess import kotlin.test.Test -class TestEvent : Subscribable { +class TestEvent : Event { var triggered = false } @@ -46,7 +45,7 @@ class EventTests { } - open class ParentEvent : Subscribable { + open class ParentEvent : Event { var triggered = false } diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt index 3bc7f7ff5..e1feaa484 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt @@ -20,7 +20,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.event.Subscribable +import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.events.ReceiveFriendAddRequestEvent import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeGroupMessages @@ -48,8 +48,8 @@ suspend fun main() { // override config here. }.alsoLogin() - // 任何可以监听的对象都继承 Subscribable, 因此这个订阅会订阅全部的事件. - GlobalScope.subscribeAlways { + // 任何可以监听的对象都继承 Event, 因此这个订阅会订阅全部的事件. + GlobalScope.subscribeAlways { //bot.logger.verbose("收到了一个事件: $this") } From 001ad975b9191caa0c804482fd9815cd12d91ef0 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 12:02:19 +0800 Subject: [PATCH 04/16] Make `CancellableEvent` an interface, introduce `AbstractCancellableEvent` --- .../net.mamoe.mirai/event/Subscribable.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt index 20db2c2c9..14d5b1106 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt @@ -34,18 +34,33 @@ interface Event /** * 可被取消的事件 */ -abstract class CancellableEvent : Event { +interface CancellableEvent { /** * 事件是否已取消. */ - val cancelled: Boolean get() = _cancelled + val isCancelled: Boolean + + /** + * 取消这个事件. + */ + fun cancel() +} + +/** + * 可被取消的事件的实现 + */ +abstract class AbstractCancellableEvent : Event, CancellableEvent { + /** + * 事件是否已取消. + */ + override val isCancelled: Boolean get() = _cancelled private var _cancelled: Boolean = false /** * 取消事件. */ - fun cancel() { + override fun cancel() { _cancelled = true } } From a322ce735b878b542c184ad2f0a03eea36fd0c4e Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 12:30:49 +0800 Subject: [PATCH 05/16] Make `CancellableEvent` an interface, introduce `AbstractCancellableEvent` --- .../mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt | 4 ++-- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 9 +++------ .../kotlin/net.mamoe.mirai/message/MessagePacket.kt | 2 +- .../jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt | 1 + 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt index df9cbb8f2..831a1dc2b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/event/PacketReceivedEvent.kt @@ -10,10 +10,10 @@ package net.mamoe.mirai.qqandroid.event import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.Cancellable +import net.mamoe.mirai.event.AbstractCancellableEvent import net.mamoe.mirai.event.Event /** * 接收到数据包 */ -class PacketReceivedEvent(val packet: Packet) : Event(), Cancellable \ No newline at end of file +data class PacketReceivedEvent(val packet: Packet) : Event, AbstractCancellableEvent() \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index abbd8c892..8b7a10104 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -23,11 +23,8 @@ import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.BroadcastControllable -import net.mamoe.mirai.event.Event -import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.* import net.mamoe.mirai.event.events.ForceOfflineEvent -import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.qqandroid.GroupImpl import net.mamoe.mirai.qqandroid.MemberImpl @@ -347,7 +344,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // check top-level cancelling - if (PacketReceivedEvent(packet).broadcast().cancelled) { + if (PacketReceivedEvent(packet).broadcast().isCancelled) { return } @@ -360,7 +357,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler packet.broadcast() } - if (packet is Cancellable && packet.cancelled) return + if (packet is CancellableEvent && packet.isCancelled) return } bot.logger.info("Received packet: ${packet.toString().replace("\n", """\n""").replace("\r", "")}") diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt index fa0d0f09a..4aeb9c04c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt @@ -37,7 +37,7 @@ expect abstract class MessagePacket(bot: Bot) */ // Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构 @Suppress("NOTHING_TO_INLINE") @MiraiInternalAPI -abstract class MessagePacketBase(_bot: Bot) : EventPacket, BotEvent() { +abstract class MessagePacketBase(_bot: Bot) : EventPacket, BotEvent { /** * 接受到这条消息的 */ diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt index 53d456c2d..b8b5a1ba5 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.event import kotlinx.coroutines.CompletableJob import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.test.shouldBeEqualTo import kotlin.system.exitProcess import kotlin.test.Test From 4d77951ae49a83987b5e9954fbb886c464bc956b Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 13:14:40 +0800 Subject: [PATCH 06/16] Redesign event structure --- .../network/QQAndroidBotNetworkHandler.kt | 4 +- .../packet/chat/receive/MessageSvc.kt | 8 +- .../event/events/ActiveEvents.kt | 53 ++++++ .../net.mamoe.mirai/event/events/BotEvents.kt | 132 --------------- .../event/events/FriendStatusChanged.kt | 19 --- .../net.mamoe.mirai/event/events/MuteEvent.kt | 84 ---------- .../event/events/PassiveEvents.kt | 155 ++++++++++++++++++ .../events/ReceiveFriendAddRequestEvent.kt | 37 ----- .../net.mamoe.mirai/event/events/types.kt | 63 +++++++ .../src/main/kotlin/demo/gentleman/Main.kt | 6 +- 10 files changed, 280 insertions(+), 281 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendStatusChanged.kt delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ReceiveFriendAddRequestEvent.kt create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 8b7a10104..6b4b55a91 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -24,7 +24,7 @@ import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.* -import net.mamoe.mirai.event.events.ForceOfflineEvent +import net.mamoe.mirai.event.events.BotForceOfflineEvent import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.qqandroid.GroupImpl import net.mamoe.mirai.qqandroid.MemberImpl @@ -119,7 +119,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) override suspend fun init(): Unit = coroutineScope { - this@QQAndroidBotNetworkHandler.subscribeAlways { + this@QQAndroidBotNetworkHandler.subscribeAlways { if (this@QQAndroidBotNetworkHandler.bot == this.bot) { this.bot.logger.error("被挤下线") close() diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 5e0011320..19bc6b821 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -11,10 +11,10 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.discardExact -import net.mamoe.mirai.event.events.ForceOfflineEvent import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.BroadcastControllable +import net.mamoe.mirai.event.events.BotForceOfflineEvent import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.qqandroid.QQAndroidBot @@ -178,10 +178,10 @@ internal class MessageSvc { /** * 被挤下线 */ - internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ForceOfflineEvent { + internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotForceOfflineEvent { val struct = this.decodeUniPacket(RequestPushForceOffline.serializer()) - return ForceOfflineEvent(bot, title = struct.title ?: "", tips = struct.tips ?: "") + return BotForceOfflineEvent(bot, title = struct.title ?: "", tips = struct.tips ?: "") } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt new file mode 100644 index 000000000..5d4549a14 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2020 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.event.events + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.QQ + + +/** + * [Bot] 登录完成, 好友列表, 群组列表初始化完成 + */ +data class BotLoginSucceedEvent(override val bot: Bot) : BotActiveEvent() + +/** + * [Bot] 主动离线. + */ +data class BotOfflineEvent(override val bot: Bot) : BotActiveEvent() + +// region 好友 + +/** + * [Bot] 删除一个好友 + */ +class BotRemoveFriendEvent(override val friend: QQ) : FriendEvent, BotActiveEvent() + +// endregion + +// region 群 + +/** + * 机器人踢出某个群员 + */ +class BotKickMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() + +/** + * 机器人禁言某个群成员 + */ +class BotMuteMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() + +/** + * 机器人取消禁言某个群成员 + */ +class BotUnmuteMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() + +// endregion \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt deleted file mode 100644 index be65b8625..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.Event - -/** - * 有关一个 [Bot] 的事件 - */ -interface BotEvent : Event { - val bot: Bot -} - -/** - * [Bot] 登录完成, 好友列表, 群组列表初始化完成 - */ -data class BotLoginSucceedEvent(override val bot: Bot) : BotEvent - -/** - * [Bot] 离线. - */ -data class BotOfflineEvent(override val bot: Bot) : BotEvent - -/** - * 被挤下线 - */ -data class ForceOfflineEvent( - override val bot: Bot, - val title: String, - val tips: String -) : BotEvent, Packet - -/** - * 有关群的事件 - */ -interface GroupEvent : BotEvent { - val group: Group - override val bot: Bot - get() = group.bot -} - -data class AddGroupEvent(override val group: Group) : BotEvent, GroupEvent - -data class RemoveGroupEvent(override val group: Group) : BotEvent, GroupEvent - -data class BotGroupPermissionChangeEvent( - override val group: Group, - val origin: MemberPermission, - val new: MemberPermission -) : BotEvent, GroupEvent - - -interface GroupSettingChangeEvent : GroupEvent { - val operator: Member - val origin: T - val new: T - - override val group: Group - get() = operator.group -} - -data class GroupNameChangeEvent( - override val operator: Member, - override val origin: String, - override val new: String -) : BotEvent, GroupSettingChangeEvent - -/** - * 群 "全员禁言" 功能开启 - */ -data class GroupMuteAllEvent( - override val operator: Member, - override val origin: Boolean, - override val new: Boolean -) : BotEvent, GroupSettingChangeEvent - -data class GroupConfessTalkEvent( - override val operator: Member, - override val origin: Boolean, - override val new: Boolean -) : BotEvent, GroupSettingChangeEvent - - -/** - * 有关群成员的事件 - */ -interface GroupMemberEvent : GroupEvent { - val member: Member - override val group: Group - get() = member.group -} - -/** - * 成员加入群的事件 - */ -data class MemberJoinEvent(override val member: Member) : BotEvent, GroupMemberEvent - -/** - * 成员离开群的事件 - */ -sealed class MemberLeftEvent : BotEvent, GroupMemberEvent { - /** - * 成员被踢出群 - */ - data class Kick(override val member: Member, val operator: Member) : MemberLeftEvent() - - /** - * 成员主动离开 - */ - data class Quit(override val member: Member) : MemberLeftEvent() -} - -data class MemberPermissionChangeEvent( - override val bot: Bot, - override val member: Member, - val origin: MemberPermission, - val new: MemberPermission -) : BotEvent, GroupMemberEvent - - diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendStatusChanged.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendStatusChanged.kt deleted file mode 100644 index f0c9b577a..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/FriendStatusChanged.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.data.EventPacket -import net.mamoe.mirai.data.OnlineStatus - -data class FriendStatusChanged( - val qq: QQ, - val status: OnlineStatus -) : EventPacket diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt deleted file mode 100644 index a17823f38..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/MuteEvent.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.data.EventPacket - - -// region mute -/** - * 某群成员被禁言事件 - */ -@Suppress("unused", "MemberVisibilityCanBePrivate") -class MemberMuteEvent( - val member: Member, - override val durationSeconds: Int, - override val operator: Member -) : MuteEvent() { - override val group: Group get() = operator.group - override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s" -} - -/** - * 机器人被禁言事件 - */ -class BeingMutedEvent( - override val durationSeconds: Int, - override val operator: Member -) : MuteEvent() { - override val group: Group get() = operator.group - override fun toString(): String = "BeingMutedEvent(group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s" -} - -sealed class MuteEvent : EventOfMute() { - abstract override val operator: Member - abstract override val group: Group - abstract val durationSeconds: Int -} -// endregion - -// region unmute -/** - * 某群成员被解除禁言事件 - */ -@Suppress("unused") -class MemberUnmuteEvent( - val member: Member, - override val operator: Member -) : UnmuteEvent() { - override val group: Group get() = operator.group - override fun toString(): String = "MemberUnmuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}" -} - -/** - * 机器人被解除禁言事件 - */ -@Suppress("SpellCheckingInspection") -class BeingUnmutedEvent( - override val operator: Member -) : UnmuteEvent() { - override val group: Group get() = operator.group - override fun toString(): String = "BeingUnmutedEvent(group=${group.id}, operator=${operator.id}" -} - -sealed class UnmuteEvent : EventOfMute() { - abstract override val operator: Member - abstract override val group: Group -} - -// endregion - -abstract class EventOfMute : EventPacket { - abstract val operator: Member - abstract val group: Group -} - diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt new file mode 100644 index 000000000..4582c25a8 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt @@ -0,0 +1,155 @@ +/* + * Copyright 2020 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.event.events + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.data.Packet + +// region Bot 在线状态 + +/** + * 被挤下线 + */ +data class BotForceOfflineEvent( + override val bot: Bot, + val title: String, + val tips: String +) : BotPassiveEvent, Packet +// endregion + +// region 群 + +/** + * Bot 在群里的权限被改变. 操作人一定是群主 + */ +data class BotGroupPermissionChangeEvent( + override val group: Group, + val origin: MemberPermission, + val new: MemberPermission +) : BotPassiveEvent, GroupEvent + +// region 群设置 + +/** + * 群设置改变 + */ +interface GroupSettingChangeEvent : GroupEvent, BotPassiveEvent { + val operator: Member + val origin: T + val new: T + + override val group: Group + get() = operator.group +} + +/** + * 群名改变 + */ +data class GroupNameChangeEvent( + override val operator: Member, + override val origin: String, + override val new: String +) : GroupSettingChangeEvent, BotPassiveEvent + +/** + * 群 "全员禁言" 功能状态改变 + */ +data class GroupMuteAllEvent( + override val operator: Member, + override val origin: Boolean, + override val new: Boolean +) : GroupSettingChangeEvent, BotPassiveEvent + +/** + * 群 "坦白说" 功能状态改变 + */ +data class GroupConfessTalkEvent( + override val operator: Member, + override val origin: Boolean, + override val new: Boolean +) : GroupSettingChangeEvent, BotPassiveEvent + +// endregion + + +// region 群成员 + +// region 成员变更 + +/** + * 成员加入群的事件 + */ +data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent + +/** + * 成员离开群的事件 + */ +sealed class MemberLeftEvent : GroupMemberEvent, BotPassiveEvent { + /** + * 成员被踢出群. 成员不可能是机器人自己. + * + * @see BotKickMemberEvent 机器人踢出一个人 + */ + data class Kick(override val member: Member, val operator: Member) : MemberLeftEvent() + + /** + * 成员主动离开 + */ + data class Quit(override val member: Member) : MemberLeftEvent() +} + +// endregion + + +// region 成员权限 + +/** + * 成员权限改变的事件. 成员不可能是机器人自己. + */ +data class MemberPermissionChangeEvent( + override val bot: Bot, + override val member: Member, + val origin: MemberPermission, + val new: MemberPermission +) : GroupMemberEvent, BotPassiveEvent + +// endregion + + +// region 禁言 + +/** + * 群成员被禁言事件. 操作人和被禁言的成员都不可能是机器人本人 + * + * @see BotMuteMemberEvent 机器人禁言一个人 + */ +data class MemberMuteEvent( + override val member: Member, + val operator: Member, + val durationSeconds: Int +) : GroupMemberEvent, BotPassiveEvent { + override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s" +} + +/** + * 群成员被取消禁言事件. 操作人和被禁言的成员都不可能是机器人本人 + * + * @see BotUnmuteMemberEvent 机器人取消禁言某个人 + */ +data class MemberUnmuteEvent(override val member: Member, val operator: Member) : GroupMemberEvent, BotPassiveEvent + +// endregion + +// endregion + +// endregion \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ReceiveFriendAddRequestEvent.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ReceiveFriendAddRequestEvent.kt deleted file mode 100644 index cd4cf311f..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ReceiveFriendAddRequestEvent.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.data.EventPacket -import net.mamoe.mirai.utils.getValue -import net.mamoe.mirai.utils.unsafeWeakRef -import kotlin.jvm.JvmOverloads - -/** - * 陌生人请求添加机器人账号为好友 - */ -class ReceiveFriendAddRequestEvent( - _qq: QQ, - /** - * 验证消息 - */ - val message: String -) : EventPacket { - val qq: QQ by _qq.unsafeWeakRef() - - /** - * 同意这个请求 - * - * @param remark 备注名, 不设置则需为 `null` - */ - @JvmOverloads - suspend fun approve(remark: String? = null): Unit = qq.bot.approveFriendAddRequest(qq.id, remark) -} diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt new file mode 100644 index 000000000..e26846474 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2020 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.event.events + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.event.AbstractCancellableEvent +import net.mamoe.mirai.event.Event + +/** + * 有关一个 [Bot] 的事件 + */ +interface BotEvent : Event { + val bot: Bot +} + +/** + * [Bot] 被动接收的事件. 这些事件可能与机器人有关 + */ +interface BotPassiveEvent : BotEvent + +/** + * 由 [Bot] 主动发起的动作的事件 + */ +abstract class BotActiveEvent : BotEvent, AbstractCancellableEvent() + + +/** + * 有关群的事件 + */ +interface GroupEvent : BotEvent { + val group: Group + override val bot: Bot + get() = group.bot +} + +/** + * 有关群成员的事件 + */ +interface GroupMemberEvent : GroupEvent { + val member: Member + override val group: Group + get() = member.group +} + + +/** + * 有关群的事件 + */ +interface FriendEvent : BotEvent { + val friend: QQ + override val bot: Bot + get() = friend.bot +} \ No newline at end of file diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt index e1feaa484..69e6b3dcf 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt @@ -21,7 +21,7 @@ import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.event.Event -import net.mamoe.mirai.event.events.ReceiveFriendAddRequestEvent +import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeGroupMessages import net.mamoe.mirai.event.subscribeMessages @@ -54,8 +54,8 @@ suspend fun main() { } // 全局范围订阅事件, 不受 bot 实例影响 - GlobalScope.subscribeAlways { - it.approve() + GlobalScope.subscribeAlways { + } // 订阅来自这个 bot 的群消息事件 From 63b5785b2d570d50d5d9e19b604407672acb42c8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 19:55:03 +0800 Subject: [PATCH 07/16] Add MemberCardChangeEvent --- .../event/events/PassiveEvents.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt index 4582c25a8..18485b588 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt @@ -110,6 +110,37 @@ sealed class MemberLeftEvent : GroupMemberEvent, BotPassiveEvent { // endregion +// region + +/** + * 群名片改动 + */ +sealed class MemberCardChangeEvent : GroupMemberEvent, BotPassiveEvent { + /** + * 群名片 + */ + abstract val card: String + + /** + * 由管理员修改 + */ + data class ByOperator( + override val card: String, + override val member: Member, + val operator: Member + ) : MemberCardChangeEvent() + + /** + * 该成员自己修改 + */ + data class BySelf( + override val card: String, + override val member: Member + ) : MemberCardChangeEvent() +} + +// endregion + // region 成员权限 From 049cf306590f66c00b8fa98084d3d19e448e1179 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 20:40:35 +0800 Subject: [PATCH 08/16] New event design --- .../api/http/route/GroupManageRouteModule.kt | 7 +- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 6 +- .../kotlin/net.mamoe.mirai/BotImpl.kt | 2 +- .../kotlin/net.mamoe.mirai/contact/Member.kt | 14 +- .../event/events/ActiveEvents.kt | 53 --- .../net.mamoe.mirai/event/events/BotEvents.kt | 324 ++++++++++++++++++ .../event/events/PassiveEvents.kt | 186 ---------- .../net.mamoe.mirai/event/events/types.kt | 3 +- .../mirai/imageplugin/ImageSenderMain.kt | 4 +- 9 files changed, 346 insertions(+), 253 deletions(-) delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt index 5e5f10720..fcf7c8e03 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt @@ -4,7 +4,8 @@ import io.ktor.application.Application import io.ktor.application.call import io.ktor.routing.routing import kotlinx.serialization.Serializable -import net.mamoe.mirai.api.http.data.* +import net.mamoe.mirai.api.http.data.PermissionDeniedException +import net.mamoe.mirai.api.http.data.StateCode import net.mamoe.mirai.api.http.data.common.DTO import net.mamoe.mirai.api.http.data.common.VerifyDTO import net.mamoe.mirai.contact.Group @@ -84,7 +85,7 @@ fun Application.groupManageModule() { miraiVerify("/memberInfo") { dto -> val member = dto.session.bot.getGroup(dto.target)[dto.memberId] with(dto.info) { - name?.let { member.groupCard = it } + name?.let { member.nameCard = it } specialTitle?.let { member.specialTitle = it } } call.respondStateCode(StateCode.Success) @@ -145,5 +146,5 @@ private data class MemberDetailDTO( val name: String? = null, val specialTitle: String? = null ) : DTO { - constructor(member: Member) : this(member.groupCard, member.specialTitle) + constructor(member: Member) : this(member.nameCard, member.specialTitle) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 0da74e692..e8a628fb9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -14,6 +14,8 @@ import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.FriendNameRemark import net.mamoe.mirai.data.PreviousNameList import net.mamoe.mirai.data.Profile +import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.events.MemberCardChangeEvent import net.mamoe.mirai.message.data.CustomFaceFromFile import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.MessageChain @@ -149,13 +151,15 @@ internal class MemberImpl( override val group: GroupImpl by group.unsafeWeakRef() val qq: QQImpl by qq.unsafeWeakRef() - override var groupCard: String + override var nameCard: String get() = _groupCard set(newValue) { group.checkBotPermissionOperator() if (_groupCard != newValue) { + val oldValue = _groupCard _groupCard = newValue launch { + MemberCardChangeEvent.ByBot(oldValue, newValue, this@MemberImpl).broadcast() bot.network.run { TroopManagement.EditGroupNametag( bot.client, diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index 39359e1b0..8003cc10e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -107,7 +107,7 @@ abstract class BotImpl constructor( logger.info("Initializing BotNetworkHandler") try { if (::_network.isInitialized) { - BotOfflineEvent(this).broadcast() + BotOfflineEvent.Active(this, cause).broadcast() _network.closeAndJoin(cause) } } catch (e: Exception) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index be3732998..92c663e2d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -11,8 +11,9 @@ package net.mamoe.mirai.contact +import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.events.MemberCardChangeEvent import net.mamoe.mirai.utils.WeakRefProperty -import kotlin.jvm.JvmName import kotlin.time.Duration import kotlin.time.ExperimentalTime @@ -32,18 +33,21 @@ interface Member : QQ, Contact { val permission: MemberPermission /** - * 群名片. 可能为空. + * 群名片. 可能为空. 修改时将会触发事件 * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] * * @see [groupCardOrNick] 获取非空群名片或昵称 + * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 */ - var groupCard: String + var nameCard: String /** * 群头衔 * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] + * + * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 */ var specialTitle: String @@ -78,9 +82,9 @@ interface Member : QQ, Contact { /** * 获取非空群名片或昵称. * - * 若 [群名片][Member.groupCard] 不为空则返回群名片, 为空则返回 [QQ.nick] + * 若 [群名片][Member.nameCard] 不为空则返回群名片, 为空则返回 [QQ.nick] */ -val Member.groupCardOrNick: String get() = this.groupCard.takeIf { it.isNotEmpty() } ?: this.nick +val Member.groupCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick @ExperimentalTime suspend inline fun Member.mute(duration: Duration): Boolean { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt deleted file mode 100644 index 5d4549a14..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/ActiveEvents.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.QQ - - -/** - * [Bot] 登录完成, 好友列表, 群组列表初始化完成 - */ -data class BotLoginSucceedEvent(override val bot: Bot) : BotActiveEvent() - -/** - * [Bot] 主动离线. - */ -data class BotOfflineEvent(override val bot: Bot) : BotActiveEvent() - -// region 好友 - -/** - * [Bot] 删除一个好友 - */ -class BotRemoveFriendEvent(override val friend: QQ) : FriendEvent, BotActiveEvent() - -// endregion - -// region 群 - -/** - * 机器人踢出某个群员 - */ -class BotKickMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() - -/** - * 机器人禁言某个群成员 - */ -class BotMuteMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() - -/** - * 机器人取消禁言某个群成员 - */ -class BotUnmuteMemberEvent(override val member: Member) : GroupMemberEvent, BotActiveEvent() - -// endregion \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt new file mode 100644 index 000000000..6350bb61a --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -0,0 +1,324 @@ +/* + * Copyright 2020 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.event.events + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member +import net.mamoe.mirai.contact.MemberPermission + + +// region Bot 状态 + +/** + * [Bot] 登录完成, 好友列表, 群组列表初始化完成 + */ +data class BotOnlineEvent(override val bot: Bot) : BotActiveEvent + +/** + * [Bot] 离线. + */ +sealed class BotOfflineEvent : BotActiveEvent { + + /** + * 主动离线 + */ + data class Active(override val bot: Bot, val cause: Throwable?) : BotOfflineEvent() + + /** + * 被挤下线 + */ + data class Force(override val bot: Bot) : BotOfflineEvent() +} + +// endregion + +// region 群 + +/** + * Bot 在群里的权限被改变. 操作人一定是群主 + */ +data class BotGroupPermissionChangeEvent( + override val group: Group, + val origin: MemberPermission, + val new: MemberPermission +) : BotPassiveEvent, GroupEvent + +// region 群设置 + +/** + * 群设置改变. 此事件广播前修改就已经完成. + */ +interface GroupSettingChangeEvent : GroupEvent, BotPassiveEvent { + val origin: T + val new: T +} + +/** + * 群名改变. 此事件广播前修改就已经完成. + */ +sealed class GroupNameChangeEvent( +) : GroupSettingChangeEvent, BotPassiveEvent { + + /** + * 由管理员操作 + */ + data class ByOperator( + override val origin: String, + override val new: String, + val operator: Member + ) : GroupNameChangeEvent() { + override val group: Group + get() = operator.group + } + + /** + * 由机器人操作 + */ + data class ByBot( + override val origin: String, + override val new: String, + override val group: Group + ) : GroupNameChangeEvent() +} + +/** + * 群 "全员禁言" 功能状态改变. 此事件广播前修改就已经完成. + */ +sealed class GroupMuteAllEvent : GroupSettingChangeEvent, BotPassiveEvent { + /** + * 由管理员操作 + */ + data class ByOperator( + override val origin: Boolean, + override val new: Boolean, + val operator: Member + ) : GroupMuteAllEvent() { + override val group: Group + get() = operator.group + } + + /** + * 由机器人操作 + */ + data class ByBot( + override val origin: Boolean, + override val new: Boolean, + override val group: Group + ) : GroupMuteAllEvent() +} + +/** + * 群 "坦白说" 功能状态改变. 此事件广播前修改就已经完成. + */ +sealed class GroupConfessTalkEvent : GroupSettingChangeEvent, BotPassiveEvent { + + /** + * 由管理员操作 + */ + data class ByOperator( + override val origin: Boolean, + override val new: Boolean, + val operator: Member + ) : GroupConfessTalkEvent() { + override val group: Group + get() = operator.group + } + + /** + * 由机器人操作 + */ + data class ByBot( + override val origin: Boolean, + override val new: Boolean, + override val group: Group + ) : GroupConfessTalkEvent() +} + +// endregion + + +// region 群成员 + +// region 成员变更 + +/** + * 成员加入群的事件 + */ +data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent + +/** + * 成员离开群的事件 + */ +sealed class MemberLeftEvent : GroupMemberEvent { + /** + * 成员被踢出群. 成员不可能是机器人自己. + */ + sealed class Kick : MemberLeftEvent() { + /** + * 被管理员踢出 + */ + data class ByOperator( + override val member: Member, + val operator: Member + ) : Kick(), BotPassiveEvent + + /** + * 被机器人踢出 + */ + data class ByBot( + override val member: Member + ) : Kick(), BotActiveEvent + } + + /** + * 成员主动离开 + */ + data class Quit(override val member: Member) : MemberLeftEvent() +} + +// endregion + +// region 名片和头衔 + +/** + * 群名片改动. 此事件广播前修改就已经完成. + */ +sealed class MemberCardChangeEvent : GroupMemberEvent { + /** + * 修改前 + */ + abstract val origin: String + + /** + * 修改后 + */ + abstract val new: String + + abstract override val member: Member + + /** + * 由管理员修改 + */ + data class ByOperator( + override val origin: String, + override val new: String, + override val member: Member, + val operator: Member + ) : MemberCardChangeEvent(), BotPassiveEvent + + /** + * 由 [Bot] 修改. 由 [Member.nameCard] + */ + data class ByBot( + override val origin: String, + override val new: String, + override val member: Member + ) : MemberCardChangeEvent(), BotActiveEvent + + /** + * 该成员自己修改 + */ + data class BySelf( + override val origin: String, + override val new: String, + override val member: Member + ) : MemberCardChangeEvent(), BotPassiveEvent +} + +/** + * 群头衔改动. 一定为群主操作 + */ +data class MemberSpecialTitleChangeEvent( + /** + * 修改前 + */ + val origin: String, + + /** + * 修改后 + */ + val new: String, + + override val member: Member +) : GroupMemberEvent + +// endregion + + +// region 成员权限 + +/** + * 成员权限改变的事件. 成员不可能是机器人自己. + */ +data class MemberPermissionChangeEvent( + override val member: Member, + val origin: MemberPermission, + val new: MemberPermission +) : GroupMemberEvent, BotPassiveEvent + +// endregion + + +// region 禁言 + +/** + * 群成员被禁言事件. 操作人和被禁言的成员都不可能是机器人本人 + */ +sealed class MemberMuteEvent : GroupMemberEvent { + abstract override val member: Member + + abstract val durationSeconds: Int + + /** + * 管理员禁言成员 + */ + data class ByOperator( + override val member: Member, + override val durationSeconds: Int, + val operator: Member + ) : MemberMuteEvent(), BotPassiveEvent + + /** + * 机器人禁言成员. 通过 [Member.mute] 触发 + */ + data class ByBot( + override val member: Member, + override var durationSeconds: Int + ) : MemberMuteEvent(), BotActiveEvent +} + +/** + * 群成员被取消禁言事件. 操作人和被禁言的成员都不可能是机器人本人 + */ +sealed class MemberUnmuteEvent : GroupMemberEvent, BotPassiveEvent { + abstract override val member: Member + + /** + * 管理员禁言成员 + */ + data class ByOperator( + override val member: Member, + val operator: Member + ) : MemberUnmuteEvent(), BotPassiveEvent + + /** + * 机器人禁言成员. 通过 [Member.unmute] 触发 + */ + data class ByBot( + override val member: Member + ) : MemberUnmuteEvent(), BotActiveEvent +} + +// endregion + +// endregion + +// endregion \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt deleted file mode 100644 index 18485b588..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/PassiveEvents.kt +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2020 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.event.events - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.data.Packet - -// region Bot 在线状态 - -/** - * 被挤下线 - */ -data class BotForceOfflineEvent( - override val bot: Bot, - val title: String, - val tips: String -) : BotPassiveEvent, Packet -// endregion - -// region 群 - -/** - * Bot 在群里的权限被改变. 操作人一定是群主 - */ -data class BotGroupPermissionChangeEvent( - override val group: Group, - val origin: MemberPermission, - val new: MemberPermission -) : BotPassiveEvent, GroupEvent - -// region 群设置 - -/** - * 群设置改变 - */ -interface GroupSettingChangeEvent : GroupEvent, BotPassiveEvent { - val operator: Member - val origin: T - val new: T - - override val group: Group - get() = operator.group -} - -/** - * 群名改变 - */ -data class GroupNameChangeEvent( - override val operator: Member, - override val origin: String, - override val new: String -) : GroupSettingChangeEvent, BotPassiveEvent - -/** - * 群 "全员禁言" 功能状态改变 - */ -data class GroupMuteAllEvent( - override val operator: Member, - override val origin: Boolean, - override val new: Boolean -) : GroupSettingChangeEvent, BotPassiveEvent - -/** - * 群 "坦白说" 功能状态改变 - */ -data class GroupConfessTalkEvent( - override val operator: Member, - override val origin: Boolean, - override val new: Boolean -) : GroupSettingChangeEvent, BotPassiveEvent - -// endregion - - -// region 群成员 - -// region 成员变更 - -/** - * 成员加入群的事件 - */ -data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotPassiveEvent - -/** - * 成员离开群的事件 - */ -sealed class MemberLeftEvent : GroupMemberEvent, BotPassiveEvent { - /** - * 成员被踢出群. 成员不可能是机器人自己. - * - * @see BotKickMemberEvent 机器人踢出一个人 - */ - data class Kick(override val member: Member, val operator: Member) : MemberLeftEvent() - - /** - * 成员主动离开 - */ - data class Quit(override val member: Member) : MemberLeftEvent() -} - -// endregion - -// region - -/** - * 群名片改动 - */ -sealed class MemberCardChangeEvent : GroupMemberEvent, BotPassiveEvent { - /** - * 群名片 - */ - abstract val card: String - - /** - * 由管理员修改 - */ - data class ByOperator( - override val card: String, - override val member: Member, - val operator: Member - ) : MemberCardChangeEvent() - - /** - * 该成员自己修改 - */ - data class BySelf( - override val card: String, - override val member: Member - ) : MemberCardChangeEvent() -} - -// endregion - - -// region 成员权限 - -/** - * 成员权限改变的事件. 成员不可能是机器人自己. - */ -data class MemberPermissionChangeEvent( - override val bot: Bot, - override val member: Member, - val origin: MemberPermission, - val new: MemberPermission -) : GroupMemberEvent, BotPassiveEvent - -// endregion - - -// region 禁言 - -/** - * 群成员被禁言事件. 操作人和被禁言的成员都不可能是机器人本人 - * - * @see BotMuteMemberEvent 机器人禁言一个人 - */ -data class MemberMuteEvent( - override val member: Member, - val operator: Member, - val durationSeconds: Int -) : GroupMemberEvent, BotPassiveEvent { - override fun toString(): String = "MemberMuteEvent(member=${member.id}, group=${group.id}, operator=${operator.id}, duration=${durationSeconds}s" -} - -/** - * 群成员被取消禁言事件. 操作人和被禁言的成员都不可能是机器人本人 - * - * @see BotUnmuteMemberEvent 机器人取消禁言某个人 - */ -data class MemberUnmuteEvent(override val member: Member, val operator: Member) : GroupMemberEvent, BotPassiveEvent - -// endregion - -// endregion - -// endregion \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt index e26846474..4e0ac6a57 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt @@ -13,7 +13,6 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.event.AbstractCancellableEvent import net.mamoe.mirai.event.Event /** @@ -31,7 +30,7 @@ interface BotPassiveEvent : BotEvent /** * 由 [Bot] 主动发起的动作的事件 */ -abstract class BotActiveEvent : BotEvent, AbstractCancellableEvent() +interface BotActiveEvent : BotEvent /** diff --git a/mirai-plugins/image-sender/src/main/java/net/mamoe/mirai/imageplugin/ImageSenderMain.kt b/mirai-plugins/image-sender/src/main/java/net/mamoe/mirai/imageplugin/ImageSenderMain.kt index c14a09ae7..931d876c5 100644 --- a/mirai-plugins/image-sender/src/main/java/net/mamoe/mirai/imageplugin/ImageSenderMain.kt +++ b/mirai-plugins/image-sender/src/main/java/net/mamoe/mirai/imageplugin/ImageSenderMain.kt @@ -11,7 +11,7 @@ package net.mamoe.mirai.imageplugin import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.GlobalScope -import net.mamoe.mirai.event.events.BotLoginSucceedEvent +import net.mamoe.mirai.event.events.BotOnlineEvent import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.plugin.PluginBase @@ -22,7 +22,7 @@ class ImageSenderMain : PluginBase() { @MiraiExperimentalAPI override fun onEnable() { logger.info("Image Sender plugin enabled") - GlobalScope.subscribeAlways { + GlobalScope.subscribeAlways { logger.info("${this.bot.uin} login succeed, it will be controlled by Image Sender Plugin") this.bot.subscribeMessages { From 96db7a6062fd8df8f6ac13d57eabbceaf1d82a6b Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 21:29:03 +0800 Subject: [PATCH 09/16] Remove BroadcastControllable from GroupMessage --- .../kotlin/net.mamoe.mirai/message/GroupMessage.kt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt index b2a613497..faebb84d0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt @@ -13,7 +13,6 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.event.BroadcastControllable import net.mamoe.mirai.message.data.At import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.utils.getValue @@ -30,21 +29,14 @@ class GroupMessage( val permission: MemberPermission, sender: Member, override val message: MessageChain -) : MessagePacket(bot), BroadcastControllable { +) : MessagePacket(bot) { val group: Group by group.unsafeWeakRef() override val sender: Member by sender.unsafeWeakRef() - /* - 01 00 09 01 00 06 66 61 69 6C 65 64 19 00 45 01 00 42 AA 02 3F 08 06 50 02 60 00 68 00 88 01 00 9A 01 31 08 0A 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 98 03 00 A0 03 02 B0 03 00 C0 03 00 D0 03 00 E8 03 02 8A 04 04 08 02 08 01 90 04 80 C8 10 0E 00 0E 01 00 04 00 00 08 E4 07 00 04 00 00 00 01 12 00 1E 02 00 09 E9 85 B1 E9 87 8E E6 98 9F 03 00 01 02 05 00 04 00 00 00 03 08 00 04 00 00 00 04 - */ override val subject: Group get() = group inline fun At.member(): Member = group[this.target] inline fun Long.member(): Member = group[this] override fun toString(): String = "GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)" - - - override val shouldBroadcast: Boolean - get() = bot.uin != sender.id // 自己会收到自己发的消息 } \ No newline at end of file From bc71475f350b79fe8cc9a1cb51383e713f2bd36c Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 21:29:28 +0800 Subject: [PATCH 10/16] Add event broadcasting --- .../api/http/route/GroupManageRouteModule.kt | 4 +- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 71 +++++++-- .../protocol/packet/chat/TroopManagement.kt | 22 +-- .../kotlin/net.mamoe.mirai/contact/Contact.kt | 10 ++ .../kotlin/net.mamoe.mirai/contact/Group.kt | 16 +- .../kotlin/net.mamoe.mirai/contact/Member.kt | 14 +- .../kotlin/net.mamoe.mirai/contact/QQ.kt | 4 + .../net.mamoe.mirai/event/Subscribable.kt | 3 + .../net.mamoe.mirai/event/events/BotEvents.kt | 146 ++++++++++++++++-- .../src/main/kotlin/demo/gentleman/Main.kt | 8 - .../japt/internal/BlockingContactsImpl.kt | 2 +- 11 files changed, 239 insertions(+), 61 deletions(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt index fcf7c8e03..645cb741e 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/GroupManageRouteModule.kt @@ -64,7 +64,7 @@ fun Application.groupManageModule() { val group = dto.session.bot.getGroup(dto.target) with(dto.config) { name?.let { group.name = it } - announcement?.let { group.announcement = it } + announcement?.let { group.entranceAnnouncement = it } confessTalk?.let { group.confessTalk = it } allowMemberInvite?.let { group.allowMemberInvite = it } // TODO: 待core接口实现设置可改 @@ -128,7 +128,7 @@ private data class GroupDetailDTO( val anonymousChat: Boolean? = null ) : DTO { constructor(group: Group) : this( - group.name, group.announcement, group.confessTalk, group.allowMemberInvite, + group.name, group.entranceAnnouncement, group.confessTalk, group.allowMemberInvite, group.autoApprove, group.anonymousChat ) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index e8a628fb9..1a5ffbf37 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -15,7 +15,9 @@ import net.mamoe.mirai.data.FriendNameRemark import net.mamoe.mirai.data.PreviousNameList import net.mamoe.mirai.data.Profile import net.mamoe.mirai.event.broadcast -import net.mamoe.mirai.event.events.MemberCardChangeEvent +import net.mamoe.mirai.event.events.* +import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent +import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.data.CustomFaceFromFile import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.MessageChain @@ -53,18 +55,25 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin override lateinit var nick: String override suspend fun sendMessage(message: MessageChain) { + val event = FriendMessageSendEvent(this, message).broadcast() + if (event.isCancelled) { + throw EventCancelledException("cancelled by FriendMessageSendEvent") + } bot.network.run { check( MessageSvc.PbSendMsg.ToFriend( bot.client, id, - message + event.message ).sendAndExpect() is MessageSvc.PbSendMsg.Response.SUCCESS ) { "send message failed" } } } override suspend fun uploadImage(image: ExternalImage): Image = try { + if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) { + throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup") + } bot.network.run { val response = LongConn.OffPicUp( bot.client, Cmd0x352.TryUpImgReq( @@ -89,7 +98,9 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin height = response.imageInfo.fileHeight, width = response.imageInfo.fileWidth, resourceId = response.resourceId - ) + ).also { + ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast() + } is LongConn.OffPicUp.Response.RequireUpload -> { Http.postImage("0x6ff0070", bot.uin, null, imageInput = image.input, inputSize = image.inputSize, uKeyHex = response.uKey.toUHexString("")) // HighwayHelper.uploadImage( @@ -110,9 +121,14 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin height = image.height, width = image.width, resourceId = response.resourceId - ) + ).also { + ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast() + } + } + is LongConn.OffPicUp.Response.Failed -> { + ImageUploadEvent.Failed(this@QQImpl, image, -1, response.message).broadcast() + error(response.message) } - is LongConn.OffPicUp.Response.Failed -> error(response.message) } } } finally { @@ -159,7 +175,6 @@ internal class MemberImpl( val oldValue = _groupCard _groupCard = newValue launch { - MemberCardChangeEvent.ByBot(oldValue, newValue, this@MemberImpl).broadcast() bot.network.run { TroopManagement.EditGroupNametag( bot.client, @@ -167,6 +182,7 @@ internal class MemberImpl( newValue ).sendWithoutExpect() } + MemberCardChangeEvent.ByBot(oldValue, newValue, this@MemberImpl).broadcast() } } } @@ -176,6 +192,7 @@ internal class MemberImpl( set(newValue) { group.checkBotPermissionOperator() if (_specialTitle != newValue) { + val oldValue = _specialTitle _specialTitle = newValue launch { bot.network.run { @@ -185,6 +202,7 @@ internal class MemberImpl( newValue ).sendWithoutExpect() } + MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl).broadcast() } } } @@ -204,6 +222,8 @@ internal class MemberImpl( timeInSecond = durationSeconds ).sendAndExpect() } + + MemberMuteEvent.ByBot(this@MemberImpl, durationSeconds).broadcast() return true } @@ -220,6 +240,8 @@ internal class MemberImpl( timeInSecond = 0 ).sendAndExpect() } + + MemberUnmuteEvent.ByBot(this@MemberImpl).broadcast() return true } @@ -233,7 +255,9 @@ internal class MemberImpl( client = bot.client, member = this@MemberImpl, message = message - ).sendAndExpect().success + ).sendAndExpect().success.also { + MemberLeaveEvent.Kick.ByBot(this@MemberImpl).broadcast() + } } } @@ -270,6 +294,7 @@ internal class GroupImpl( set(newValue) { this.checkBotPermissionOperator() if (_name != newValue) { + val oldValue = _name _name = newValue launch { bot.network.run { @@ -279,15 +304,17 @@ internal class GroupImpl( newName = newValue ).sendWithoutExpect() } + GroupNameChangeEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() } } } - override var announcement: String + override var entranceAnnouncement: String get() = _announcement set(newValue) { this.checkBotPermissionOperator() if (_announcement != newValue) { + val oldValue = _announcement _announcement = newValue launch { bot.network.run { @@ -297,6 +324,7 @@ internal class GroupImpl( newMemo = newValue ).sendWithoutExpect() } + GroupEntranceAnnouncementChangeEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() } } } @@ -307,6 +335,7 @@ internal class GroupImpl( set(newValue) { this.checkBotPermissionOperator() if (_allowMemberInvite != newValue) { + val oldValue = _allowMemberInvite _allowMemberInvite = newValue launch { bot.network.run { @@ -316,6 +345,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } + GroupAllowMemberInviteEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() } } } @@ -337,6 +367,7 @@ internal class GroupImpl( set(newValue) { this.checkBotPermissionOperator() if (_confessTalk != newValue) { + val oldValue = _confessTalk _confessTalk = newValue launch { bot.network.run { @@ -346,6 +377,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } + GroupAllowConfessTalkEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() } } } @@ -356,6 +388,7 @@ internal class GroupImpl( set(newValue) { this.checkBotPermissionOperator() if (_muteAll != newValue) { + val oldValue = _muteAll _muteAll = newValue launch { bot.network.run { @@ -365,6 +398,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } + GroupMuteAllEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() } } } @@ -376,7 +410,7 @@ internal class GroupImpl( override suspend fun quit(): Boolean { check(botPermission != MemberPermission.OWNER) { "An owner cannot quit from a owning group" } - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + TODO("not implemented") } @@ -395,11 +429,15 @@ internal class GroupImpl( override val bot: QQAndroidBot by bot.unsafeWeakRef() override suspend fun sendMessage(message: MessageChain) { + val event = GroupMessageSendEvent(this, message).broadcast() + if (event.isCancelled) { + throw EventCancelledException("cancelled by FriendMessageSendEvent") + } bot.network.run { val response = MessageSvc.PbSendMsg.ToGroup( bot.client, id, - message + event.message ).sendAndExpect() check( response is MessageSvc.PbSendMsg.Response.SUCCESS @@ -408,6 +446,9 @@ internal class GroupImpl( } override suspend fun uploadImage(image: ExternalImage): Image = try { + if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) { + throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup") + } bot.network.run { val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp( bot.client, @@ -422,7 +463,10 @@ internal class GroupImpl( ).sendAndExpect() when (response) { - is ImgStore.GroupPicUp.Response.Failed -> error("upload group image failed with reason ${response.message}") + is ImgStore.GroupPicUp.Response.Failed -> { + ImageUploadEvent.Failed(this@GroupImpl, image, response.resultCode, response.message).broadcast() + error("upload group image failed with reason ${response.message}") + } is ImgStore.GroupPicUp.Response.FileExists -> { val resourceId = image.calculateImageResourceId() // return NotOnlineImageFromFile( @@ -439,10 +483,9 @@ internal class GroupImpl( return CustomFaceFromFile( md5 = image.md5, filepath = resourceId - ) + ).also { ImageUploadEvent.Succeed(this@GroupImpl, image, it).broadcast() } } is ImgStore.GroupPicUp.Response.RequireUpload -> { - HighwayHelper.uploadImage( client = bot.client, serverIp = response.uploadIpList.first().toIpV4AddressString(), @@ -467,7 +510,7 @@ internal class GroupImpl( return CustomFaceFromFile( md5 = image.md5, filepath = resourceId - ) + ).also { ImageUploadEvent.Succeed(this@GroupImpl, image, it).broadcast() } /* fileId = response.fileId.toInt(), fileType = 0, // ? diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt index 6074712cb..bedf67f9a 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt @@ -27,7 +27,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement.GetGroupOperationInfo.decode import net.mamoe.mirai.utils.daysToSeconds import net.mamoe.mirai.utils.io.encodeToString @@ -66,9 +65,7 @@ internal class TroopManagement { } object Response : Packet { - override fun toString(): String { - return "Response(Mute)" - } + override fun toString(): String = "Response(Mute)" } } @@ -80,9 +77,7 @@ internal class TroopManagement { val autoApprove: Boolean, val confessTalk: Boolean ) : Packet { - override fun toString(): String { - return "Response(GroupInfo)" - } + override fun toString(): String = "Response(GroupInfo)" } operator fun invoke( @@ -146,9 +141,7 @@ internal class TroopManagement { class Response( val success: Boolean ) : Packet { - override fun toString(): String { - return "Response(Kick Member)" - } + override fun toString(): String = "Response(Kick Member)" } operator fun invoke( @@ -424,13 +417,4 @@ internal class TroopManagement { } } - - /* - internal object Recall: OutgoingPacketFactory("wtlogin.login"){ - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): WtLogin.Login.LoginPacketResponse { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - } - */ - } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index 794b8c36c..96ba7609c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -13,6 +13,10 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.events.BeforeImageUploadEvent +import net.mamoe.mirai.event.events.ImageUploadEvent +import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent +import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.data.* import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.WeakRefProperty @@ -40,6 +44,9 @@ interface Contact : CoroutineScope { /** * 向这个对象发送消息. + * + * @see FriendMessageSendEvent 发送好友信息事件, cancellable + * @see GroupMessageSendEvent 发送群消息事件. cancellable */ suspend fun sendMessage(message: MessageChain) @@ -47,6 +54,9 @@ interface Contact : CoroutineScope { * 上传一个图片以备发送. * TODO: 群图片与好友图片之间是否通用还不确定. * TODO: 好友之间图片是否通用还不确定. + * + * @see BeforeImageUploadEvent 图片发送前事件, cancellable + * @see ImageUploadEvent 图片发送完成事件 */ suspend fun uploadImage(image: ExternalImage): Image diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 128b63a19..d4448a6ea 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.event.events.* import net.mamoe.mirai.utils.MiraiExperimentalAPI /** @@ -22,32 +23,41 @@ interface Group : Contact, CoroutineScope { * 群名称. * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] + * 频繁修改可能会被服务器拒绝. * - * 注: 频繁修改可能会被服务器拒绝. + * @see MemberPermissionChangeEvent */ var name: String /** * 入群公告, 没有时为空字符串. * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] + * + * @see GroupEntranceAnnouncementChangeEvent */ - var announcement: String + var entranceAnnouncement: String /** * 全体禁言状态. `true` 为开启. * * 当前仅能修改状态. + * + * @see GroupMuteAllEvent */// TODO: 2020/2/5 实现 muteAll 的查询 var muteAll: Boolean /** * 坦白说状态. `true` 为允许. * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] + + * @see GroupAllowConfessTalkEvent */ var confessTalk: Boolean /** * 允许群员邀请好友入群的状态. `true` 为允许 * * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] + * + * @see GroupAllowMemberInviteEvent */ var allowMemberInvite: Boolean /** @@ -74,6 +84,8 @@ interface Group : Contact, CoroutineScope { * 机器人在这个群里的权限 * * **MiraiExperimentalAPI**: 在未来可能会被修改 + * + * @see BotGroupPermissionChangeEvent */ @MiraiExperimentalAPI val botPermission: MemberPermission diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index 92c663e2d..686217407 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -13,6 +13,9 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Bot import net.mamoe.mirai.event.events.MemberCardChangeEvent +import net.mamoe.mirai.event.events.MemberLeaveEvent +import net.mamoe.mirai.event.events.MemberMuteEvent +import net.mamoe.mirai.event.events.MemberSpecialTitleChangeEvent import net.mamoe.mirai.utils.WeakRefProperty import kotlin.time.Duration import kotlin.time.ExperimentalTime @@ -38,6 +41,7 @@ interface Member : QQ, Contact { * 在修改时将会异步上传至服务器. 无权限修改时将会抛出异常 [PermissionDeniedException] * * @see [groupCardOrNick] 获取非空群名片或昵称 + * * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 */ var nameCard: String @@ -55,7 +59,7 @@ interface Member : QQ, Contact { * 禁言 * * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常. - * @return 当机器人无权限禁言这个群成员时返回 `false` + * @return 机器人无权限时返回 `false` * * @see Int.minutesToSeconds * @see Int.hoursToSeconds @@ -64,12 +68,16 @@ interface Member : QQ, Contact { suspend fun mute(durationSeconds: Int): Boolean /** - * 解除禁言. 在没有权限时会返回 `false`. + * 解除禁言. 机器人无权限时返回 `false`. + * + * @see MemberMuteEvent 成员被禁言事件. */ suspend fun unmute(): Boolean /** - * 踢出该成员. 机器人无权限时返回 `false` + * 踢出该成员. 机器人无权限时返回 `false`. + * + * @see MemberLeaveEvent.Kick 成员被踢出事件. */ suspend fun kick(message: String = ""): Boolean diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt index 1ea488a5e..986c00072 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt @@ -16,6 +16,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.data.FriendNameRemark import net.mamoe.mirai.data.PreviousNameList import net.mamoe.mirai.data.Profile +import net.mamoe.mirai.utils.MiraiExperimentalAPI /** * QQ 对象. @@ -49,6 +50,7 @@ interface QQ : Contact, CoroutineScope { /** * 查询用户资料 */ + @MiraiExperimentalAPI("还未支持") suspend fun queryProfile(): Profile /** @@ -58,10 +60,12 @@ interface QQ : Contact, CoroutineScope { * - 昵称 * - 共同群内的群名片 */ + @MiraiExperimentalAPI("还未支持") suspend fun queryPreviousNameList(): PreviousNameList /** * 查询机器人账号给这个人设置的备注 */ + @MiraiExperimentalAPI("还未支持") suspend fun queryRemark(): FriendNameRemark } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt index 14d5b1106..0a8346cf4 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt @@ -70,6 +70,9 @@ abstract class AbstractCancellableEvent : Event, CancellableEvent { */ @UseExperimental(MiraiInternalAPI::class) suspend fun E.broadcast(): E = apply { + if (this is BroadcastControllable && !this.shouldBroadcast) { + return@apply + } if (this is BotEvent && !(this.bot as BotImpl<*>).onEvent(this)) { return@apply } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 6350bb61a..f9607fd52 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -10,9 +10,21 @@ package net.mamoe.mirai.event.events import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.contact.* +import net.mamoe.mirai.event.AbstractCancellableEvent +import net.mamoe.mirai.event.CancellableEvent +import net.mamoe.mirai.message.data.Image +import net.mamoe.mirai.message.data.MessageChain +import net.mamoe.mirai.utils.ExternalImage + + +@Suppress("unused") +class EventCancelledException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} // region Bot 状态 @@ -40,6 +52,64 @@ sealed class BotOfflineEvent : BotActiveEvent { // endregion +// region 消息 + +sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractCancellableEvent() { + abstract val target: Contact + final override val bot: Bot + get() = target.bot + + data class GroupMessageSendEvent( + override val target: Group, + var message: MessageChain + ) : MessageSendEvent(), CancellableEvent + + data class FriendMessageSendEvent( + override val target: QQ, + var message: MessageChain + ) : MessageSendEvent(), CancellableEvent +} + +// endregion + +// region 图片 + +/** + * 图片上传前. 可以阻止上传 + */ +data class BeforeImageUploadEvent( + val target: Contact, + val source: ExternalImage +) : BotEvent, BotActiveEvent, AbstractCancellableEvent() { + override val bot: Bot + get() = target.bot +} + +/** + * 图片上传完成 + */ +sealed class ImageUploadEvent : BotEvent, BotActiveEvent, AbstractCancellableEvent() { + abstract val target: Contact + abstract val source: ExternalImage + override val bot: Bot + get() = target.bot + + data class Succeed( + override val target: Contact, + override val source: ExternalImage, + val image: Image + ) : ImageUploadEvent(), CancellableEvent + + data class Failed( + override val target: Contact, + override val source: ExternalImage, + val errno: Int, + val message: String + ) : ImageUploadEvent(), CancellableEvent +} + +// endregion + // region 群 /** @@ -64,8 +134,7 @@ interface GroupSettingChangeEvent : GroupEvent, BotPassiveEvent { /** * 群名改变. 此事件广播前修改就已经完成. */ -sealed class GroupNameChangeEvent( -) : GroupSettingChangeEvent, BotPassiveEvent { +sealed class GroupNameChangeEvent : GroupSettingChangeEvent, BotPassiveEvent { /** * 由管理员操作 @@ -89,6 +158,34 @@ sealed class GroupNameChangeEvent( ) : GroupNameChangeEvent() } + +/** + * 入群公告改变. 此事件广播前修改就已经完成. + */ +sealed class GroupEntranceAnnouncementChangeEvent : GroupSettingChangeEvent, BotPassiveEvent { + + /** + * 由管理员操作 + */ + data class ByOperator( + override val origin: String, + override val new: String, + val operator: Member + ) : GroupEntranceAnnouncementChangeEvent() { + override val group: Group + get() = operator.group + } + + /** + * 由机器人操作 + */ + data class ByBot( + override val origin: String, + override val new: String, + override val group: Group + ) : GroupEntranceAnnouncementChangeEvent() +} + /** * 群 "全员禁言" 功能状态改变. 此事件广播前修改就已经完成. */ @@ -118,8 +215,7 @@ sealed class GroupMuteAllEvent : GroupSettingChangeEvent, BotPassiveEve /** * 群 "坦白说" 功能状态改变. 此事件广播前修改就已经完成. */ -sealed class GroupConfessTalkEvent : GroupSettingChangeEvent, BotPassiveEvent { - +sealed class GroupAllowConfessTalkEvent : GroupSettingChangeEvent, BotPassiveEvent { /** * 由管理员操作 */ @@ -127,7 +223,7 @@ sealed class GroupConfessTalkEvent : GroupSettingChangeEvent, BotPassiv override val origin: Boolean, override val new: Boolean, val operator: Member - ) : GroupConfessTalkEvent() { + ) : GroupAllowConfessTalkEvent() { override val group: Group get() = operator.group } @@ -139,7 +235,33 @@ sealed class GroupConfessTalkEvent : GroupSettingChangeEvent, BotPassiv override val origin: Boolean, override val new: Boolean, override val group: Group - ) : GroupConfessTalkEvent() + ) : GroupAllowConfessTalkEvent() +} + +/** + * 群 "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成. + */ +sealed class GroupAllowMemberInviteEvent : GroupSettingChangeEvent, BotPassiveEvent { + /** + * 由管理员操作 + */ + data class ByOperator( + override val origin: Boolean, + override val new: Boolean, + val operator: Member + ) : GroupAllowMemberInviteEvent() { + override val group: Group + get() = operator.group + } + + /** + * 由机器人操作 + */ + data class ByBot( + override val origin: Boolean, + override val new: Boolean, + override val group: Group + ) : GroupAllowMemberInviteEvent() } // endregion @@ -157,11 +279,11 @@ data class MemberJoinEvent(override val member: Member) : GroupMemberEvent, BotP /** * 成员离开群的事件 */ -sealed class MemberLeftEvent : GroupMemberEvent { +sealed class MemberLeaveEvent : GroupMemberEvent { /** * 成员被踢出群. 成员不可能是机器人自己. */ - sealed class Kick : MemberLeftEvent() { + sealed class Kick : MemberLeaveEvent() { /** * 被管理员踢出 */ @@ -181,7 +303,7 @@ sealed class MemberLeftEvent : GroupMemberEvent { /** * 成员主动离开 */ - data class Quit(override val member: Member) : MemberLeftEvent() + data class Quit(override val member: Member) : MemberLeaveEvent() } // endregion diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt index 69e6b3dcf..bd15503f9 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt @@ -81,14 +81,6 @@ suspend fun main() { "你好" reply "你好!" - startsWith("profile", removePrefix = true) { - val account = it.trim() - if (account.isNotEmpty()) { - bot.getFriend(account.toLong()) - } else { - sender - }.queryProfile().toString().reply() - } "grouplist" reply { //"https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin=" + bot.qqAccount + "&clientkey=" + com.tick_tock.pctim.utils.Util.byte2HexString( diff --git a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt index 5d52aa1b5..812299984 100644 --- a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt +++ b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingContactsImpl.kt @@ -52,7 +52,7 @@ internal class BlockingGroupImpl(private val delegate: Group) : BlockingGroup { override fun toFullString(): String = delegate.toFullString() override fun getMember(id: Long): BlockingMember = delegate[id].blocking() override fun getBot(): BlockingBot = delegate.bot.blocking() - override fun getAnnouncement(): String = delegate.announcement + override fun getAnnouncement(): String = delegate.entranceAnnouncement @UseExperimental(MiraiInternalAPI::class) override fun getMembers(): Map = delegate.members.delegate.toList().associateBy { it.id }.mapValues { it.value.blocking() } From dfa3af56436d79a15a2a4a36f3e94a71c87e8ea7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 21:33:03 +0800 Subject: [PATCH 11/16] Fix build --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 8 ++++---- .../packet/list/{FriendListPacket.kt => FriendList.kt} | 0 .../kotlin/net.mamoe.mirai/event/events/BotEvents.kt | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/{FriendListPacket.kt => FriendList.kt} (100%) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 19bc6b821..82fe43680 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -14,7 +14,7 @@ import kotlinx.io.core.discardExact import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.BroadcastControllable -import net.mamoe.mirai.event.events.BotForceOfflineEvent +import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.qqandroid.QQAndroidBot @@ -178,10 +178,10 @@ internal class MessageSvc { /** * 被挤下线 */ - internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotForceOfflineEvent { + internal object PushForceOffline : OutgoingPacketFactory("MessageSvc.PushForceOffline") { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): BotOfflineEvent.Force { val struct = this.decodeUniPacket(RequestPushForceOffline.serializer()) - return BotForceOfflineEvent(bot, title = struct.title ?: "", tips = struct.tips ?: "") + return BotOfflineEvent.Force(bot, title = struct.title ?: "", message = struct.tips ?: "") } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt similarity index 100% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendList.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index f9607fd52..7bb935655 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.event.events import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.* +import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.AbstractCancellableEvent import net.mamoe.mirai.event.CancellableEvent import net.mamoe.mirai.message.data.Image @@ -47,7 +48,7 @@ sealed class BotOfflineEvent : BotActiveEvent { /** * 被挤下线 */ - data class Force(override val bot: Bot) : BotOfflineEvent() + data class Force(override val bot: Bot, val title: String, val message: String) : BotOfflineEvent(), Packet } // endregion From 5bd96876d9484e35e31477da97ad8a07679099a5 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 11 Feb 2020 22:06:03 +0800 Subject: [PATCH 12/16] Add event broadcast --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 22 +- .../network/QQAndroidBotNetworkHandler.kt | 4 +- .../packet/chat/receive/OnlinePush.kt | 154 ++++++----- .../kotlin/net.mamoe.mirai/contact/Member.kt | 9 +- .../net.mamoe.mirai/event/events/BotEvents.kt | 249 +++++------------- 5 files changed, 171 insertions(+), 267 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 1a5ffbf37..08eefee5c 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -162,7 +162,7 @@ internal class MemberImpl( var _specialTitle: String, group: GroupImpl, override val coroutineContext: CoroutineContext, - override val permission: MemberPermission + override var permission: MemberPermission ) : ContactImpl(), Member, QQ by qq { override val group: GroupImpl by group.unsafeWeakRef() val qq: QQImpl by qq.unsafeWeakRef() @@ -182,7 +182,7 @@ internal class MemberImpl( newValue ).sendWithoutExpect() } - MemberCardChangeEvent.ByBot(oldValue, newValue, this@MemberImpl).broadcast() + MemberCardChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast() } } } @@ -190,7 +190,7 @@ internal class MemberImpl( override var specialTitle: String get() = _specialTitle set(newValue) { - group.checkBotPermissionOperator() + group.checkBotPermission(MemberPermission.OWNER) if (_specialTitle != newValue) { val oldValue = _specialTitle _specialTitle = newValue @@ -223,7 +223,7 @@ internal class MemberImpl( ).sendAndExpect() } - MemberMuteEvent.ByBot(this@MemberImpl, durationSeconds).broadcast() + MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast() return true } @@ -241,7 +241,7 @@ internal class MemberImpl( ).sendAndExpect() } - MemberUnmuteEvent.ByBot(this@MemberImpl).broadcast() + MemberUnmuteEvent(this@MemberImpl, null).broadcast() return true } @@ -256,7 +256,7 @@ internal class MemberImpl( member = this@MemberImpl, message = message ).sendAndExpect().success.also { - MemberLeaveEvent.Kick.ByBot(this@MemberImpl).broadcast() + MemberLeaveEvent.Kick(this@MemberImpl, null).broadcast() } } } @@ -304,7 +304,7 @@ internal class GroupImpl( newName = newValue ).sendWithoutExpect() } - GroupNameChangeEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() + GroupNameChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast() } } } @@ -324,7 +324,7 @@ internal class GroupImpl( newMemo = newValue ).sendWithoutExpect() } - GroupEntranceAnnouncementChangeEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() + GroupEntranceAnnouncementChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast() } } } @@ -345,7 +345,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } - GroupAllowMemberInviteEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() + GroupAllowMemberInviteEvent(oldValue, newValue, this@GroupImpl, null).broadcast() } } } @@ -377,7 +377,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } - GroupAllowConfessTalkEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() + GroupAllowConfessTalkEvent(oldValue, newValue, this@GroupImpl, null).broadcast() } } } @@ -398,7 +398,7 @@ internal class GroupImpl( switch = newValue ).sendWithoutExpect() } - GroupMuteAllEvent.ByBot(oldValue, newValue, this@GroupImpl).broadcast() + GroupMuteAllEvent(oldValue, newValue, this@GroupImpl, null).broadcast() } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 6b4b55a91..44d84610d 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -24,7 +24,7 @@ import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.* -import net.mamoe.mirai.event.events.BotForceOfflineEvent +import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.qqandroid.GroupImpl import net.mamoe.mirai.qqandroid.MemberImpl @@ -119,7 +119,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) override suspend fun init(): Unit = coroutineScope { - this@QQAndroidBotNetworkHandler.subscribeAlways { + this@QQAndroidBotNetworkHandler.subscribeAlways { if (this@QQAndroidBotNetworkHandler.bot == this.bot) { this.bot.logger.error("被挤下线") close() diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 3c6538a1c..0ff8aeb3e 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -18,7 +18,9 @@ import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.NoPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.events.* import net.mamoe.mirai.message.GroupMessage +import net.mamoe.mirai.qqandroid.MemberImpl import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket import net.mamoe.mirai.qqandroid.io.serialization.loadAs @@ -103,26 +105,33 @@ internal class OnlinePush { this.discardExact(5) val var4 = readByte().toInt() var var5 = 0L - val var7 = readUInt().toLong() + val target = readUInt().toLong() if (var4 != 0 && var4 != 1) { var5 = readUInt().toLong() } if (var5 == 0L && this.remaining == 1L) {//管理员变更 val groupUin = content.fromUin - val target = var7 - if (this.readByte().toInt() == 1) { - println("群uin" + groupUin + "新增管理员" + target) + + val member = bot.getGroupByUin(groupUin)[target] as MemberImpl + val old = member.permission + return if (this.readByte().toInt() == 1) { + member.permission = MemberPermission.ADMINISTRATOR + MemberPermissionChangeEvent(member, old, MemberPermission.ADMINISTRATOR) } else { - println("群uin" + groupUin + "减少管理员" + target) + member.permission = MemberPermission.MEMBER + MemberPermissionChangeEvent(member, old, MemberPermission.ADMINISTRATOR) } } } 34 -> { - var groupUinOrCode = readUInt().toLong() + readUInt().toLong() // uin or code ? if (readByte().toInt() == 1) { val target = readUInt().toLong() val groupUin = content.fromUin - println("群uin" + groupUin + "t掉了" + target) + + val member = bot.getGroupByUin(groupUin)[target] as MemberImpl + + return MemberLeaveEvent.Kick(member, TODO("踢出时获取管理员")) } } @@ -144,79 +153,86 @@ internal class OnlinePush { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet { val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") reqPushMsg.vMsgInfos.forEach { msgInfo: MsgInfo -> - var debug = "" msgInfo.vMsg!!.read { - if (msgInfo.shMsgType.toInt() == 732) { - val groupCode = this.readUInt().toLong() - debug = "群 $groupCode " - when (val internalType = this.readShort().toInt()) { - 3073 -> { - val operatorUin = this.readUInt().toLong() - debug += " 管理员 $operatorUin" - val operationTime = this.readUInt().toLong() - debug += " 禁言 " - this.discardExact(2) - val target = this.readUInt().toLong() - val time = this.readUInt().toLong() - if (target == 0L) { - debug += "全群" - } else { - debug += target - } + when { + msgInfo.shMsgType.toInt() == 732 -> { + val group = bot.getGroup(this.readUInt().toLong()) - if (time == 0L) { - debug += " 解除 " - } else { - debug += " " + time + "s" - } - } - 3585 -> { - val operatorUin = this.readUInt().toLong() - debug += " 管理员 $operatorUin" - debug += " 匿名聊天 " - if (this.readInt() == 0) { - debug += " 开启 " - } else { - debug += " 关闭 " - } - } - 4096 -> { - val dataBytes = this.readBytes(26) - val message = this.readString(this.readByte().toInt()) - if (dataBytes[0].toInt() != 59) { - println("更改群名为$message") - } else { - println(message + ":" + dataBytes.toUHexString()) - debug += message - when (message) { - "管理员已关闭群聊坦白说" -> { + when (val internalType = this.readShort().toInt()) { + 3073 -> { // mute + val operator = group[this.readUInt().toLong()] + this.readUInt().toLong() // time + this.discardExact(2) + val target = this.readUInt().toLong() + val time = this.readInt() + return if (target == 0L) { + if (time == 0) { + GroupMuteAllEvent(origin = true, new = false, operator = operator, group = group) + } else { + GroupMuteAllEvent(origin = false, new = true, operator = operator, group = group) } - "管理员已开启群聊坦白说" -> { - - } - else -> { - println("Unknown server messages $message") + } else { + val member = group[target] + if (time == 0) { + MemberUnmuteEvent(operator = operator, member = member) + } else { + MemberMuteEvent(operator = operator, member = member, durationSeconds = time) } } } - } - 4352 -> { - println(msgInfo.contentToString()) - println(msgInfo.vMsg.toUHexString()) - } - else -> { - println("unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " ") + 3585 -> { // 匿名 + val operator = group[this.readUInt().toLong()] + return GroupAllowAnonymousChatEvent( + origin = group.anonymousChat, + new = this.readInt() == 0, + operator = operator, + group = group + ) + } + 4096 -> { + val dataBytes = this.readBytes(26) + val message = this.readString(this.readByte().toInt()) + + TODO("读取操作人") + + /* + return if (dataBytes[0].toInt() != 59) { + GroupNameChangeEvent(origin = group.name, new = ) + } else { + println(message + ":" + dataBytes.toUHexString()) + when (message) { + "管理员已关闭群聊坦白说" -> { + GroupAllowConfessTalkEvent(group.confessTalk, false, ope) + } + "管理员已开启群聊坦白说" -> { + + } + else -> { + println("Unknown server messages $message") + } + } + } + */ + } + 4352 -> { + println(msgInfo.contentToString()) + println(msgInfo.vMsg.toUHexString()) + } + else -> { + println("unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " ") + } } } - } else if (msgInfo.shMsgType.toInt() == 528) { - val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer()) - println(content.contentToString()) - } else { - println("unknown shtype ${msgInfo.shMsgType.toInt()}") + msgInfo.shMsgType.toInt() == 528 -> { + val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer()) + println(content.contentToString()) + } + else -> { + println("unknown shtype ${msgInfo.shMsgType.toInt()}") + } } } - println(debug) } return NoPacket diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index 686217407..acd50e64b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -12,10 +12,7 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Bot -import net.mamoe.mirai.event.events.MemberCardChangeEvent -import net.mamoe.mirai.event.events.MemberLeaveEvent -import net.mamoe.mirai.event.events.MemberMuteEvent -import net.mamoe.mirai.event.events.MemberSpecialTitleChangeEvent +import net.mamoe.mirai.event.events.* import net.mamoe.mirai.utils.WeakRefProperty import kotlin.time.Duration import kotlin.time.ExperimentalTime @@ -64,13 +61,15 @@ interface Member : QQ, Contact { * @see Int.minutesToSeconds * @see Int.hoursToSeconds * @see Int.daysToSeconds + * + * @see MemberMuteEvent 成员被禁言事件 */ suspend fun mute(durationSeconds: Int): Boolean /** * 解除禁言. 机器人无权限时返回 `false`. * - * @see MemberMuteEvent 成员被禁言事件. + * @see MemberUnmuteEvent 成员被取消禁言事件. */ suspend fun unmute(): Boolean diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 7bb935655..5ba1caeaf 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -135,135 +135,81 @@ interface GroupSettingChangeEvent : GroupEvent, BotPassiveEvent { /** * 群名改变. 此事件广播前修改就已经完成. */ -sealed class GroupNameChangeEvent : GroupSettingChangeEvent, BotPassiveEvent { - +data class GroupNameChangeEvent( + override val origin: String, + override val new: String, + override val group: Group, /** - * 由管理员操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByOperator( - override val origin: String, - override val new: String, - val operator: Member - ) : GroupNameChangeEvent() { - override val group: Group - get() = operator.group - } - - /** - * 由机器人操作 - */ - data class ByBot( - override val origin: String, - override val new: String, - override val group: Group - ) : GroupNameChangeEvent() -} - + val operator: Member? +) : GroupSettingChangeEvent, Packet /** * 入群公告改变. 此事件广播前修改就已经完成. */ -sealed class GroupEntranceAnnouncementChangeEvent : GroupSettingChangeEvent, BotPassiveEvent { - +data class GroupEntranceAnnouncementChangeEvent( + override val origin: String, + override val new: String, + override val group: Group, /** - * 由管理员操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByOperator( - override val origin: String, - override val new: String, - val operator: Member - ) : GroupEntranceAnnouncementChangeEvent() { - override val group: Group - get() = operator.group - } + val operator: Member? +) : GroupSettingChangeEvent, Packet - /** - * 由机器人操作 - */ - data class ByBot( - override val origin: String, - override val new: String, - override val group: Group - ) : GroupEntranceAnnouncementChangeEvent() -} /** * 群 "全员禁言" 功能状态改变. 此事件广播前修改就已经完成. */ -sealed class GroupMuteAllEvent : GroupSettingChangeEvent, BotPassiveEvent { +data class GroupMuteAllEvent( + override val origin: Boolean, + override val new: Boolean, + override val group: Group, /** - * 由管理员操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByOperator( - override val origin: Boolean, - override val new: Boolean, - val operator: Member - ) : GroupMuteAllEvent() { - override val group: Group - get() = operator.group - } + val operator: Member? +) : GroupSettingChangeEvent, Packet +/** + * 群 "匿名聊天" 功能状态改变. 此事件广播前修改就已经完成. + */ +data class GroupAllowAnonymousChatEvent( + override val origin: Boolean, + override val new: Boolean, + override val group: Group, /** - * 由机器人操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByBot( - override val origin: Boolean, - override val new: Boolean, - override val group: Group - ) : GroupMuteAllEvent() -} + val operator: Member? +) : GroupSettingChangeEvent, Packet /** * 群 "坦白说" 功能状态改变. 此事件广播前修改就已经完成. */ -sealed class GroupAllowConfessTalkEvent : GroupSettingChangeEvent, BotPassiveEvent { +data class GroupAllowConfessTalkEvent( + override val origin: Boolean, + override val new: Boolean, + override val group: Group, /** - * 由管理员操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByOperator( - override val origin: Boolean, - override val new: Boolean, - val operator: Member - ) : GroupAllowConfessTalkEvent() { - override val group: Group - get() = operator.group - } - - /** - * 由机器人操作 - */ - data class ByBot( - override val origin: Boolean, - override val new: Boolean, - override val group: Group - ) : GroupAllowConfessTalkEvent() -} + val operator: Member? +) : GroupSettingChangeEvent, Packet /** * 群 "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成. */ -sealed class GroupAllowMemberInviteEvent : GroupSettingChangeEvent, BotPassiveEvent { +data class GroupAllowMemberInviteEvent( + override val origin: Boolean, + override val new: Boolean, + override val group: Group, /** - * 由管理员操作 + * 操作人. 为 null 时则是机器人操作 */ - data class ByOperator( - override val origin: Boolean, - override val new: Boolean, - val operator: Member - ) : GroupAllowMemberInviteEvent() { - override val group: Group - get() = operator.group - } - - /** - * 由机器人操作 - */ - data class ByBot( - override val origin: Boolean, - override val new: Boolean, - override val group: Group - ) : GroupAllowMemberInviteEvent() -} + val operator: Member? +) : GroupSettingChangeEvent, Packet // endregion @@ -284,22 +230,13 @@ sealed class MemberLeaveEvent : GroupMemberEvent { /** * 成员被踢出群. 成员不可能是机器人自己. */ - sealed class Kick : MemberLeaveEvent() { + data class Kick( + override val member: Member, /** - * 被管理员踢出 + * 操作人. 为 null 则是机器人操作 */ - data class ByOperator( - override val member: Member, - val operator: Member - ) : Kick(), BotPassiveEvent - - /** - * 被机器人踢出 - */ - data class ByBot( - override val member: Member - ) : Kick(), BotActiveEvent - } + val operator: Member? + ) : MemberLeaveEvent(), Packet /** * 成员主动离开 @@ -314,47 +251,24 @@ sealed class MemberLeaveEvent : GroupMemberEvent { /** * 群名片改动. 此事件广播前修改就已经完成. */ -sealed class MemberCardChangeEvent : GroupMemberEvent { +data class MemberCardChangeEvent( /** * 修改前 */ - abstract val origin: String + val origin: String, /** * 修改后 */ - abstract val new: String + val new: String, - abstract override val member: Member + override val member: Member, /** - * 由管理员修改 + * 操作人. 为 null 时则是机器人操作. 可能与 [member] 引用相同, 此时为群员自己修改. */ - data class ByOperator( - override val origin: String, - override val new: String, - override val member: Member, - val operator: Member - ) : MemberCardChangeEvent(), BotPassiveEvent - - /** - * 由 [Bot] 修改. 由 [Member.nameCard] - */ - data class ByBot( - override val origin: String, - override val new: String, - override val member: Member - ) : MemberCardChangeEvent(), BotActiveEvent - - /** - * 该成员自己修改 - */ - data class BySelf( - override val origin: String, - override val new: String, - override val member: Member - ) : MemberCardChangeEvent(), BotPassiveEvent -} + val operator: Member? +) : GroupMemberEvent /** * 群头衔改动. 一定为群主操作 @@ -385,7 +299,7 @@ data class MemberPermissionChangeEvent( override val member: Member, val origin: MemberPermission, val new: MemberPermission -) : GroupMemberEvent, BotPassiveEvent +) : GroupMemberEvent, BotPassiveEvent, Packet // endregion @@ -395,50 +309,25 @@ data class MemberPermissionChangeEvent( /** * 群成员被禁言事件. 操作人和被禁言的成员都不可能是机器人本人 */ -sealed class MemberMuteEvent : GroupMemberEvent { - abstract override val member: Member - - abstract val durationSeconds: Int - +data class MemberMuteEvent( + override val member: Member, + val durationSeconds: Int, /** - * 管理员禁言成员 + * 操作人. 为 null 则为机器人操作 */ - data class ByOperator( - override val member: Member, - override val durationSeconds: Int, - val operator: Member - ) : MemberMuteEvent(), BotPassiveEvent - - /** - * 机器人禁言成员. 通过 [Member.mute] 触发 - */ - data class ByBot( - override val member: Member, - override var durationSeconds: Int - ) : MemberMuteEvent(), BotActiveEvent -} + val operator: Member? +) : GroupMemberEvent, Packet /** * 群成员被取消禁言事件. 操作人和被禁言的成员都不可能是机器人本人 */ -sealed class MemberUnmuteEvent : GroupMemberEvent, BotPassiveEvent { - abstract override val member: Member - +data class MemberUnmuteEvent( + override val member: Member, /** - * 管理员禁言成员 + * 操作人. 为 null 则为机器人操作 */ - data class ByOperator( - override val member: Member, - val operator: Member - ) : MemberUnmuteEvent(), BotPassiveEvent - - /** - * 机器人禁言成员. 通过 [Member.unmute] 触发 - */ - data class ByBot( - override val member: Member - ) : MemberUnmuteEvent(), BotActiveEvent -} + val operator: Member? +) : GroupMemberEvent, Packet // endregion From a6276047e5019d725104823d41407f40eccbdeb5 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 12 Feb 2020 08:34:14 +0800 Subject: [PATCH 13/16] Update libraries --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index f455bbc88..cce0a8c34 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,12 +8,12 @@ kotlin.parallel.tasks.in.project=true kotlinVersion=1.3.61 # kotlin libraries serializationVersion=0.14.0 -coroutinesVersion=1.3.2 +coroutinesVersion=1.3.3 atomicFuVersion=0.14.1 kotlinXIoVersion=0.1.16 coroutinesIoVersion=0.1.16 # utility -ktorVersion=1.2.6 +ktorVersion=1.3.1 klockVersion=1.7.0 # gradle plugin protobufJavaVersion=3.10.0 \ No newline at end of file From 80a3a9a65ee2a372c895ebb7b49df92a50fa95d5 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 12 Feb 2020 09:04:25 +0800 Subject: [PATCH 14/16] Add shortcuts --- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index c4a1e5e8e..c9c41912c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName") +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE") package net.mamoe.mirai @@ -24,8 +24,11 @@ import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.network.BotNetworkHandler -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.WeakRef import net.mamoe.mirai.utils.io.transferTo +import net.mamoe.mirai.utils.toList /** * 机器人对象. 一个机器人实例登录一个 QQ 账号. @@ -186,6 +189,7 @@ abstract class Bot : CoroutineScope { @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this.toLong())")) fun Int.qq(): QQ = getFriend(this.toLong()) + @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this)")) fun Long.qq(): QQ = getFriend(this) @@ -200,4 +204,12 @@ abstract class Bot : CoroutineScope { download().use { input -> input.transferTo(output) } // endregion -} \ No newline at end of file +} + +inline fun Bot.containsFriend(id: Long): Boolean = this.qqs.contains(id) + +inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id) + +inline fun Bot.getFriendOrNull(id: Long): QQ? = this.qqs.getOrNull(id) + +inline fun Bot.getGroupOrNull(id: Long): Group? = this.groups.getOrNull(id) \ No newline at end of file From e33fea8a3fff748ad3761ceee4be1aafc6de1fdf Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 12 Feb 2020 09:07:40 +0800 Subject: [PATCH 15/16] Remove override --- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 17 +++++----------- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 20 ++++++++++++------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index 854c0bef1..ebc148ff3 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -12,7 +12,10 @@ package net.mamoe.mirai.qqandroid import kotlinx.io.core.ByteReadPacket import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotImpl -import net.mamoe.mirai.contact.* +import net.mamoe.mirai.contact.ContactList +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.filteringGetOrNull import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.data.Image @@ -40,12 +43,7 @@ internal abstract class QQAndroidBotBase constructor( override val uin: Long get() = client.uin override val qqs: ContactList = ContactList(LockFreeLinkedList()) - val selfQQ: QQ by lazy { QQ(uin) } - - override fun getFriend(id: Long): QQ { - if (id == uin) return selfQQ - return qqs.delegate[id] - } + override val selfQQ: QQ by lazy { QQ(uin) } override fun QQ(id: Long): QQ { return QQImpl(this as QQAndroidBot, coroutineContext, id) @@ -61,11 +59,6 @@ internal abstract class QQAndroidBotBase constructor( return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}") } - override fun getGroup(id: Long): Group { - return groups.delegate.getOrNull(id) - ?: throw NoSuchElementException("Can not found group with GroupCode=${id}") - } - override fun onEvent(event: BotEvent): Boolean { return firstLoginSucceed } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index c9c41912c..c87295985 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -17,10 +17,7 @@ import kotlinx.io.OutputStream import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.IoBuffer import kotlinx.io.core.use -import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.ContactList -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.network.BotNetworkHandler @@ -38,8 +35,8 @@ import net.mamoe.mirai.utils.toList * * @see Contact */ +@UseExperimental(MiraiInternalAPI::class) abstract class Bot : CoroutineScope { - @UseExperimental(MiraiInternalAPI::class) companion object { /** * 复制一份此时的 [Bot] 实例列表. @@ -75,6 +72,8 @@ abstract class Bot : CoroutineScope { // region contacts + abstract val selfQQ: QQ + /** * 机器人的好友列表. 它将与服务器同步更新 */ @@ -105,7 +104,11 @@ abstract class Bot : CoroutineScope { /** * 获取一个好友对象. 若没有这个好友, 则会抛出异常 [NoSuchElementException] */ - abstract fun getFriend(id: Long): QQ + fun getFriend(id: Long): QQ { + if (id == uin) return selfQQ + return qqs.delegate.getOrNull(id) + ?: throw NoSuchElementException("No such friend $id for bot ${this.uin}") + } /** * 构造一个 [QQ] 对象. 它持有对 [Bot] 的弱引用([WeakRef]). @@ -123,7 +126,10 @@ abstract class Bot : CoroutineScope { /** * 获取一个机器人加入的群. 若没有这个群, 则会抛出异常 [NoSuchElementException] */ - abstract fun getGroup(id: Long): Group + fun getGroup(id: Long): Group { + return groups.delegate.getOrNull(id) + ?: throw NoSuchElementException("No such group $id for bot ${this.uin}") + } // TODO 目前还不能构造群对象. 这将在以后支持 From 905d4ede9a3c525625d08593f992fbe19787f9d8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 12 Feb 2020 13:52:07 +0800 Subject: [PATCH 16/16] Fix build --- mirai-core-qqandroid/build.gradle.kts | 8 +- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 1 + .../net/mamoe/mirai/qqandroid/io/JceOutput.kt | 301 ------------------ .../net/mamoe/mirai/qqandroid/io/JceStruct.kt | 4 +- .../network/highway/HighwayHelper.kt | 3 +- .../qqandroid/network/http/HttpRequest.kt | 87 ----- .../androidPacketTests/clientToServer.kt | 1 + .../androidPacketTests/serverToClient.kt | 10 +- .../JceDecoderTest.kt | 6 +- mirai-core/build.gradle.kts | 33 +- .../mamoe/mirai/utils/ExternalImageAndroid.kt | 3 +- .../mirai/utils/DefaultCaptchaSolverJvm.kt | 4 +- .../net/mamoe/mirai/utils/ExternalImageJvm.kt | 3 +- mirai-demos/mirai-demo-android/build.gradle | 1 + 14 files changed, 42 insertions(+), 423 deletions(-) delete mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceOutput.kt delete mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt diff --git a/mirai-core-qqandroid/build.gradle.kts b/mirai-core-qqandroid/build.gradle.kts index 7afca1a66..20e38065b 100644 --- a/mirai-core-qqandroid/build.gradle.kts +++ b/mirai-core-qqandroid/build.gradle.kts @@ -93,10 +93,10 @@ kotlin { val androidTest by getting { dependencies { - api(kotlin("test", kotlinVersion)) - api(kotlin("test-junit", kotlinVersion)) - api(kotlin("test-annotations-common")) - api(kotlin("test-common")) + implementation(kotlin("test", kotlinVersion)) + implementation(kotlin("test-junit", kotlinVersion)) + implementation(kotlin("test-annotations-common")) + implementation(kotlin("test-common")) } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index ebc148ff3..d20b4aab9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -55,6 +55,7 @@ internal abstract class QQAndroidBotBase constructor( override val groups: ContactList = ContactList(LockFreeLinkedList()) + // internally visible only fun getGroupByUin(uin: Long): Group { return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}") } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceOutput.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceOutput.kt deleted file mode 100644 index a6c134eb8..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceOutput.kt +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2020 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.qqandroid.io - -import kotlinx.io.charsets.Charset -import kotlinx.io.core.* -import kotlin.experimental.or -import kotlin.reflect.KClass - -@PublishedApi -internal val CharsetGBK = Charset.forName("GBK") -@PublishedApi -internal val CharsetUTF8 = Charset.forName("UTF8") - -inline fun buildJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit): ByteReadPacket { - return JceOutput(stringCharset).apply(block).build() -} - -inline fun BytePacketBuilder.writeJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit) { - return this.writePacket(buildJcePacket(stringCharset, block)) -} - -fun jceStruct(tag: Int, struct: JceStruct): ByteArray{ - return buildJcePacket { - writeJceStruct(struct, tag) - }.readBytes() -} - -fun jceMap(tag: Int, vararg entries: Pair): ByteArray { - return buildJcePacket { - writeMap(mapOf(*entries), tag) - }.readBytes() -} - -/** - * - * From: com.qq.taf.jce.JceOutputStream - */ -@Suppress("unused", "MemberVisibilityCanBePrivate") -@UseExperimental(ExperimentalIoApi::class) -class JceOutput( - private val stringCharset: Charset = CharsetGBK -) { - private val output: BytePacketBuilder = BytePacketBuilder() - - fun build(): ByteReadPacket = output.build() - - fun close() = output.close() - fun flush() = output.flush() - - fun writeByte(v: Byte, tag: Int) { - if (v.toInt() == 0) { - writeHead(ZERO_TYPE, tag) - } else { - writeHead(BYTE, tag) - output.writeByte(v) - } - } - - fun writeDouble(v: Double, tag: Int) { - writeHead(DOUBLE, tag) - output.writeDouble(v) - } - - fun writeFloat(v: Float, tag: Int) { - writeHead(FLOAT, tag) - output.writeFloat(v) - } - - fun writeFully(src: ByteArray, tag: Int) { - writeHead(SIMPLE_LIST, tag) - writeHead(BYTE, 0) - writeInt(src.size, 0) - output.writeFully(src) - } - - fun writeFully(src: DoubleArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeDouble(it, 0) - } - } - - fun writeFully(src: FloatArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeFloat(it, 0) - } - } - - fun writeFully(src: IntArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeInt(it, 0) - } - } - - fun writeFully(src: LongArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeLong(it, 0) - } - } - - fun writeFully(src: ShortArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeShort(it, 0) - } - } - - fun writeFully(src: BooleanArray, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeBoolean(it, 0) - } - } - - fun writeFully(src: Array, tag: Int) { - writeHead(LIST, tag) - writeInt(src.size, 0) - src.forEach { - writeObject(it, 0) - } - } - - fun writeInt(v: Int, tag: Int) { - if (v in Short.MIN_VALUE..Short.MAX_VALUE) { - writeShort(v.toShort(), tag) - } else { - writeHead(INT, tag) - output.writeInt(v) - } - } - - fun writeLong(v: Long, tag: Int) { - if (v in Int.MIN_VALUE..Int.MAX_VALUE) { - writeInt(v.toInt(), tag) - } else { - writeHead(LONG, tag) - output.writeLong(v) - } - } - - fun writeShort(v: Short, tag: Int) { - if (v in Byte.MIN_VALUE..Byte.MAX_VALUE) { - writeByte(v.toByte(), tag) - } else { - writeHead(SHORT, tag) - output.writeShort(v) - } - } - - fun writeBoolean(v: Boolean, tag: Int) { - this.writeByte(if (v) 1 else 0, tag) - } - - fun writeString(v: String, tag: Int) { - val array = v.toByteArray(stringCharset) - if (array.size > 255) { - writeHead(STRING4, tag) - output.writeInt(array.size) - output.writeFully(array) - } else { - writeHead(STRING1, tag) - output.writeByte(array.size.toByte()) - output.writeFully(array) - } - } - - fun writeMap(map: Map, tag: Int) { - writeHead(MAP, tag) - if (map.isEmpty()) { - writeInt(0, 0) - } else { - writeInt(map.size, 0) - map.forEach { (key, value) -> - writeObject(key, 0) - writeObject(value, 1) - } - } - } - - fun writeCollection(collection: Collection<*>?, tag: Int) { - writeHead(LIST, tag) - if (collection == null || collection.isEmpty()) { - writeInt(0, 0) - } else { - writeInt(collection.size, 0) - collection.forEach { - writeObject(it, 0) - } - } - } - - fun writeJceStruct(v: JceStruct, tag: Int) { - writeHead(STRUCT_BEGIN, tag) - v.writeTo(this) - writeHead(STRUCT_END, 0) - } - - fun writeObject(v: T, tag: Int) { - when (v) { - is Byte -> writeByte(v, tag) - is Short -> writeShort(v, tag) - is Int -> writeInt(v, tag) - is Long -> writeLong(v, tag) - is Float -> writeFloat(v, tag) - is Double -> writeDouble(v, tag) - is JceStruct -> writeJceStruct(v, tag) - is ByteArray -> writeFully(v, tag) - is Collection<*> -> writeCollection(v, tag) - is Boolean -> writeBoolean(v, tag) - is Map<*, *> -> writeMap(v, tag) - is IntArray -> writeFully(v, tag) - is ShortArray -> writeFully(v, tag) - is BooleanArray -> writeFully(v, tag) - is LongArray -> writeFully(v, tag) - is FloatArray -> writeFully(v, tag) - is DoubleArray -> writeFully(v, tag) - is Array<*> -> writeFully(v, tag) - is String -> writeString(v, tag) - -// -// is ByteReadPacket -> ByteArrayPool.useInstance { -// v.readAvailable(it) -// writeFully(it, tag) -// } - else -> error("unsupported type: ${v.getClassName()}") - } - } - - fun write(v: Int, tag: Int) = writeInt(v, tag) - fun write(v: Byte, tag: Int) = writeByte(v, tag) - fun write(v: Short, tag: Int) = writeShort(v, tag) - fun write(v: Long, tag: Int) = writeLong(v, tag) - fun write(v: Float, tag: Int) = writeFloat(v, tag) - fun write(v: Double, tag: Int) = writeDouble(v, tag) - fun write(v: String, tag: Int) = writeString(v, tag) - fun write(v: Boolean, tag: Int) = writeBoolean(v, tag) - fun write(v: Collection<*>, tag: Int) = writeCollection(v, tag) - fun write(v: Map<*, *>, tag: Int) = writeMap(v, tag) - fun write(v: ByteArray, tag: Int) = writeFully(v, tag) - fun write(v: IntArray, tag: Int) = writeFully(v, tag) - fun write(v: BooleanArray, tag: Int) = writeFully(v, tag) - fun write(v: LongArray, tag: Int) = writeFully(v, tag) - fun write(v: ShortArray, tag: Int) = writeFully(v, tag) - fun write(v: Array<*>, tag: Int) = writeFully(v, tag) - fun write(v: FloatArray, tag: Int) = writeFully(v, tag) - fun write(v: DoubleArray, tag: Int) = writeFully(v, tag) - - @PublishedApi - internal companion object { - const val BYTE: Int = 0 - const val DOUBLE: Int = 5 - const val FLOAT: Int = 4 - const val INT: Int = 2 - const val JCE_MAX_STRING_LENGTH = 104857600 - const val LIST: Int = 9 - const val LONG: Int = 3 - const val MAP: Int = 8 - const val SHORT: Int = 1 - const val SIMPLE_LIST: Int = 13 - const val STRING1: Int = 6 - const val STRING4: Int = 7 - const val STRUCT_BEGIN: Int = 10 - const val STRUCT_END: Int = 11 - const val ZERO_TYPE: Int = 12 - - private fun Any?.getClassName(): KClass = if (this == null) Unit::class else this::class - } - - @PublishedApi - internal fun writeHead(type: Int, tag: Int) { - if (tag < 15) { - this.output.writeByte(((tag shl 4) or type).toByte()) - return - } - if (tag < 256) { - this.output.writeByte((type.toByte() or 0xF0.toByte())) - this.output.writeByte(tag.toByte()) - return - } - throw JceEncodeException("tag is too large: $tag") - } -} - -class JceEncodeException(message: String) : RuntimeException(message) \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt index 6cd990f9f..d1c78c177 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/JceStruct.kt @@ -9,6 +9,4 @@ package net.mamoe.mirai.qqandroid.io -interface JceStruct { - fun writeTo(output: JceOutput) = Unit -} \ No newline at end of file +interface JceStruct \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt index 84bfa6566..adc5b372e 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt @@ -16,7 +16,6 @@ import io.ktor.http.HttpStatusCode import io.ktor.http.URLProtocol import io.ktor.http.content.OutgoingContent import io.ktor.http.userAgent -import kotlinx.coroutines.io.ByteWriteChannel import kotlinx.io.core.Input import kotlinx.io.core.readAvailable import kotlinx.io.core.use @@ -64,7 +63,7 @@ internal suspend inline fun HttpClient.postImage( override val contentType: ContentType = ContentType.Image.Any override val contentLength: Long = inputSize - override suspend fun writeTo(channel: ByteWriteChannel) { + override suspend fun writeTo(channel: io.ktor.utils.io.ByteWriteChannel) { ByteArrayPool.useInstance { buffer: ByteArray -> var size: Int while (imageInput.readAvailable(buffer).also { size = it } != 0) { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt deleted file mode 100644 index 14fc74fd3..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2020 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.qqandroid.network.http - -import io.ktor.client.HttpClient -import io.ktor.client.request.get -import io.ktor.client.request.headers -import io.ktor.client.request.post -import io.ktor.client.response.HttpResponse -import io.ktor.http.URLProtocol -import io.ktor.http.setCookie -import io.ktor.http.userAgent -import kotlinx.coroutines.io.readRemaining -import kotlinx.io.core.readBytes -import net.mamoe.mirai.qqandroid.network.QQAndroidClient -import net.mamoe.mirai.utils.currentTimeMillis -import net.mamoe.mirai.utils.io.toUHexString - -/** - * 好像不需要了 - */ -object HttpRequest { - private lateinit var cookie: String -} - - -internal suspend fun HttpClient.getPTLoginCookies( - client: QQAndroidClient -): String { - //$"https://ssl.ptlogin2.qq.com/jump?pt_clientver=5593&pt_src=1&keyindex=9&ptlang=2052&clientuin={QQ}&clientkey={Util.ToHex(TXProtocol.BufServiceTicketHttp, "", "{0}")}&u1=https:%2F%2Fuser.qzone.qq.com%2F417085811%3FADUIN=417085811%26ADSESSION={Util.GetTimeMillis(DateTime.Now)}%26ADTAG=CLIENT.QQ.5593_MyTip.0%26ADPUBNO=26841&source=namecardhoverstar" - // "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441", - val res = post { - println(client.wLoginSigInfo.userStWebSig.data.toUHexString().replace(" ", "").toLowerCase()) - url { - protocol = URLProtocol.HTTPS - host = "ssl.ptlogin2.qq.com" - path( - "/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin=${client.uin}&clientkey=${client.wLoginSigInfo.userStWebSig.data.toUHexString().replace( - " ", - "" - )}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441&FADUIN=417085811&ADSESSION=${currentTimeMillis}&source=namecardhoverstar" - ) - } - headers { - userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36") - } - } - - println(res.status) - println(res.setCookie()) - println(res.content.readRemaining().readBytes().toUHexString()) - return "done"; -} - - -internal suspend fun HttpClient.getGroupList( - client: QQAndroidClient -): String { - // "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441", - val res = get { - url { - protocol = URLProtocol.HTTPS - host = "ssl.ptlogin2.qq.com" - path("jump") - parameters["pt_clientver"] = "5509" - parameters["pt_src"] = "1" - parameters["keyindex"] = "9" - parameters["u1"] = "http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441" - parameters["clientuin"] = client.uin.toString() - parameters["clientkey"] = client.wLoginSigInfo.userStWebSig.data.toUHexString() - } - headers { - userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36") - } - } - - println(res.status) - println(res.setCookie()) - return "done"; -} diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt index 9458b98e6..2233b8534 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt @@ -248,6 +248,7 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed val encryptedBody = readBytes((remaining - 1).toInt()) + @Suppress("NAME_SHADOWING") val decrypted = kotlin.runCatching { encryptedBody.decryptBy(encrypt).also { println("first by calculatedShareKey or sessionKey(method=7)") } }.getOrElse { diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt index 5d9797ab9..0baf4205c 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt @@ -75,7 +75,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) { val flag3 = readByte().toInt() - val uinAccount = readString(readInt() - 4)//uin + readString(readInt() - 4)//uin //debugPrint("remaining") @@ -163,17 +163,17 @@ private fun Map.getOrEmpty(key: Int): ByteArray { var randomKey: ByteArray = byteArrayOf() private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) { - val qq: Long readIoBuffer(readInt() - 4).withUse { check(readByte().toInt() == 2) this.discardExact(2) // 27 + 2 + body.size this.discardExact(2) // const, =8001 this.readUShort() // commandId this.readShort() // const, =0x0001 - qq = this.readUInt().toLong() + this.readUInt().toLong() // qq val encryptionMethod = this.readUShort().toInt() this.discardExact(1) // const = 0 + @Suppress("UNUSED_VARIABLE") val packet = when (encryptionMethod) { 4 -> { // peer public key, ECDH var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1) @@ -229,7 +229,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori commandName = readString(readInt() - 4) DebugLogger.warning("commandName=$commandName") - val unknown = readBytes(readInt() - 4) + readBytes(readInt() - 4) // unknown, sessionId? //if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}") check(readInt() == 0) @@ -278,7 +278,7 @@ private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP commandName = readString(readInt() - 4) DebugLogger.warning("commandName=$commandName") - val unknown = readBytes(readInt() - 4) + readBytes(readInt() - 4) // unknown //if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}") check(readInt() == 0) diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/net.mamoe.mirai.qqandroid.io.serialization/JceDecoderTest.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/net.mamoe.mirai.qqandroid.io.serialization/JceDecoderTest.kt index e3dc596a5..14ee4b490 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/net.mamoe.mirai.qqandroid.io.serialization/JceDecoderTest.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/net.mamoe.mirai.qqandroid.io.serialization/JceDecoderTest.kt @@ -9,6 +9,8 @@ package net.mamoe.mirai.qqandroid.io.serialization +/* + import kotlinx.io.core.readBytes import kotlinx.serialization.SerialId import kotlinx.serialization.Serializable @@ -310,4 +312,6 @@ class JceDecoderTest { OuterStruct(listOf(TestSimpleJceStruct(), TestSimpleJceStruct())).contentToString() ) } -} \ No newline at end of file +} + + */ \ No newline at end of file diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index b8b22ddbb..a75175266 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -61,13 +61,13 @@ kotlin { languageSettings.useExperimentalAnnotation("kotlin.Experimental") dependencies { - api(kotlin("stdlib", kotlinVersion)) - api(kotlin("serialization", kotlinVersion)) + implementation(kotlin("stdlib", kotlinVersion)) + implementation(kotlin("serialization", kotlinVersion)) - api("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion") - api(kotlinx("io", kotlinXIoVersion)) - api(kotlinx("coroutines-io", coroutinesIoVersion)) - api(kotlinx("coroutines-core", coroutinesVersion)) + implementation("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion") + implementation(kotlinx("io", kotlinXIoVersion)) + implementation(kotlinx("coroutines-io", coroutinesIoVersion)) + implementation(kotlinx("coroutines-core", coroutinesVersion)) } } commonMain { @@ -90,8 +90,8 @@ kotlin { } commonTest { dependencies { - api(kotlin("test-annotations-common")) - api(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation(kotlin("test-common")) //runtimeOnly(files("build/classes/kotlin/metadata/test")) // classpath is not properly set by IDE } @@ -102,6 +102,8 @@ kotlin { dependencies { api(kotlin("reflect", kotlinVersion)) + api(kotlinx("io", kotlinXIoVersion)) + api(kotlinx("io-jvm", kotlinXIoVersion)) api(kotlinx("serialization-runtime", serializationVersion)) api(kotlinx("coroutines-android", coroutinesVersion)) @@ -111,10 +113,10 @@ kotlin { val androidTest by getting { dependencies { - api(kotlin("test", kotlinVersion)) - api(kotlin("test-junit", kotlinVersion)) - api(kotlin("test-annotations-common")) - api(kotlin("test-common")) + implementation(kotlin("test", kotlinVersion)) + implementation(kotlin("test-junit", kotlinVersion)) + implementation(kotlin("test-annotations-common")) + implementation(kotlin("test-common")) } } } @@ -128,6 +130,9 @@ kotlin { api(ktor("client-core-jvm", ktorVersion)) api(kotlinx("io-jvm", kotlinXIoVersion)) api(kotlinx("serialization-runtime", serializationVersion)) + api(kotlinx("coroutines-io", coroutinesIoVersion)) + api(kotlinx("coroutines-io-jvm", coroutinesIoVersion)) + api(kotlinx("io-jvm", coroutinesIoVersion)) api("org.bouncycastle:bcprov-jdk15on:1.64") runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE @@ -136,8 +141,8 @@ kotlin { val jvmTest by getting { dependencies { - api(kotlin("test", kotlinVersion)) - api(kotlin("test-junit", kotlinVersion)) + implementation(kotlin("test", kotlinVersion)) + implementation(kotlin("test-junit", kotlinVersion)) implementation("org.pcap4j:pcap4j-distribution:1.8.2") runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/ExternalImageAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/ExternalImageAndroid.kt index d31615b83..a880b7fcd 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/ExternalImageAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/ExternalImageAndroid.kt @@ -12,7 +12,6 @@ package net.mamoe.mirai.utils import android.graphics.BitmapFactory -import io.ktor.util.asStream import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext import kotlinx.io.core.Input @@ -100,7 +99,7 @@ suspend fun InputStream.suspendToExternalImage(): ExternalImage = withContext(IO fun Input.toExternalImage(): ExternalImage { val file = createTempFile().apply { deleteOnExit() } file.outputStream().asOutput().use { - this.asStream().asInput().copyTo(it) + this.copyTo(it) } return file.toExternalImage() } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt index f22465eb0..ec265bd0e 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt @@ -9,11 +9,11 @@ package net.mamoe.mirai.utils -import io.ktor.util.cio.use import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.io.ByteWriteChannel +import kotlinx.coroutines.io.close import kotlinx.coroutines.io.jvm.nio.copyTo import kotlinx.coroutines.io.reader import kotlinx.coroutines.sync.Mutex @@ -44,7 +44,7 @@ internal class DefaultLoginSolver : LoginSolver() { tempFile.createNewFile() bot.logger.info("需要图片验证码登录, 验证码为 4 字母") try { - tempFile.writeChannel().use { writeFully(data) } + tempFile.writeChannel().apply { writeFully(data); close() } bot.logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}") } catch (e: Exception) { bot.logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片") diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/ExternalImageJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/ExternalImageJvm.kt index 1391affa3..e8318e410 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/ExternalImageJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/ExternalImageJvm.kt @@ -11,7 +11,6 @@ package net.mamoe.mirai.utils -import io.ktor.util.asStream import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext import kotlinx.io.core.Input @@ -132,7 +131,7 @@ suspend inline fun InputStream.suspendToExternalImage(): ExternalImage = withCon fun Input.toExternalImage(): ExternalImage { val file = createTempFile().apply { deleteOnExit() } file.outputStream().asOutput().use { - this.asStream().asInput().copyTo(it) + this.copyTo(it) } return file.toExternalImage() } diff --git a/mirai-demos/mirai-demo-android/build.gradle b/mirai-demos/mirai-demo-android/build.gradle index fc6a5a130..0cadf3aa8 100644 --- a/mirai-demos/mirai-demo-android/build.gradle +++ b/mirai-demos/mirai-demo-android/build.gradle @@ -31,6 +31,7 @@ android { exclude 'META-INF/ktor-http-cio.kotlin_module' exclude 'META-INF/ktor-client-core.kotlin_module' exclude "META-INF/kotlinx-serialization-runtime.kotlin_module" + exclude 'META-INF/ktor-io.kotlin_module' } }