mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 09:50:16 +08:00
Remove PacketHandler
This commit is contained in:
parent
afd87826b8
commit
76e6e37c38
@ -5,9 +5,8 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancelChildren
|
import kotlinx.coroutines.cancelChildren
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter
|
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler
|
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.handler.*
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.login.HeartbeatPacket
|
import net.mamoe.mirai.network.protocol.tim.packet.login.HeartbeatPacket
|
||||||
@ -18,16 +17,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务.
|
* Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务.
|
||||||
* [BotNetworkHandler] 是全异步和线程安全的.
|
* [BotNetworkHandler] 是线程安全的.
|
||||||
*
|
|
||||||
* [BotNetworkHandler] 由 2 个模块构成:
|
|
||||||
* - [BotSocketAdapter]: 处理数据包底层的发送([ByteArray])
|
|
||||||
* - [PacketHandler]: 制作 [OutgoingPacket] 并传递给 [BotSocketAdapter] 发送; 分析 [Packet] 并处理
|
|
||||||
*
|
|
||||||
* 其中, [PacketHandler] 由 3 个子模块构成:
|
|
||||||
* - [LoginHandler] 处理 sendTouch/login/verification code 相关
|
|
||||||
* - [ActionPacketHandler] 处理动作相关(踢人/加入群/好友列表等)
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* NetworkHandler 实现接口 [CoroutineScope]
|
* NetworkHandler 实现接口 [CoroutineScope]
|
||||||
* 即 [BotNetworkHandler] 自己就是作用域.
|
* 即 [BotNetworkHandler] 自己就是作用域.
|
||||||
@ -50,14 +40,7 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : CoroutineScope {
|
|||||||
|
|
||||||
val supervisor get() = SupervisorJob()
|
val supervisor get() = SupervisorJob()
|
||||||
|
|
||||||
/**
|
val session: BotSession
|
||||||
* 得到 [PacketHandler].
|
|
||||||
* `get(EventPacketHandler)` 返回 [EventPacketHandler]
|
|
||||||
* `get(ActionPacketHandler)` 返回 [ActionPacketHandler].
|
|
||||||
*
|
|
||||||
* 这个方法在 [PacketHandlerList] 中实现
|
|
||||||
*/
|
|
||||||
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
|
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
|
||||||
|
@ -15,7 +15,6 @@ import net.mamoe.mirai.message.Image
|
|||||||
import net.mamoe.mirai.message.ImageId0x03
|
import net.mamoe.mirai.message.ImageId0x03
|
||||||
import net.mamoe.mirai.message.ImageId0x06
|
import net.mamoe.mirai.message.ImageId0x06
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
|
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
|
||||||
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
|
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||||
@ -65,29 +64,29 @@ abstract class BotSessionBase(
|
|||||||
val socket: DataPacketSocketAdapter,
|
val socket: DataPacketSocketAdapter,
|
||||||
val NetworkScope: CoroutineScope
|
val NetworkScope: CoroutineScope
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web api 使用
|
* Web api 使用
|
||||||
*/
|
*/
|
||||||
lateinit var cookies: String
|
val cookies: String get() = _cookies
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web api 使用
|
* Web api 使用
|
||||||
*/
|
*/
|
||||||
val sKey: String get() = _sKey
|
val sKey: String get() = _sKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web api 使用
|
||||||
|
*/
|
||||||
|
val gtk: Int get() = _gtk
|
||||||
|
|
||||||
|
|
||||||
@Suppress("PropertyName")
|
@Suppress("PropertyName")
|
||||||
internal var _sKey: String = ""
|
internal var _sKey: String = ""
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
_gtk = getGTK(value)
|
_gtk = getGTK(value)
|
||||||
}
|
}
|
||||||
|
internal lateinit var _cookies: String
|
||||||
/**
|
|
||||||
* Web api 使用
|
|
||||||
*/
|
|
||||||
val gtk: Int get() = _gtk
|
|
||||||
|
|
||||||
private var _gtk: Int = 0
|
private var _gtk: Int = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,12 +162,6 @@ abstract class BotSessionBase(
|
|||||||
inline val BotSession.isOpen: Boolean get() = socket.isOpen
|
inline val BotSession.isOpen: Boolean get() = socket.isOpen
|
||||||
inline val BotSession.qqAccount: UInt get() = bot.account.id
|
inline val BotSession.qqAccount: UInt get() = bot.account.id
|
||||||
|
|
||||||
/**
|
|
||||||
* 取得 [BotNetworkHandler] 的 [BotSession].
|
|
||||||
* 实际上是一个捷径.
|
|
||||||
*/
|
|
||||||
val BotNetworkHandler<*>.session: BotSession get() = this[ActionPacketHandler].session
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取得 [BotNetworkHandler] 的 sessionKey.
|
* 取得 [BotNetworkHandler] 的 sessionKey.
|
||||||
* 实际上是一个捷径.
|
* 实际上是一个捷径.
|
||||||
|
@ -15,10 +15,10 @@ import net.mamoe.mirai.event.events.PacketSentEvent
|
|||||||
import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
|
import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
|
||||||
import net.mamoe.mirai.network.BotNetworkHandler
|
import net.mamoe.mirai.network.BotNetworkHandler
|
||||||
import net.mamoe.mirai.network.BotSession
|
import net.mamoe.mirai.network.BotSession
|
||||||
import net.mamoe.mirai.network.protocol.tim.handler.*
|
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
|
||||||
|
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.login.*
|
import net.mamoe.mirai.network.protocol.tim.packet.login.*
|
||||||
import net.mamoe.mirai.network.session
|
|
||||||
import net.mamoe.mirai.qqAccount
|
import net.mamoe.mirai.qqAccount
|
||||||
import net.mamoe.mirai.utils.BotConfiguration
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.OnlineStatus
|
import net.mamoe.mirai.utils.OnlineStatus
|
||||||
@ -40,7 +40,7 @@ internal expect val NetworkDispatcher: CoroutineDispatcher
|
|||||||
* @see BotNetworkHandler
|
* @see BotNetworkHandler
|
||||||
*/
|
*/
|
||||||
internal class TIMBotNetworkHandler internal constructor(coroutineContext: CoroutineContext, override inline val bot: Bot) :
|
internal class TIMBotNetworkHandler internal constructor(coroutineContext: CoroutineContext, override inline val bot: Bot) :
|
||||||
BotNetworkHandler<TIMBotNetworkHandler.BotSocketAdapter>, PacketHandlerList(), CoroutineScope {
|
BotNetworkHandler<TIMBotNetworkHandler.BotSocketAdapter>, CoroutineScope {
|
||||||
|
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext =
|
override val coroutineContext: CoroutineContext =
|
||||||
@ -94,13 +94,11 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
|
|
||||||
internal var loginResult: CompletableDeferred<LoginResult> = CompletableDeferred()
|
internal var loginResult: CompletableDeferred<LoginResult> = CompletableDeferred()
|
||||||
|
|
||||||
|
override lateinit var session: BotSession
|
||||||
|
|
||||||
//private | internal
|
//private | internal
|
||||||
private fun onLoggedIn() {
|
private fun onLoggedIn() {
|
||||||
require(size == 0) { "Already logged in" }
|
session = BotSession(sessionKey, socket)
|
||||||
val session = BotSession(sessionKey, socket)
|
|
||||||
|
|
||||||
add(ActionPacketHandler(session).asNode(ActionPacketHandler))
|
|
||||||
bot.logger.info("Successfully logged in")
|
bot.logger.info("Successfully logged in")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,10 +120,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
this.loginResult.join()
|
this.loginResult.join()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.forEach {
|
|
||||||
it.instance.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.socket.close()
|
this.socket.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +132,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
|
|
||||||
override val isOpen: Boolean get() = channel.isOpen
|
override val isOpen: Boolean get() = channel.isOpen
|
||||||
|
|
||||||
private lateinit var loginHandler: LoginHandler
|
private var loginHandler: LoginHandler? = null
|
||||||
|
|
||||||
private suspend fun processReceive() {
|
private suspend fun processReceive() {
|
||||||
while (channel.isOpen) {
|
while (channel.isOpen) {
|
||||||
@ -186,7 +180,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
|
|
||||||
val packet = try {
|
val packet = try {
|
||||||
with(id.factory) {
|
with(id.factory) {
|
||||||
loginHandler.provideDecrypter(id.factory)
|
loginHandler!!.provideDecrypter(id.factory)
|
||||||
.decrypt(input)
|
.decrypt(input)
|
||||||
.decode(id, sequenceId, this@TIMBotNetworkHandler)
|
.decode(id, sequenceId, this@TIMBotNetworkHandler)
|
||||||
}
|
}
|
||||||
@ -205,7 +199,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal suspend fun resendTouch(): LoginResult /* = coroutineScope */ {
|
internal suspend fun resendTouch(): LoginResult /* = coroutineScope */ {
|
||||||
if (::loginHandler.isInitialized) loginHandler.close()
|
loginHandler?.close()
|
||||||
|
|
||||||
loginHandler = LoginHandler(configuration)
|
loginHandler = LoginHandler(configuration)
|
||||||
|
|
||||||
@ -265,11 +259,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// They should be called in sequence because packet is lock-free
|
loginHandler?.onPacketReceived(packet)
|
||||||
loginHandler.onPacketReceived(packet)
|
|
||||||
this@TIMBotNetworkHandler.forEach {
|
|
||||||
it.instance.onPacketReceived(packet)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendPacket(packet: OutgoingPacket): Unit = withContext(coroutineContext + CoroutineName("sendPacket")) {
|
override suspend fun sendPacket(packet: OutgoingPacket): Unit = withContext(coroutineContext + CoroutineName("sendPacket")) {
|
||||||
@ -319,7 +309,8 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
override val owner: Bot get() = this@TIMBotNetworkHandler.bot
|
override val owner: Bot get() = this@TIMBotNetworkHandler.bot
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
if (::loginHandler.isInitialized) loginHandler.close()
|
loginHandler?.close()
|
||||||
|
loginHandler = null
|
||||||
this.channel.close()
|
this.channel.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,7 +325,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
private lateinit var loginIP: String
|
private lateinit var loginIP: String
|
||||||
private var privateKey: PrivateKey = PrivateKey(getRandomByteArray(16))
|
private var privateKey: PrivateKey = PrivateKey(getRandomByteArray(16))
|
||||||
|
|
||||||
private var sessionResponseDecryptionKey: SessionResponseDecryptionKey by Delegates.notNull()
|
private var sessionResponseDecryptionKey: SessionResponseDecryptionKey? = null
|
||||||
|
|
||||||
private var captchaSectionId: Int = 1
|
private var captchaSectionId: Int = 1
|
||||||
private var captchaCache: IoBuffer? = null
|
private var captchaCache: IoBuffer? = null
|
||||||
@ -359,7 +350,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
|||||||
|
|
||||||
NoDecrypter -> NoDecrypter
|
NoDecrypter -> NoDecrypter
|
||||||
|
|
||||||
SessionResponseDecryptionKey -> sessionResponseDecryptionKey
|
SessionResponseDecryptionKey -> sessionResponseDecryptionKey!!
|
||||||
SubmitPasswordResponseDecrypter -> SubmitPasswordResponseDecrypter(privateKey)
|
SubmitPasswordResponseDecrypter -> SubmitPasswordResponseDecrypter(privateKey)
|
||||||
PrivateKey -> privateKey
|
PrivateKey -> privateKey
|
||||||
SessionKey -> sessionKey
|
SessionKey -> sessionKey
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
|
|
||||||
|
|
||||||
package net.mamoe.mirai.network.protocol.tim.handler
|
|
||||||
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.mamoe.mirai.network.BotSession
|
|
||||||
import net.mamoe.mirai.network.isOpen
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.action.RequestAccountInfoPacket
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.login.SKey
|
|
||||||
import net.mamoe.mirai.network.qqAccount
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动作: 获取好友列表, 点赞, 踢人等.
|
|
||||||
* 处理动作事件, 承担动作任务.
|
|
||||||
*
|
|
||||||
* @author Him188moe
|
|
||||||
*/
|
|
||||||
class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
|
|
||||||
companion object Key : PacketHandler.Key<ActionPacketHandler>
|
|
||||||
|
|
||||||
|
|
||||||
private var sKeyRefresherJob: Job? = null
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun onPacketReceived(packet: Packet): Unit = with(session) {
|
|
||||||
when (packet) {
|
|
||||||
is SKey -> {
|
|
||||||
_sKey = packet.value
|
|
||||||
cookies = "uin=o$qqAccount;skey=$sKey;"
|
|
||||||
|
|
||||||
|
|
||||||
if (sKeyRefresherJob?.isActive != true) {
|
|
||||||
sKeyRefresherJob = NetworkScope.launch {
|
|
||||||
while (isOpen) {
|
|
||||||
delay(1800000)
|
|
||||||
try {
|
|
||||||
requestSKey()
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
bot.logger.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun requestSKey() = with(session) {
|
|
||||||
withContext(NetworkScope.coroutineContext) {
|
|
||||||
RequestSKeyPacket().send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
suspend fun requestAccountInfo() = with(session) {
|
|
||||||
withContext(NetworkScope.coroutineContext) {
|
|
||||||
RequestAccountInfoPacket(qqAccount, sessionKey).send()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
this.sKeyRefresherJob?.cancel()
|
|
||||||
this.sKeyRefresherJob = null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package net.mamoe.mirai.network.protocol.tim.handler
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import net.mamoe.mirai.network.BotSession
|
|
||||||
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据包(接受/发送)处理器
|
|
||||||
*/
|
|
||||||
abstract class PacketHandler(
|
|
||||||
val session: BotSession
|
|
||||||
) : CoroutineScope {
|
|
||||||
override val coroutineContext: CoroutineContext
|
|
||||||
get() = EmptyCoroutineContext
|
|
||||||
|
|
||||||
abstract suspend fun onPacketReceived(packet: Packet)
|
|
||||||
|
|
||||||
interface Key<T : PacketHandler>
|
|
||||||
|
|
||||||
open fun close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class PacketHandlerNode<T : PacketHandler>(
|
|
||||||
val instance: T,
|
|
||||||
val key: PacketHandler.Key<T>
|
|
||||||
)
|
|
||||||
|
|
||||||
internal fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return PacketHandlerNode(this, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key == key }.instance as T
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
|||||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||||
import net.mamoe.mirai.network.qqAccount
|
import net.mamoe.mirai.network.qqAccount
|
||||||
import net.mamoe.mirai.utils.io.*
|
import net.mamoe.mirai.utils.io.*
|
||||||
|
import net.mamoe.mirai.withSession
|
||||||
|
|
||||||
fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount, sessionKey)
|
fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount, sessionKey)
|
||||||
|
|
||||||
@ -39,6 +40,26 @@ object RequestSKeyPacket : SessionPacketFactory<SKey>() {
|
|||||||
DebugLogger.warning("SKey 包后面${readRemainingBytes().toUHexString()}")
|
DebugLogger.warning("SKey 包后面${readRemainingBytes().toUHexString()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun BotNetworkHandler<*>.handlePacket(packet: SKey) = bot.withSession {
|
||||||
|
_sKey = packet.value
|
||||||
|
_cookies = "uin=o$qqAccount;skey=$sKey;"
|
||||||
|
|
||||||
|
// TODO: 2019/11/27 SKEY 实现
|
||||||
|
/*
|
||||||
|
if (sKeyRefresherJob?.isActive != true) {
|
||||||
|
sKeyRefresherJob = NetworkScope.launch {
|
||||||
|
while (isOpen) {
|
||||||
|
delay(1800000)
|
||||||
|
try {
|
||||||
|
requestSKey()
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
bot.logger.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline class SKey(
|
inline class SKey(
|
||||||
|
Loading…
Reference in New Issue
Block a user