mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-28 13:10:13 +08:00
Add corresponding events
This commit is contained in:
parent
8bc59820bc
commit
4ddfc0b509
@ -32,6 +32,7 @@ Mirai 在 JVM 平台采用插件模式运行,同时提供独立的跨平台核
|
||||
- Android客户端上线/下线(10/18)
|
||||
- 上传并发送好友/群图片(10/21, 10/26)
|
||||
- 群员权限改变(11/2)
|
||||
- 发起会话(11/2)
|
||||
|
||||
计划中: 添加好友
|
||||
|
||||
|
@ -1,9 +1,18 @@
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.event.Cancellable
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
|
||||
|
||||
abstract class BotEvent(val bot: Bot) : Event()
|
||||
|
||||
class BotLoginSucceedEvent(bot: Bot) : BotEvent(bot)
|
||||
|
||||
/**
|
||||
* 上传好友图片时, 服务器返回好友图片 ID 事件.
|
||||
*
|
||||
* 在这之后图片将会被上传到服务器.
|
||||
*/
|
||||
class FriendImageIdObtainedEvent(bot: Bot, val imageId: ImageId) : BotEvent(bot), Cancellable
|
@ -1,12 +1,17 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.message.Message
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
import net.mamoe.mirai.utils.OnlineStatus
|
||||
|
||||
|
||||
abstract class FriendEvent(bot: Bot, val sender: QQ) : BotEvent(bot)
|
||||
/**
|
||||
* 好友事件
|
||||
*/
|
||||
sealed class FriendEvent(bot: Bot, val sender: QQ) : BotEvent(bot)
|
||||
|
||||
/**
|
||||
* 接受好友消息事件
|
||||
@ -20,3 +25,13 @@ class FriendMessageEvent(bot: Bot, sender: QQ, val message: MessageChain) : Frie
|
||||
|
||||
suspend inline fun reply(message: MessageChain) = sender.sendMessage(message)//shortcut
|
||||
}
|
||||
|
||||
/**
|
||||
* 好友发起会话事件. 即好友在消息输入框内输入任意内容.
|
||||
*/
|
||||
class FriendConversationInitializedEvent(bot: Bot, sender: QQ) : FriendEvent(bot, sender)
|
||||
|
||||
/**
|
||||
* 好友在线状态改变事件
|
||||
*/
|
||||
class FriendOnlineStatusChangedEvent(bot: Bot, sender: QQ, val newStatus: OnlineStatus) : FriendEvent(bot, sender)
|
@ -1,3 +1,5 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.mamoe.mirai.event.events
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
@ -10,8 +12,9 @@ import net.mamoe.mirai.network.protocol.tim.packet.event.SenderPermission
|
||||
|
||||
abstract class GroupEvent(bot: Bot, val group: Group) : BotEvent(bot)
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
/**
|
||||
* 群消息
|
||||
*/
|
||||
class GroupMessageEvent(
|
||||
bot: Bot,
|
||||
group: Group,
|
||||
@ -26,3 +29,24 @@ class GroupMessageEvent(
|
||||
|
||||
suspend inline fun reply(message: MessageChain) = group.sendMessage(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 群成员权限改变
|
||||
*/
|
||||
class MemberPermissionChangedEvent(
|
||||
bot: Bot,
|
||||
group: Group,
|
||||
val member: QQ,
|
||||
val kind: Kind
|
||||
) : GroupEvent(bot, group) {
|
||||
enum class Kind {
|
||||
/**
|
||||
* 变成管理员
|
||||
*/
|
||||
BECOME_OPERATOR,
|
||||
/**
|
||||
* 不再是管理员
|
||||
*/
|
||||
NO_LONGER_OPERATOR,
|
||||
} // TODO: 2019/11/2 变成群主的情况
|
||||
}
|
@ -8,27 +8,45 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
|
||||
/* Abstract */
|
||||
|
||||
|
||||
sealed class PacketEvent<out P : Packet>(bot: Bot, open val packet: P) : BotEvent(bot)
|
||||
/**
|
||||
* 数据包相关事件
|
||||
*
|
||||
* @param P 指代数据包的类型. 这个类型是 **invariant(不变的)**
|
||||
*/
|
||||
sealed class PacketEvent<P : Packet>(bot: Bot, open val packet: P) : BotEvent(bot)
|
||||
|
||||
|
||||
/* Client to Server */
|
||||
|
||||
sealed class ClientPacketEvent(bot: Bot, packet: OutgoingPacket) : PacketEvent<OutgoingPacket>(bot, packet)
|
||||
/**
|
||||
* 发送给服务器的数据包的相关事件
|
||||
*/
|
||||
sealed class OutgoingPacketEvent(bot: Bot, packet: OutgoingPacket) : PacketEvent<OutgoingPacket>(bot, packet)
|
||||
|
||||
/**
|
||||
* 包已发送. 不可被取消
|
||||
* 包已发送, 此时包数据已完全发送至服务器, 且包已被关闭.
|
||||
*
|
||||
* 不可被取消
|
||||
*/
|
||||
class PacketSentEvent(bot: Bot, packet: OutgoingPacket) : ClientPacketEvent(bot, packet)
|
||||
class PacketSentEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet)
|
||||
|
||||
/**
|
||||
* 包发送前. 可被取消
|
||||
* 包发送前, 此时包数据已经编码完成.
|
||||
*
|
||||
* 可被取消
|
||||
*/
|
||||
class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : ClientPacketEvent(bot, packet), Cancellable
|
||||
class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet), Cancellable
|
||||
|
||||
|
||||
/* Server to Client */
|
||||
|
||||
sealed class ServerPacketEvent<out P : ServerPacket>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
|
||||
/**
|
||||
* 来自服务器的数据包的相关事件
|
||||
*/
|
||||
sealed class ServerPacketEvent<P : ServerPacket>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
|
||||
|
||||
class ServerPacketReceivedEvent(bot: Bot, packet: ServerPacket) : ServerPacketEvent<ServerPacket>(bot, packet)
|
||||
/**
|
||||
* 服务器数据包接收事件. 此时包已经解密完成.
|
||||
*/
|
||||
class ServerPacketReceivedEvent<P : ServerPacket>(bot: Bot, packet: P) : ServerPacketEvent<P>(bot, packet),
|
||||
Cancellable
|
@ -186,8 +186,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
|
||||
private suspend inline fun <reified P : ServerPacket> expectPacket(): CompletableDeferred<P> {
|
||||
val receiving = CompletableDeferred<P>()
|
||||
subscribe<ServerPacketReceivedEvent> {
|
||||
val receiving = CompletableDeferred<P>(coroutineContext[Job])
|
||||
subscribe<ServerPacketReceivedEvent<*>> {
|
||||
if (it.packet is P && it.bot === bot) {
|
||||
receiving.complete(it.packet)
|
||||
ListeningStatus.STOPPED
|
||||
|
@ -29,14 +29,8 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
|
||||
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
override suspend fun onPacketReceived(packet: ServerPacket) = with(session) {
|
||||
override suspend fun onPacketReceived(packet: ServerPacket): Unit = with(session) {
|
||||
when (packet) {
|
||||
//is AddFriendPacket.Response -> {
|
||||
// this.uploadImageSessions.forEach {
|
||||
// it.onPacketReceived(packet)
|
||||
// }
|
||||
//}
|
||||
|
||||
is RequestSKeyPacket.Response -> {
|
||||
sKey = packet.sKey
|
||||
cookies = "uin=o$qqAccount;skey=$sKey;"
|
||||
|
@ -3,9 +3,9 @@ package net.mamoe.mirai.network.protocol.tim.handler
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.GroupId
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.contact.groupId
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.FriendMessageEvent
|
||||
import net.mamoe.mirai.event.events.GroupMessageEvent
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.getGroup
|
||||
import net.mamoe.mirai.getQQ
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
@ -13,12 +13,10 @@ import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.distributePacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.FriendOnlineStatusChangedPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.SendFriendMessagePacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.SendGroupMessagePacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessageEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.GroupMessageEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.IgnoredServerEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerGroupUploadFileEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.*
|
||||
import net.mamoe.mirai.network.qqAccount
|
||||
|
||||
/**
|
||||
@ -37,35 +35,27 @@ class EventPacketHandler(session: BotSession) : PacketHandler(session) {
|
||||
}
|
||||
|
||||
is FriendMessageEventPacket -> {
|
||||
if (!packet.isPrevious) {
|
||||
FriendMessageEvent(bot, bot.getQQ(packet.qq), packet.message).broadcast()
|
||||
}
|
||||
if (!packet.isPrevious) FriendMessageEvent(bot, bot.getQQ(packet.qq), packet.message).broadcast()
|
||||
}
|
||||
|
||||
is GroupMessageEventPacket -> {
|
||||
if (packet.qq == bot.account.id) return
|
||||
|
||||
GroupMessageEvent(
|
||||
bot,
|
||||
group = bot.getGroup(GroupId(packet.groupNumber)),
|
||||
sender = bot.getQQ(packet.qq),
|
||||
message = packet.message,
|
||||
senderName = packet.senderName,
|
||||
senderPermission = packet.senderPermission
|
||||
bot, bot.getGroup(GroupId(packet.groupNumber)), bot.getQQ(packet.qq), packet.message, packet.senderPermission, packet.senderName
|
||||
).broadcast()
|
||||
}
|
||||
|
||||
is FriendConversationInitializedEventPacket -> FriendConversationInitializedEvent(bot, bot.getQQ(packet.qq)).broadcast()
|
||||
is FriendOnlineStatusChangedPacket -> FriendOnlineStatusChangedEvent(bot, bot.getQQ(packet.qq), packet.status).broadcast()
|
||||
is FriendImageIdRequestPacket.Response -> packet.imageId?.let { FriendImageIdObtainedEvent(bot, it) }
|
||||
|
||||
is GroupMemberPermissionChangedEventPacket -> MemberPermissionChangedEvent(
|
||||
bot, bot.getGroup(packet.groupId.groupId()), bot.getQQ(packet.qq), packet.kind
|
||||
).broadcast()
|
||||
|
||||
|
||||
is FriendOnlineStatusChangedPacket.Encrypted -> distributePacket(packet.decrypt(sessionKey))
|
||||
is FriendOnlineStatusChangedPacket -> {
|
||||
//TODO
|
||||
}
|
||||
|
||||
is IgnoredServerEventPacket -> {
|
||||
|
||||
}
|
||||
else -> {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "unused")
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet
|
||||
|
||||
import net.mamoe.mirai.event.Event
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
/**
|
||||
* 包 ID. 除特殊外, [OutgoingPacketBuilder] 都需要这个注解来指定包 ID.
|
||||
*/
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class AnnotatedId(
|
||||
val id: KnownPacketId
|
||||
)
|
||||
|
||||
inline val AnnotatedId.value: UShort get() = id.value
|
||||
|
||||
|
||||
/**
|
||||
* 标记这个包对应的事件.
|
||||
* 这个注解应该被标记在 [ServerPacket] 上
|
||||
*/
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class CorrespondingEvent(
|
||||
val eventClass: KClass<out Event>
|
||||
)
|
||||
|
||||
/**
|
||||
* 版本信息
|
||||
*/
|
||||
@MustBeDocumented
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
internal annotation class PacketVersion(val date: String, val timVersion: String)
|
||||
|
||||
/**
|
||||
* 带有这个注解的 [Packet], 将不会被记录在 log 中.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class NoLog
|
@ -11,8 +11,6 @@ import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* 好友在线状态改变
|
||||
*
|
||||
* TODO 真的是在线状态改变么
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE)
|
||||
class FriendOnlineStatusChangedPacket(input: ByteReadPacket) : ServerPacket(input) {
|
||||
|
@ -37,17 +37,6 @@ val Packet.idHexString: String get() = (packetId.value.toInt().shl(16) or sequen
|
||||
|
||||
// region Packet id
|
||||
|
||||
/**
|
||||
* 包 ID
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class AnnotatedId(
|
||||
val id: KnownPacketId
|
||||
)
|
||||
|
||||
inline val AnnotatedId.value: UShort get() = id.value
|
||||
|
||||
/**
|
||||
* 通过 [value] 匹配一个 [KnownPacketId], 无匹配则返回一个 [UnknownPacketId].
|
||||
*/
|
||||
@ -110,15 +99,6 @@ enum class KnownPacketId(override inline val value: UShort, internal inline val
|
||||
|
||||
// region Internal utils
|
||||
|
||||
/**
|
||||
* 版本信息
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@MustBeDocumented
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
internal annotation class PacketVersion(val date: String, val timVersion: String)
|
||||
|
||||
private object PacketNameFormatter {
|
||||
private var longestNameLength: Int = 43
|
||||
fun adjustName(name: String): String =
|
||||
@ -160,13 +140,6 @@ private object IgnoreIdListInclude : List<String> by listOf(
|
||||
"RefVolatile"
|
||||
)
|
||||
|
||||
/**
|
||||
* 带有这个注解的 [Packet], 将不会被记录在 log 中.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class NoLog
|
||||
|
||||
/**
|
||||
* 这个方法会翻倍内存占用, 考虑修改.
|
||||
*/
|
||||
|
@ -10,6 +10,7 @@ import io.ktor.http.userAgent
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.event.events.FriendImageIdObtainedEvent
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
@ -254,6 +255,7 @@ object FriendImageIdRequestPacket : OutgoingPacketBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
@CorrespondingEvent(FriendImageIdObtainedEvent::class)
|
||||
@AnnotatedId(KnownPacketId.FRIEND_IMAGE_ID)
|
||||
@PacketVersion(date = "2019.11.1", timVersion = "2.3.2.21173")
|
||||
class Response(input: ByteReadPacket) : ResponsePacket(input) {
|
||||
|
@ -5,8 +5,12 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUInt
|
||||
import net.mamoe.mirai.event.events.FriendConversationInitializedEvent
|
||||
import net.mamoe.mirai.event.events.MemberPermissionChangedEvent
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.CorrespondingEvent
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
|
||||
import net.mamoe.mirai.utils.io.readString
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
/**
|
||||
@ -32,30 +36,36 @@ class GroupMemberNickChangedEventPacket(input: ByteReadPacket, eventIdentity: Ev
|
||||
override fun decode() {
|
||||
// GroupId VarInt
|
||||
// 00 00 00 08 00 0A 00 04 01 00 00 00 22 96 29 7B 01 01 00 00 F3 66 00 00 00 05 00 00 00 EE 00 00 00 05
|
||||
// ? 数据中没有哪个人的昵称改变了
|
||||
// TODO ? 数据中没有哪个人的昵称改变了
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 好友发起会话, 即在输入框输入了任意内容.
|
||||
*/
|
||||
@CorrespondingEvent(FriendConversationInitializedEvent::class)
|
||||
@PacketVersion(date = "2019.11.2", timVersion = "2.3.2.21173")
|
||||
class GroupMemberPermissionChangedPacket internal constructor(
|
||||
class FriendConversationInitializedEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) :
|
||||
ServerEventPacket(input, eventIdentity) {
|
||||
var qq: UInt by Delegates.notNull()
|
||||
|
||||
// 00 00 00 00 3E 03 3F A2 00
|
||||
override fun decode() = with(input) {
|
||||
discardExact(4)// 00 00 00 00
|
||||
qq = readUInt()
|
||||
}
|
||||
}
|
||||
|
||||
@CorrespondingEvent(MemberPermissionChangedEvent::class)
|
||||
@PacketVersion(date = "2019.11.2", timVersion = "2.3.2.21173")
|
||||
class GroupMemberPermissionChangedEventPacket internal constructor(
|
||||
input: ByteReadPacket,
|
||||
eventIdentity: EventPacketIdentity
|
||||
) :
|
||||
ServerEventPacket(input, eventIdentity) {
|
||||
val groupId: UInt get() = eventIdentity.from
|
||||
var qq: UInt = 0u
|
||||
lateinit var kind: Kind
|
||||
|
||||
enum class Kind {
|
||||
/**
|
||||
* 变成管理员
|
||||
*/
|
||||
BECOME_OPERATOR,
|
||||
/**
|
||||
* 不再是管理员
|
||||
*/
|
||||
NO_LONGER_OPERATOR,
|
||||
} // TODO: 2019/11/2 变成群主的情况
|
||||
lateinit var kind: MemberPermissionChangedEvent.Kind
|
||||
|
||||
override fun decode(): Unit = with(input) {
|
||||
// 群里一个人变成管理员:
|
||||
@ -65,8 +75,8 @@ class GroupMemberPermissionChangedPacket internal constructor(
|
||||
discardExact(remaining - 5)
|
||||
qq = readUInt()
|
||||
kind = when (readByte().toInt()) {
|
||||
0x00 -> Kind.NO_LONGER_OPERATOR
|
||||
0x01 -> Kind.BECOME_OPERATOR
|
||||
0x00 -> MemberPermissionChangedEvent.Kind.NO_LONGER_OPERATOR
|
||||
0x01 -> MemberPermissionChangedEvent.Kind.BECOME_OPERATOR
|
||||
else -> {
|
||||
error("Could not determine permission change kind")
|
||||
}
|
||||
|
@ -58,21 +58,17 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
|
||||
}
|
||||
}
|
||||
0x002Du -> ServerGroupUploadFileEventPacket(input, eventIdentity)
|
||||
|
||||
0x002Cu -> GroupMemberPermissionChangedPacket(input, eventIdentity)
|
||||
|
||||
0x002Cu -> GroupMemberPermissionChangedEventPacket(input, eventIdentity)
|
||||
/*
|
||||
*
|
||||
inline GROUP_MEMBER_NICK_CHANGED(0x002Fu, null),
|
||||
inline GROUP_MEMBER_PERMISSION_CHANGED(0x002Cu, null),
|
||||
|
||||
*/
|
||||
|
||||
0x0052u -> GroupMessageEventPacket(input, eventIdentity)
|
||||
|
||||
0x00A6u -> FriendMessageEventPacket(input, eventIdentity)
|
||||
0x0079u -> FriendConversationInitializedEventPacket(input, eventIdentity)
|
||||
|
||||
0x0079u,
|
||||
0x0210u // "对方正在输入..."
|
||||
-> IgnoredServerEventPacket(input, eventIdentity)
|
||||
|
||||
@ -125,7 +121,7 @@ class IgnoredServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacket
|
||||
* Unknown event
|
||||
*/
|
||||
class UnknownServerEventPacket(
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@Suppress("MemberVisibilityCanBePrivate")// 让它能被日志记录
|
||||
val eventId: ByteArray,
|
||||
private val showData: Boolean = false,
|
||||
input: ByteReadPacket,
|
||||
|
Loading…
Reference in New Issue
Block a user