Commit 24404f9a authored by Him188's avatar Him188

Rename qqNumber as account

parent 09046ae6
...@@ -21,9 +21,9 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -21,9 +21,9 @@ import net.mamoe.mirai.utils.MiraiLogger
* [Bot] 由 3 个模块组成. * [Bot] 由 3 个模块组成.
* [联系人管理][ContactSystem]: 可通过 [Bot.contacts] 访问 * [联系人管理][ContactSystem]: 可通过 [Bot.contacts] 访问
* [网络处理器][TIMBotNetworkHandler]: 可通过 [Bot.network] 访问 * [网络处理器][TIMBotNetworkHandler]: 可通过 [Bot.network] 访问
* [机器人账号信息][BotAccount]: 可通过 [Bot.account] 访问 * [机器人账号信息][BotAccount]: 可通过 [Bot.qqAccount] 访问
* *
* 若你需要得到机器人的 QQ 账号, 请访问 [Bot.account] * 若你需要得到机器人的 QQ 账号, 请访问 [Bot.qqAccount]
* 若你需要得到服务器上所有机器人列表, 请访问 [Bot.instances] * 若你需要得到服务器上所有机器人列表, 请访问 [Bot.instances]
* *
* *
...@@ -34,7 +34,7 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -34,7 +34,7 @@ import net.mamoe.mirai.utils.MiraiLogger
* a [TIMBotNetworkHandler], which manages the connection to the server; * a [TIMBotNetworkHandler], which manages the connection to the server;
* a [BotAccount], which stores the account information(e.g. qq number the bot) * a [BotAccount], which stores the account information(e.g. qq number the bot)
* *
* To of all the QQ contacts, access [Bot.account] * To of all the QQ contacts, access [Bot.qqAccount]
* To of all the Robot instance, access [Bot.instances] * To of all the Robot instance, access [Bot.instances]
* *
* *
...@@ -52,10 +52,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -52,10 +52,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
init { init {
instances.add(this) instances.add(this)
this.logger.identity = "Bot" + this.id + "(" + this.account.qqNumber + ")" this.logger.identity = "Bot" + this.id + "(" + this.account.account + ")"
} }
override fun toString(): String = "Bot{id=$id,qq=${account.qqNumber}}" override fun toString(): String = "Bot{id=$id,qq=${account.account}}"
/** /**
* [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程. * [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程.
...@@ -83,7 +83,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -83,7 +83,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
* 通过群号码获取群对象. * 通过群号码获取群对象.
* 注意: 在并发调用时, 这个方法并不是原子的. * 注意: 在并发调用时, 这个方法并不是原子的.
*/ */
fun getQQ(qqNumber: Long): QQ = qqs.getOrPut(qqNumber) { QQ(this@Bot, qqNumber) } fun getQQ(account: Long): QQ = qqs.getOrPut(account) { QQ(this@Bot, account) }
/** /**
* 通过群号码获取群对象. * 通过群号码获取群对象.
......
...@@ -41,7 +41,7 @@ suspend fun Bot.login(configuration: LoginConfiguration.() -> Unit): LoginResult ...@@ -41,7 +41,7 @@ suspend fun Bot.login(configuration: LoginConfiguration.() -> Unit): LoginResult
suspend fun Bot.login(): LoginResult = this.network.login(LoginConfiguration.Default) suspend fun Bot.login(): LoginResult = this.network.login(LoginConfiguration.Default)
//BotAccount //BotAccount
val Bot.qqNumber: Long get() = this.account.qqNumber val Bot.qqAccount: Long get() = this.account.account
//logging //logging
......
...@@ -2,7 +2,7 @@ package net.mamoe.mirai.network ...@@ -2,7 +2,7 @@ package net.mamoe.mirai.network
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.io.core.Closeable import kotlinx.io.core.Closeable
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocket 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.TIMBotNetworkHandler.LoginHandler
import net.mamoe.mirai.network.protocol.tim.handler.* import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
...@@ -17,8 +17,8 @@ import kotlin.coroutines.ContinuationInterceptor ...@@ -17,8 +17,8 @@ import kotlin.coroutines.ContinuationInterceptor
* [BotNetworkHandler] 是全异步和线程安全的. * [BotNetworkHandler] 是全异步和线程安全的.
* *
* [BotNetworkHandler] 由 2 个模块构成: * [BotNetworkHandler] 由 2 个模块构成:
* - [BotSocket]: 处理数据包底层的发送([ByteArray]) * - [BotSocketAdapter]: 处理数据包底层的发送([ByteArray])
* - [PacketHandler]: 制作 [ClientPacket] 并传递给 [BotSocket] 发送; 分析 [ServerPacket] 并处理 * - [PacketHandler]: 制作 [ClientPacket] 并传递给 [BotSocketAdapter] 发送; 分析 [ServerPacket] 并处理
* *
* 其中, [PacketHandler] 由 3 个子模块构成: * 其中, [PacketHandler] 由 3 个子模块构成:
* - [LoginHandler] 处理 sendTouch/login/verification code 相关 * - [LoginHandler] 处理 sendTouch/login/verification code 相关
...@@ -27,7 +27,7 @@ import kotlin.coroutines.ContinuationInterceptor ...@@ -27,7 +27,7 @@ import kotlin.coroutines.ContinuationInterceptor
* *
* A BotNetworkHandler is used to connect with Tencent servers. * A BotNetworkHandler is used to connect with Tencent servers.
*/ */
interface BotNetworkHandler<Socket : DataPacketSocket> : Closeable { interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable {
/** /**
* [BotNetworkHandler] 的协程作用域. * [BotNetworkHandler] 的协程作用域.
* 所有 [BotNetworkHandler] 的协程均启动在此作用域下. * 所有 [BotNetworkHandler] 的协程均启动在此作用域下.
......
...@@ -4,13 +4,12 @@ import kotlinx.coroutines.CompletableJob ...@@ -4,13 +4,12 @@ import kotlinx.coroutines.CompletableJob
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocket 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.ClientPacket import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.utils.getGTK import net.mamoe.mirai.utils.getGTK
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
import kotlin.jvm.JvmSynthetic
/** /**
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey. * 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
...@@ -18,10 +17,10 @@ import kotlin.jvm.JvmSynthetic ...@@ -18,10 +17,10 @@ import kotlin.jvm.JvmSynthetic
* *
* @author Him188moe * @author Him188moe
*/ */
class LoginSession( class BotSession(
val bot: Bot, val bot: Bot,
val sessionKey: ByteArray,//TODO 协议抽象? 可能并不是所有协议均需要 sessionKey val sessionKey: ByteArray,//TODO 协议抽象? 可能并不是所有协议均需要 sessionKey
val socket: DataPacketSocket, val socket: DataPacketSocketAdapter,
val scope: CoroutineScope val scope: CoroutineScope
) { ) {
...@@ -35,7 +34,7 @@ class LoginSession( ...@@ -35,7 +34,7 @@ class LoginSession(
*/ */
@ExperimentalStdlibApi @ExperimentalStdlibApi
var sKey: String = "" var sKey: String = ""
set(value) { internal set(value) {
field = value field = value
gtk = getGTK(value) gtk = getGTK(value)
} }
...@@ -44,8 +43,7 @@ class LoginSession( ...@@ -44,8 +43,7 @@ class LoginSession(
* Web api 使用 * Web api 使用
*/ */
var gtk: Int = 0 var gtk: Int = 0
private set
val isOpen: Boolean get() = socket.isOpen
/** /**
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket]. * 发送一个数据包, 并期待接受一个特定的 [ServerPacket].
...@@ -73,7 +71,7 @@ class LoginSession( ...@@ -73,7 +71,7 @@ class LoginSession(
/** /**
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket]. * 发送一个数据包, 并期待接受一个特定的 [ServerPacket].
* 发送成功后, 该方法会等待收到 [ServerPacket] 直到超时. * 发送成功后, 该方法会等待收到 [ServerPacket] 直到超时.
* 由于包名可能过长, 可使用 `DataPacketSocket.expectPacket(PacketProcessor)` 替代. * 由于包名可能过长, 可使用 `DataPacketSocketAdapter.expectPacket(PacketProcessor)` 替代.
* *
* 实现方法: * 实现方法:
* ```kotlin * ```kotlin
...@@ -86,7 +84,7 @@ class LoginSession( ...@@ -86,7 +84,7 @@ class LoginSession(
* @param toSend 将要发送的包 * @param toSend 将要发送的包
* @param handler 处理期待的包 * @param handler 处理期待的包
*/ */
@JvmSynthetic //@JvmSynthetic
suspend inline fun <reified P : ServerPacket> expectPacket(toSend: ClientPacket, noinline handler: suspend (P) -> Unit): CompletableJob { suspend inline fun <reified P : ServerPacket> expectPacket(toSend: ClientPacket, noinline handler: suspend (P) -> Unit): CompletableJob {
val job = coroutineContext[Job].takeIf { it != null }?.let { Job(it) } ?: Job() val job = coroutineContext[Job].takeIf { it != null }?.let { Job(it) } ?: Job()
this.bot.network.addHandler(TemporaryPacketHandler(P::class, job, this).also { this.bot.network.addHandler(TemporaryPacketHandler(P::class, job, this).also {
...@@ -98,4 +96,6 @@ class LoginSession( ...@@ -98,4 +96,6 @@ class LoginSession(
} }
suspend fun LoginSession.distributePacket(packet: ServerPacket) = this.socket.distributePacket(packet) suspend fun BotSession.distributePacket(packet: ServerPacket) = this.socket.distributePacket(packet)
\ No newline at end of file val BotSession.isOpen: Boolean get() = socket.isOpen
val BotSession.account: Long get() = bot.account.account
\ No newline at end of file
...@@ -14,7 +14,7 @@ import net.mamoe.mirai.event.events.PacketSentEvent ...@@ -14,7 +14,7 @@ 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.event.subscribe import net.mamoe.mirai.event.subscribe
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.handler.* import net.mamoe.mirai.network.protocol.tim.handler.*
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.*
...@@ -26,10 +26,10 @@ import net.mamoe.mirai.utils.* ...@@ -26,10 +26,10 @@ import net.mamoe.mirai.utils.*
* *
* @see BotNetworkHandler * @see BotNetworkHandler
*/ */
internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : BotNetworkHandler<TIMBotNetworkHandler.BotSocket>, PacketHandlerList() { internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : BotNetworkHandler<TIMBotNetworkHandler.BotSocketAdapter>, PacketHandlerList() {
override val NetworkScope: CoroutineScope = CoroutineScope(Dispatchers.Default) override val NetworkScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
override lateinit var socket: BotSocket override lateinit var socket: BotSocketAdapter
internal val temporaryPacketHandlers = mutableListOf<TemporaryPacketHandler<*>>() internal val temporaryPacketHandlers = mutableListOf<TemporaryPacketHandler<*>>()
private val handlersLock = Mutex() private val handlersLock = Mutex()
...@@ -47,7 +47,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -47,7 +47,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
override suspend fun login(configuration: LoginConfiguration): LoginResult { override suspend fun login(configuration: LoginConfiguration): LoginResult {
TIMProtocol.SERVER_IP.forEach { TIMProtocol.SERVER_IP.forEach {
bot.logger.logInfo("Connecting server $it") bot.logger.logInfo("Connecting server $it")
this.socket = BotSocket(it, configuration) this.socket = BotSocketAdapter(it, configuration)
loginResult = CompletableDeferred() loginResult = CompletableDeferred()
...@@ -69,7 +69,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -69,7 +69,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
//private | internal //private | internal
private fun onLoggedIn(sessionKey: ByteArray) { private fun onLoggedIn(sessionKey: ByteArray) {
require(size == 0) { "Already logged in" } require(size == 0) { "Already logged in" }
val session = LoginSession(bot, sessionKey, socket, NetworkScope) val session = BotSession(bot, sessionKey, socket, NetworkScope)
add(EventPacketHandler(session).asNode(EventPacketHandler)) add(EventPacketHandler(session).asNode(EventPacketHandler))
add(ActionPacketHandler(session).asNode(ActionPacketHandler)) add(ActionPacketHandler(session).asNode(ActionPacketHandler))
...@@ -96,7 +96,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -96,7 +96,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
override suspend fun sendPacket(packet: ClientPacket) = socket.sendPacket(packet) override suspend fun sendPacket(packet: ClientPacket) = socket.sendPacket(packet)
internal inner class BotSocket(override val serverIp: String, val configuration: LoginConfiguration) : DataPacketSocket { internal inner class BotSocketAdapter(override val serverIp: String, val configuration: LoginConfiguration) : DataPacketSocketAdapter {
override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000) override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000)
override val isOpen: Boolean get() = channel.isOpen override val isOpen: Boolean get() = channel.isOpen
...@@ -147,7 +147,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -147,7 +147,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
loginResult.complete(LoginResult.TIMEOUT) loginResult.complete(LoginResult.TIMEOUT)
} }
} }
sendPacket(ClientTouchPacket(bot.qqNumber, this.serverIp)) sendPacket(ClientTouchPacket(bot.qqAccount, this.serverIp))
return loginResult.await() return loginResult.await()
} }
...@@ -189,7 +189,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -189,7 +189,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
if (packet is ServerEventPacket) { if (packet is ServerEventPacket) {
//no need to sync acknowledgement packets //no need to sync acknowledgement packets
NetworkScope.launch { NetworkScope.launch {
sendPacket(packet.ResponsePacket(bot.qqNumber, sessionKey)) sendPacket(packet.ResponsePacket(bot.qqAccount, sessionKey))
} }
} }
...@@ -293,7 +293,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -293,7 +293,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
is ServerTouchResponsePacket -> { is ServerTouchResponsePacket -> {
if (packet.serverIP != null) {//redirection if (packet.serverIP != null) {//redirection
socket.close() socket.close()
socket = BotSocket(packet.serverIP!!, socket.configuration) socket = BotSocketAdapter(packet.serverIP!!, socket.configuration)
bot.logger.logPurple("Redirecting to ${packet.serverIP}") bot.logger.logPurple("Redirecting to ${packet.serverIP}")
loginResult.complete(socket.resendTouch()) loginResult.complete(socket.resendTouch())
} else {//password submission } else {//password submission
...@@ -302,7 +302,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -302,7 +302,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.token0825 = packet.token0825 this.token0825 = packet.token0825
socket.sendPacket(ClientPasswordSubmissionPacket( socket.sendPacket(ClientPasswordSubmissionPacket(
bot = bot.qqNumber, bot = bot.qqAccount,
password = bot.account.password, password = bot.account.password,
loginTime = loginTime, loginTime = loginTime,
loginIP = loginIP, loginIP = loginIP,
...@@ -324,7 +324,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -324,7 +324,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
socket.sendPacket(ClientPasswordSubmissionPacket( socket.sendPacket(ClientPasswordSubmissionPacket(
bot = bot.qqNumber, bot = bot.qqAccount,
password = bot.account.password, password = bot.account.password,
loginTime = loginTime, loginTime = loginTime,
loginIP = loginIP, loginIP = loginIP,
...@@ -342,7 +342,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -342,7 +342,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
if (packet.unknownBoolean == true) { if (packet.unknownBoolean == true) {
this.captchaSectionId = 1 this.captchaSectionId = 1
socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqNumber, this.token0825, this.captchaSectionId++, packet.token00BA)) socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA))
} }
} }
...@@ -363,19 +363,19 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -363,19 +363,19 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.captchaCache = null this.captchaCache = null
if (code == null) { if (code == null) {
this.captchaSectionId = 1//意味着正在刷新验证码 this.captchaSectionId = 1//意味着正在刷新验证码
socket.sendPacket(ClientCaptchaRefreshPacket(bot.qqNumber, token0825)) socket.sendPacket(ClientCaptchaRefreshPacket(bot.qqAccount, token0825))
} else { } else {
this.captchaSectionId = 0//意味着已经提交验证码 this.captchaSectionId = 0//意味着已经提交验证码
socket.sendPacket(ClientCaptchaSubmitPacket(bot.qqNumber, token0825, code, packet.verificationToken)) socket.sendPacket(ClientCaptchaSubmitPacket(bot.qqAccount, token0825, code, packet.verificationToken))
} }
} else { } else {
socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqNumber, token0825, captchaSectionId++, packet.token00BA)) socket.sendPacket(ClientCaptchaTransmissionRequestPacket(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA))
} }
} }
is ServerLoginResponseSuccessPacket -> { is ServerLoginResponseSuccessPacket -> {
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
socket.sendPacket(ClientSessionRequestPacket(bot.qqNumber, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey)) socket.sendPacket(ClientSessionRequestPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey))
} }
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一 //是ClientPasswordSubmissionPacket之后服务器回复的可能之一
...@@ -383,7 +383,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -383,7 +383,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this.privateKey = packet.privateKeyUpdate this.privateKey = packet.privateKeyUpdate
socket.sendPacket(ClientPasswordSubmissionPacket( socket.sendPacket(ClientPasswordSubmissionPacket(
bot = bot.qqNumber, bot = bot.qqAccount,
password = bot.account.password, password = bot.account.password,
loginTime = loginTime, loginTime = loginTime,
loginIP = loginIP, loginIP = loginIP,
...@@ -400,7 +400,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -400,7 +400,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
heartbeatJob = NetworkScope.launch { heartbeatJob = NetworkScope.launch {
while (socket.isOpen) { while (socket.isOpen) {
delay(90000) delay(90000)
socket.sendPacket(ClientHeartbeatPacket(bot.qqNumber, sessionKey)) socket.sendPacket(ClientHeartbeatPacket(bot.qqAccount, sessionKey))
} }
} }
...@@ -445,7 +445,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -445,7 +445,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
suspend fun setOnlineStatus(status: OnlineStatus) { suspend fun setOnlineStatus(status: OnlineStatus) {
socket.sendPacket(ClientChangeOnlineStatusPacket(bot.qqNumber, sessionKey, status)) socket.sendPacket(ClientChangeOnlineStatusPacket(bot.qqAccount, sessionKey, status))
} }
fun close() { fun close() {
......
...@@ -6,7 +6,8 @@ import kotlinx.coroutines.CompletableDeferred ...@@ -6,7 +6,8 @@ import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.isOpen
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendResult import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendResult
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientAddFriendPacket import net.mamoe.mirai.network.protocol.tim.packet.action.ClientAddFriendPacket
...@@ -15,9 +16,6 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResp ...@@ -15,9 +16,6 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResp
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRequestPacket import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerSKeyResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.login.ServerSKeyResponsePacket
import net.mamoe.mirai.utils.getGTK
import net.mamoe.mirai.utils.hexToBytes
import kotlin.properties.Delegates
/** /**
* 动作: 获取好友列表, 点赞, 踢人等. * 动作: 获取好友列表, 点赞, 踢人等.
...@@ -25,7 +23,7 @@ import kotlin.properties.Delegates ...@@ -25,7 +23,7 @@ import kotlin.properties.Delegates
* *
* @author Him188moe * @author Him188moe
*/ */
class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
companion object Key : PacketHandler.Key<ActionPacketHandler> companion object Key : PacketHandler.Key<ActionPacketHandler>
private val addFriendSessions = mutableListOf<AddFriendSession>() private val addFriendSessions = mutableListOf<AddFriendSession>()
...@@ -60,17 +58,15 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -60,17 +58,15 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
is ServerSKeyResponsePacket.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey)) is ServerSKeyResponsePacket.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
is ServerSKeyResponsePacket -> { is ServerSKeyResponsePacket -> {
session.sKey = packet.sKey session.sKey = packet.sKey
session.cookies = "uin=o" + session.bot.account.qqNumber + ";skey=" + session.sKey + ";" session.cookies = "uin=o" + session.bot.account.account + ";skey=" + session.sKey + ";"
sKeyRefresherJob = session.scope.launch { sKeyRefresherJob = session.scope.launch {
while (session.isOpen) { while (session.isOpen) {
delay(1800000) delay(1800000)
session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.qqNumber, session.sessionKey)) session.socket.sendPacket(ClientSKeyRefreshmentRequestPacket(session.bot.account.account, session.sessionKey))
} }
} }
session.gtk = getGTK(session.sKey)
} }
is ServerEventPacket.Raw.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey)) is ServerEventPacket.Raw.Encrypted -> session.socket.distributePacket(packet.decrypt(session.sessionKey))
...@@ -82,9 +78,9 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -82,9 +78,9 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
//@JvmSynthetic //@JvmSynthetic
suspend fun addFriend(qqNumber: Long, message: Lazy<String> = lazyOf("")): CompletableDeferred<AddFriendResult> { suspend fun addFriend(account: Long, message: Lazy<String> = lazyOf("")): CompletableDeferred<AddFriendResult> {
val future = CompletableDeferred<AddFriendResult>() val future = CompletableDeferred<AddFriendResult>()
val session = AddFriendSession(qqNumber, future, message) val session = AddFriendSession(account, future, message)
// uploadImageSessions.add(session) // uploadImageSessions.add(session)
session.sendAddRequest() session.sendAddRequest()
return future return future
...@@ -92,12 +88,12 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -92,12 +88,12 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
suspend fun requestSKey() { suspend fun requestSKey() {
session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.qqNumber, session.sessionKey)) session.socket.sendPacket(ClientSKeyRequestPacket(session.bot.account.account, session.sessionKey))
} }
suspend fun requestAccountInfo() { suspend fun requestAccountInfo() {
session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.qqNumber, session.sessionKey)) session.socket.sendPacket(ClientAccountInfoRequestPacket(session.bot.account.account, session.sessionKey))
} }
override fun close() { override fun close() {
...@@ -135,7 +131,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -135,7 +131,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> { ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> {
// session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey)) // session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
} }
ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> { ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> {
...@@ -188,7 +184,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -188,7 +184,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> { ServerCanAddFriendResponsePacket.State.REQUIRE_VERIFICATION -> {
session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey)) session.socket.sendPacket(ClientAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
} }
ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> { ServerCanAddFriendResponsePacket.State.NOT_REQUIRE_VERIFICATION -> {
...@@ -203,7 +199,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -203,7 +199,7 @@ class ActionPacketHandler(session: LoginSession) : PacketHandler(session) {
suspend fun sendAddRequest() { suspend fun sendAddRequest() {
session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.qqNumber, qq, session.sessionKey)) session.socket.sendPacket(ClientCanAddFriendPacket(session.bot.account.account, qq, session.sessionKey))
} }
fun close() { fun close() {
......
...@@ -3,7 +3,7 @@ package net.mamoe.mirai.network.protocol.tim.handler ...@@ -3,7 +3,7 @@ package net.mamoe.mirai.network.protocol.tim.handler
import kotlinx.io.core.Closeable import kotlinx.io.core.Closeable
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.events.ServerPacketReceivedEvent import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
...@@ -16,7 +16,7 @@ import net.mamoe.mirai.utils.PlatformDatagramChannel ...@@ -16,7 +16,7 @@ import net.mamoe.mirai.utils.PlatformDatagramChannel
* *
* @author Him188moe * @author Him188moe
*/ */
interface DataPacketSocket : Closeable { interface DataPacketSocketAdapter : Closeable {
val owner: Bot val owner: Bot
val serverIp: String val serverIp: String
...@@ -41,7 +41,7 @@ interface DataPacketSocket : Closeable { ...@@ -41,7 +41,7 @@ interface DataPacketSocket : Closeable {
* *
* 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回. * 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回.
* *
* @see [LoginSession.expectPacket] kotlin DSL * @see [BotSession.expectPacket] kotlin DSL
*/ */
suspend fun sendPacket(packet: ClientPacket) suspend fun sendPacket(packet: ClientPacket)
......
...@@ -8,7 +8,7 @@ import net.mamoe.mirai.event.events.GroupMessageEvent ...@@ -8,7 +8,7 @@ import net.mamoe.mirai.event.events.GroupMessageEvent
import net.mamoe.mirai.getGroupByNumber import net.mamoe.mirai.getGroupByNumber
import net.mamoe.mirai.getQQ import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.distributePacket import net.mamoe.mirai.network.distributePacket
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket
...@@ -23,7 +23,7 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -23,7 +23,7 @@ import net.mamoe.mirai.utils.MiraiLogger
* @author Him188moe * @author Him188moe
*/ */
@Suppress("EXPERIMENTAL_API_USAGE") @Suppress("EXPERIMENTAL_API_USAGE")
class EventPacketHandler(session: LoginSession) : PacketHandler(session) { class EventPacketHandler(session: BotSession) : PacketHandler(session) {
companion object Key : PacketHandler.Key<EventPacketHandler> companion object Key : PacketHandler.Key<EventPacketHandler>
...@@ -44,7 +44,7 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -44,7 +44,7 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
is ServerGroupMessageEventPacket -> { is ServerGroupMessageEventPacket -> {
if (ignoreMessage) return if (ignoreMessage) return
if (packet.qq.toLong() == bot.account.qqNumber) return if (packet.qq.toLong() == bot.account.account) return
GroupMessageEvent(bot, bot.getGroupByNumber(packet.groupNumber), bot.getQQ(packet.qq), packet.message).broadcast() GroupMessageEvent(bot, bot.getGroupByNumber(packet.groupNumber), bot.getQQ(packet.qq), packet.message).broadcast()
} }
...@@ -80,10 +80,10 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -80,10 +80,10 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
} }
suspend fun sendFriendMessage(qq: QQ, message: MessageChain) { suspend fun sendFriendMessage(qq: QQ, message: MessageChain) {
session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.qqNumber, qq.number, session.sessionKey, message)) session.socket.sendPacket(ClientSendFriendMessagePacket(session.bot.account.account, qq.number, session.sessionKey, message))
} }
suspend fun sendGroupMessage(group: Group, message: MessageChain) { suspend fun sendGroupMessage(group: Group, message: MessageChain) {
session.socket.sendPacket(ClientSendGroupMessagePacket(session.bot.account.qqNumber, group.groupId, session.sessionKey, message)) session.socket.sendPacket(ClientSendGroupMessagePacket(session.bot.account.account, group.groupId, session.sessionKey, message))
} }
} }
\ No newline at end of file
package net.mamoe.mirai.network.protocol.tim.handler package net.mamoe.mirai.network.protocol.tim.handler
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import kotlin.reflect.KClass import kotlin.reflect.KClass
...@@ -8,7 +8,7 @@ import kotlin.reflect.KClass ...@@ -8,7 +8,7 @@ import kotlin.reflect.KClass
* 数据包(接受/发送)处理器 * 数据包(接受/发送)处理器
*/ */
abstract class PacketHandler( abstract class PacketHandler(
val session: LoginSession val session: BotSession
) { ) {
abstract suspend fun onPacketReceived(packet: ServerPacket) abstract suspend fun onPacketReceived(packet: ServerPacket)
......
package net.mamoe.mirai.network.protocol.tim.handler package net.mamoe.mirai.network.protocol.tim.handler
import kotlinx.coroutines.CompletableJob import kotlinx.coroutines.CompletableJob
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import kotlin.reflect.KClass import kotlin.reflect.KClass
...@@ -17,19 +17,19 @@ import kotlin.reflect.KClass ...@@ -17,19 +17,19 @@ import kotlin.reflect.KClass
* } * }
* ``` * ```
* *
* @see LoginSession.expectPacket * @see BotSession.expectPacket
*/ */
class TemporaryPacketHandler<P : ServerPacket>( class TemporaryPacketHandler<P : ServerPacket>(
private val expectationClass: KClass<P>, private val expectationClass: KClass<P>,
private val deferred: CompletableJob, private val deferred: CompletableJob,
private val fromSession: LoginSession private val fromSession: BotSession
) { ) {
private lateinit var toSend: ClientPacket private lateinit var toSend: ClientPacket
private lateinit var expect: suspend (P) -> Unit private lateinit var expect: suspend (P) -> Unit
lateinit var session: LoginSession//无需覆盖 lateinit var session: BotSession//无需覆盖
fun toSend(packet: () -> ClientPacket) { fun toSend(packet: () -> ClientPacket) {
this.toSend = packet() this.toSend = packet()
...@@ -44,12 +44,12 @@ class TemporaryPacketHandler<P : ServerPacket>( ...@@ -44,12 +44,12 @@ class TemporaryPacketHandler<P : ServerPacket>(
this.expect = handler this.expect = handler
} }
suspend fun send(session: LoginSession) { suspend fun send(session: BotSession) {
this.session = session this.session = session
session.socket.sendPacket(toSend) session.socket.sendPacket(toSend)
} }
suspend fun shouldRemove(session: LoginSession, packet: ServerPacket): Boolean { suspend fun shouldRemove(session: BotSession, packet: ServerPacket): Boolean {
if (expectationClass.isInstance(packet) && session === this.fromSession) { if (expectationClass.isInstance(packet) && session === this.fromSession) {
kotlin.runCatching { kotlin.runCatching {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
......
...@@ -12,7 +12,7 @@ expect class PlatformImage ...@@ -12,7 +12,7 @@ expect class PlatformImage
expect class ClientTryGetImageIDPacket( expect class ClientTryGetImageIDPacket(
botNumber: Long, botNumber: Long,
sessionKey: ByteArray, sessionKey: ByteArray,
groupNumberOrQQNumber: Long, groupNumberOrAccount: Long,
image: PlatformImage image: PlatformImage
) : ClientPacket ) : ClientPacket
......
...@@ -2,6 +2,6 @@ package net.mamoe.mirai.utils ...@@ -2,6 +2,6 @@ package net.mamoe.mirai.utils
data class BotAccount( data class BotAccount(
val qqNumber: Long,//实际上是 UInt val account: Long,//实际上是 UInt
val password: String//todo 不保存 password? val password: String//todo 不保存 password?
) )
\ No newline at end of file
...@@ -32,6 +32,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket { ...@@ -32,6 +32,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
return when (id.toUInt()) { return when (id.toUInt()) {
0x08_25u -> ServerTouchResponsePacket.Encrypted(this) 0x08_25u -> ServerTouchResponsePacket.Encrypted(this)
0x08_36u -> { 0x08_36u -> {
//todo 不要用size分析
when (size) { when (size) {
271, 207 -> return ServerLoginResponseKeyExchangePacket.Encrypted(this).applySequence(sequenceId) 271, 207 -> return ServerLoginResponseKeyExchangePacket.Encrypted(this).applySequence(sequenceId)
871 -> return ServerLoginResponseCaptchaInitPacket.Encrypted(this).applySequence(sequenceId) 871 -> return ServerLoginResponseCaptchaInitPacket.Encrypted(this).applySequence(sequenceId)
......
...@@ -4,12 +4,12 @@ import kotlinx.coroutines.CompletableJob ...@@ -4,12 +4,12 @@ import kotlinx.coroutines.CompletableJob
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.network.LoginSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.ClientTryGetImageIDPacketJvm import net.mamoe.mirai.network.protocol.tim.packet.ClientTryGetImageIDPacketJvm
import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDFailedPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDFailedPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDSuccessPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerTryGetImageIDSuccessPacket
import net.mamoe.mirai.qqNumber import net.mamoe.mirai.qqAccount
import net.mamoe.mirai.utils.ImageNetworkUtils import net.mamoe.mirai.utils.ImageNetworkUtils
import net.mamoe.mirai.utils.md5 import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.toByteArray import net.mamoe.mirai.utils.toByteArray
...@@ -30,9 +30,9 @@ class UnsolvedImage(private val filename: String, val image: BufferedImage) { ...@@ -30,9 +30,9 @@ class UnsolvedImage(private val filename: String, val image: BufferedImage) {
constructor(imageFile: File) : this(imageFile.name, ImageIO.read(imageFile)) constructor(imageFile: File) : this(imageFile.name, ImageIO.read(imageFile))
constructor(url: URL) : this(File(url.file)) constructor(url: URL) : this(File(url.file))
suspend fun upload(session: LoginSession, contact: Contact): CompletableJob { suspend fun upload(session: BotSession, contact: Contact): CompletableJob {
return session.expectPacket<ServerTryGetImageIDResponsePacket> { return session.expectPacket<ServerTryGetImageIDResponsePacket> {
toSend { ClientTryGetImageIDPacketJvm(session.bot.qqNumber, session.sessionKey, contact.number, image) } toSend { ClientTryGetImageIDPacketJvm(session.bot.qqAccount, session.sessionKey, contact.number, image) }
onExpect { onExpect {
when (it) { when (it) {
...@@ -43,7 +43,7 @@ class UnsolvedImage(private val filename: String, val image: BufferedImage) { ...@@ -43,7 +43,7 @@ class UnsolvedImage(private val filename: String, val image: BufferedImage) {
is ServerTryGetImageIDSuccessPacket -> { is ServerTryGetImageIDSuccessPacket -> {
val data = image.toByteArray() val data = image.toByteArray()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
if (!ImageNetworkUtils.postImage(it.uKey.toUHexString(), data.size, session.bot.qqNumber, contact.number, data)) { if (!ImageNetworkUtils.postImage(it.uKey.toUHexString(), data.size, session.bot.qqAccount, contact.number, data)) {
throw RuntimeException("cannot upload image") throw RuntimeException("cannot upload image")
} }
} }
......
...@@ -23,7 +23,7 @@ actual typealias ClientTryGetImageIDPacket = ClientTryGetImageIDPacketJvm ...@@ -23,7 +23,7 @@ actual typealias ClientTryGetImageIDPacket = ClientTryGetImageIDPacketJvm
class ClientTryGetImageIDPacketJvm( class ClientTryGetImageIDPacketJvm(
private val botNumber: Long, private val botNumber: Long,
private val sessionKey: ByteArray, private val sessionKey: ByteArray,
private val groupNumberOrQQNumber: Long, private val groupNumberOrAccount: Long,
private val image: PlatformImage private val image: PlatformImage
) : ClientPacket() { ) : ClientPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) { override fun encode(builder: BytePacketBuilder) = with(builder) {
...@@ -52,7 +52,7 @@ class ClientTryGetImageIDPacketJvm( ...@@ -52,7 +52,7 @@ class ClientTryGetImageIDPacketJvm(
writeHex("57")//原5A writeHex("57")//原5A
writeHex("08") writeHex("08")
writeUVarInt(groupNumberOrQQNumber)//FB D2 D8 94 writeUVarInt(groupNumberOrAccount)//FB D2 D8 94
writeByte(0x02) writeByte(0x02)
writeHex("10") writeHex("10")
......
...@@ -62,5 +62,5 @@ suspend fun main() { ...@@ -62,5 +62,5 @@ suspend fun main() {
} }
println("Filtering finished") println("Filtering finished")
println(goodBotList.joinToString("\n") { it.account.qqNumber.toString() + " " + it.account.password }) println(goodBotList.joinToString("\n") { it.account.account.toString() + " " + it.account.password })
} }
...@@ -23,7 +23,7 @@ import kotlin.system.measureTimeMillis ...@@ -23,7 +23,7 @@ import kotlin.system.measureTimeMillis
suspend fun main() { suspend fun main() {
val bot = Bot(BotAccount(//填写你的账号 val bot = Bot(BotAccount(//填写你的账号
qqNumber = 2903772581, account = 2903772581,
password = "zxc123456" password = "zxc123456"
), Console()) ), Console())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment