diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index 33a8e3dd5..6924e46f5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt @@ -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 : CoroutineScope { val supervisor get() = SupervisorJob() - /** - * 得到 [PacketHandler]. - * `get(EventPacketHandler)` 返回 [EventPacketHandler] - * `get(ActionPacketHandler)` 返回 [ActionPacketHandler]. - * - * 这个方法在 [PacketHandlerList] 中实现 - */ - operator fun get(key: PacketHandler.Key): T + val session: BotSession /** * 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt index 9408d2625..701a5b78e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt @@ -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. * 实际上是一个捷径. diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt index 15f68510f..3e729c909 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt @@ -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, PacketHandlerList(), CoroutineScope { + BotNetworkHandler, CoroutineScope { override val coroutineContext: CoroutineContext = @@ -94,13 +94,11 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou internal var loginResult: CompletableDeferred = 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 diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/ActionPacketHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/ActionPacketHandler.kt deleted file mode 100644 index f77670fd6..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/ActionPacketHandler.kt +++ /dev/null @@ -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 - - - 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 - } - -} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt deleted file mode 100644 index b5b37004a..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/handler/PacketHandler.kt +++ /dev/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 - - open fun close() { - - } -} - -internal class PacketHandlerNode( - val instance: T, - val key: PacketHandler.Key -) - -internal fun T.asNode(key: PacketHandler.Key): PacketHandlerNode { - @Suppress("UNCHECKED_CAST") - return PacketHandlerNode(this, key) -} - -internal open class PacketHandlerList : MutableList> by mutableListOf() { - @Suppress("UNCHECKED_CAST") - operator fun get(key: PacketHandler.Key): T = this.first { it.key == key }.instance as T -} diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt index 2ec39fc6e..4fc2b18cb 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/SKey.kt @@ -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() { 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(