Remove PacketHandler

This commit is contained in:
Him188 2019-11-27 12:47:06 +08:00
parent afd87826b8
commit 76e6e37c38
6 changed files with 46 additions and 172 deletions

View File

@ -5,9 +5,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler
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.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.Packet
import net.mamoe.mirai.network.protocol.tim.packet.login.HeartbeatPacket
@ -18,16 +17,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
/**
* Mirai 的网络处理器, 它承担所有数据包([Packet])的处理任务.
* [BotNetworkHandler] 是全异步和线程安全的.
*
* [BotNetworkHandler] 2 个模块构成:
* - [BotSocketAdapter]: 处理数据包底层的发送([ByteArray])
* - [PacketHandler]: 制作 [OutgoingPacket] 并传递给 [BotSocketAdapter] 发送; 分析 [Packet] 并处理
*
* 其中, [PacketHandler] 3 个子模块构成:
* - [LoginHandler] 处理 sendTouch/login/verification code 相关
* - [ActionPacketHandler] 处理动作相关(踢人/加入群/好友列表等)
*
* [BotNetworkHandler] 是线程安全的.
*
* NetworkHandler 实现接口 [CoroutineScope]
* [BotNetworkHandler] 自己就是作用域.
@ -50,14 +40,7 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : CoroutineScope {
val supervisor get() = SupervisorJob()
/**
* 得到 [PacketHandler].
* `get(EventPacketHandler)` 返回 [EventPacketHandler]
* `get(ActionPacketHandler)` 返回 [ActionPacketHandler].
*
* 这个方法在 [PacketHandlerList] 中实现
*/
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T
val session: BotSession
/**
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果

View File

@ -15,7 +15,6 @@ import net.mamoe.mirai.message.Image
import net.mamoe.mirai.message.ImageId0x03
import net.mamoe.mirai.message.ImageId0x06
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.TemporaryPacketHandler
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
@ -65,29 +64,29 @@ abstract class BotSessionBase(
val socket: DataPacketSocketAdapter,
val NetworkScope: CoroutineScope
) {
/**
* Web api 使用
*/
lateinit var cookies: String
val cookies: String get() = _cookies
/**
* Web api 使用
*/
val sKey: String get() = _sKey
/**
* Web api 使用
*/
val gtk: Int get() = _gtk
@Suppress("PropertyName")
internal var _sKey: String = ""
set(value) {
field = value
_gtk = getGTK(value)
}
/**
* Web api 使用
*/
val gtk: Int get() = _gtk
internal lateinit var _cookies: String
private var _gtk: Int = 0
/**
@ -163,12 +162,6 @@ abstract class BotSessionBase(
inline val BotSession.isOpen: Boolean get() = socket.isOpen
inline val BotSession.qqAccount: UInt get() = bot.account.id
/**
* 取得 [BotNetworkHandler] [BotSession].
* 实际上是一个捷径.
*/
val BotNetworkHandler<*>.session: BotSession get() = this[ActionPacketHandler].session
/**
* 取得 [BotNetworkHandler] sessionKey.
* 实际上是一个捷径.

View File

@ -15,10 +15,10 @@ import net.mamoe.mirai.event.events.PacketSentEvent
import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
import net.mamoe.mirai.network.BotNetworkHandler
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.login.*
import net.mamoe.mirai.network.session
import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.OnlineStatus
@ -40,7 +40,7 @@ internal expect val NetworkDispatcher: CoroutineDispatcher
* @see BotNetworkHandler
*/
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 =
@ -94,13 +94,11 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
internal var loginResult: CompletableDeferred<LoginResult> = CompletableDeferred()
override lateinit var session: BotSession
//private | internal
private fun onLoggedIn() {
require(size == 0) { "Already logged in" }
val session = BotSession(sessionKey, socket)
add(ActionPacketHandler(session).asNode(ActionPacketHandler))
session = BotSession(sessionKey, socket)
bot.logger.info("Successfully logged in")
}
@ -122,10 +120,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
this.loginResult.join()
}
this.forEach {
it.instance.close()
}
this.socket.close()
}
@ -138,7 +132,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
override val isOpen: Boolean get() = channel.isOpen
private lateinit var loginHandler: LoginHandler
private var loginHandler: LoginHandler? = null
private suspend fun processReceive() {
while (channel.isOpen) {
@ -186,7 +180,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
val packet = try {
with(id.factory) {
loginHandler.provideDecrypter(id.factory)
loginHandler!!.provideDecrypter(id.factory)
.decrypt(input)
.decode(id, sequenceId, this@TIMBotNetworkHandler)
}
@ -205,7 +199,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
}
internal suspend fun resendTouch(): LoginResult /* = coroutineScope */ {
if (::loginHandler.isInitialized) loginHandler.close()
loginHandler?.close()
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)
this@TIMBotNetworkHandler.forEach {
it.instance.onPacketReceived(packet)
}
loginHandler?.onPacketReceived(packet)
}
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 fun close() {
if (::loginHandler.isInitialized) loginHandler.close()
loginHandler?.close()
loginHandler = null
this.channel.close()
}
}
@ -334,7 +325,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
private lateinit var loginIP: String
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 captchaCache: IoBuffer? = null
@ -359,7 +350,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
NoDecrypter -> NoDecrypter
SessionResponseDecryptionKey -> sessionResponseDecryptionKey
SessionResponseDecryptionKey -> sessionResponseDecryptionKey!!
SubmitPasswordResponseDecrypter -> SubmitPasswordResponseDecrypter(privateKey)
PrivateKey -> privateKey
SessionKey -> sessionKey

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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.qqAccount
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.withSession
fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount, sessionKey)
@ -39,6 +40,26 @@ object RequestSKeyPacket : SessionPacketFactory<SKey>() {
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(