Commit 2a379040 authored by Him188's avatar Him188

Fix the problem that login() function never returns

parent 62969444
......@@ -17,6 +17,7 @@ import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
import net.mamoe.mirai.utils.io.logStacktrace
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.jvm.JvmOverloads
......@@ -75,7 +76,8 @@ suspend inline fun Bot(qq: Long, password: String): Bot = Bot(qq.toUInt(), passw
*/
class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineContext) : CoroutineScope {
private val supervisorJob = SupervisorJob(context[Job])
override val coroutineContext: CoroutineContext = context + supervisorJob
override val coroutineContext: CoroutineContext =
context + supervisorJob + CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }
constructor(qq: UInt, password: String, context: CoroutineContext) : this(BotAccount(qq, password), context)
constructor(account: BotAccount, context: CoroutineContext) : this(account, DefaultLogger("Bot(" + account.id + ")"), context)
......@@ -116,10 +118,10 @@ class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineCo
* 然后重新启动并尝试登录
*/
@JvmOverloads // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
fun reinitializeNetworkHandlerAsync(
suspend fun reinitializeNetworkHandler(
configuration: BotConfiguration,
cause: Throwable? = null
): Deferred<LoginResult> = async {
): LoginResult {
logger.info("Initializing BotNetworkHandler")
try {
if (::network.isInitialized) {
......@@ -129,9 +131,20 @@ class Bot(val account: BotAccount, val logger: MiraiLogger, context: CoroutineCo
logger.error("Cannot close network handler", e)
}
network = TIMBotNetworkHandler(coroutineContext + configuration, this@Bot)
network.login()
return network.login()
}
/**
* [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler] 下的协程.
* 然后重新启动并尝试登录
*/
@JvmOverloads // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
fun reinitializeNetworkHandlerAsync(
configuration: BotConfiguration,
cause: Throwable? = null
): Deferred<LoginResult> = async { reinitializeNetworkHandler(configuration, cause) }
/**
* Bot 联系人管理.
*
......
......@@ -70,13 +70,13 @@ suspend inline fun Bot.login(noinline configuration: BotConfiguration.() -> Unit
contract {
callsInPlace(configuration, InvocationKind.EXACTLY_ONCE)
}
return this.reinitializeNetworkHandlerAsync(BotConfiguration().apply(configuration)).await()
return this.reinitializeNetworkHandler(BotConfiguration().apply(configuration))
}
/**
* 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回登录结果
*/
suspend inline fun Bot.login(): LoginResult = this.reinitializeNetworkHandlerAsync(BotConfiguration.Default).await()
suspend inline fun Bot.login(): LoginResult = this.reinitializeNetworkHandler(BotConfiguration.Default)
/**
* 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回 [this]
......@@ -91,7 +91,7 @@ suspend inline fun Bot.alsoLogin(noinline configuration: BotConfiguration.() ->
contract {
callsInPlace(configuration, InvocationKind.EXACTLY_ONCE)
}
this.reinitializeNetworkHandlerAsync(BotConfiguration().apply(configuration)).await().requireSuccess()
this.reinitializeNetworkHandler(BotConfiguration().apply(configuration)).requireSuccess()
return this
}
......
......@@ -58,8 +58,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
private var heartbeatJob: Job? = null
private lateinit var userContext: CoroutineContext
override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) {
handlersLock.withLock {
temporaryPacketHandlers.add(temporaryPacketHandler)
......@@ -68,7 +66,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
}
override suspend fun login(): LoginResult {
userContext = coroutineContext
return withContext(this.coroutineContext) {
TIMProtocol.SERVER_IP.sortedBy { Random.nextInt() }.forEach { ip ->
bot.logger.info("Connecting server $ip")
......@@ -97,10 +94,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
override lateinit var session: BotSession
//private | internal
private fun onLoggedIn() {
session = BotSession(sessionKey, socket)
bot.logger.info("Successfully logged in")
}
private var sessionKey: SessionKey by Delegates.notNull()
......@@ -379,12 +372,10 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
}
is TouchPacket.TouchResponse.Redirection -> {
withContext(userContext) {
socket.close()
bot.logger.info("Redirecting to ${packet.serverIP}")
socket = BotSocketAdapter(packet.serverIP!!)
loginResult.complete(socket.resendTouch())
}
socket.close()
bot.logger.info("Redirecting to ${packet.serverIP}")
socket = BotSocketAdapter(packet.serverIP!!)
loginResult.complete(socket.resendTouch())
}
is SubmitPasswordPacket.LoginResponse.Failed -> {
......@@ -417,14 +408,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
if (packet.unknownBoolean) {
this.captchaSectionId = 1
socket.sendPacket(
CaptchaPacket.RequestTransmission(
bot.qqAccount,
this.token0825,
this.captchaSectionId++,
packet.token00BA
)
)
socket.sendPacket(CaptchaPacket.RequestTransmission(bot.qqAccount, this.token0825, this.captchaSectionId++, packet.token00BA))
}
}
......@@ -457,17 +441,13 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
socket.sendPacket(CaptchaPacket.Submit(bot.qqAccount, token0825, code, packet.captchaToken))
}
} else {
socket.sendPacket(
CaptchaPacket.RequestTransmission(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA)
)
socket.sendPacket(CaptchaPacket.RequestTransmission(bot.qqAccount, token0825, captchaSectionId++, packet.token00BA))
}
}
is SubmitPasswordPacket.LoginResponse.Success -> {
this.sessionResponseDecryptionKey = packet.sessionResponseDecryptionKey
socket.sendPacket(
RequestSessionPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey)
)
socket.sendPacket(RequestSessionPacket(bot.qqAccount, socket.serverIp, packet.token38, packet.token88, packet.encryptionKey))
}
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一
......@@ -493,6 +473,15 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
sessionKey = packet.sessionKey
bot.logger.info("sessionKey = ${sessionKey.value.toUHexString()}")
setOnlineStatus(OnlineStatus.ONLINE)//required
}
is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> {
BotLoginSucceedEvent(bot).broadcast()
session = BotSession(sessionKey, socket)
val configuration = currentBotConfiguration()
heartbeatJob = this@TIMBotNetworkHandler.launch {
while (socket.isOpen) {
......@@ -514,15 +503,8 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
}
}
bot.logger.info("Successfully logged in")
loginResult.complete(LoginResult.SUCCESS)
setOnlineStatus(OnlineStatus.ONLINE)//required
}
is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> {
BotLoginSucceedEvent(bot).broadcast()
onLoggedIn()
this.close()//The LoginHandler is useless since then
}
}
......
......@@ -113,7 +113,8 @@ inline fun LoginResult.requireSuccess(lazyMessage: (LoginResult) -> String) {
* 检查 [this] 为 [LoginResult.SUCCESS].
* 失败则 [error]
*/
fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
@Suppress("NOTHING_TO_INLINE")
inline fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
/**
* 检查 [this] 为 [LoginResult.SUCCESS].
......@@ -121,7 +122,8 @@ fun LoginResult.requireSuccess() = requireSuccess { "Login failed: $this" }
*
* @return 成功时 [Unit], 失败时 `null`
*/
fun LoginResult.requireSuccessOrNull(): Unit? = if (this == SUCCESS) Unit else null
@Suppress("NOTHING_TO_INLINE")
inline fun LoginResult.requireSuccessOrNull(): Unit? = if (this == SUCCESS) Unit else null
/**
* 返回 [this] 是否为 [LoginResult.SUCCESS].
......
......@@ -12,6 +12,7 @@ internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
internal fun Throwable.logStacktrace(message: String? = null) = DebugLogger.error(message, this)
@PublishedApi
internal fun debugPrintln(any: Any?) = DebugLogger.debug(any)
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
......
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