Adjust job cancelling hence fix #65

This commit is contained in:
Him188 2020-02-19 11:28:23 +08:00
parent 0643e9eac9
commit b2e0114e4f
3 changed files with 41 additions and 35 deletions

View File

@ -78,7 +78,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} catch (e: CancellationException) {
return@launch
} catch (e: Throwable) {
BotOfflineEvent.Dropped(bot).broadcast()
if (this@QQAndroidBotNetworkHandler.isActive) {
BotOfflineEvent.Dropped(bot).broadcast()
}
return@launch
}
packetReceiveLock.withLock {
@ -185,6 +187,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
@UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class)
override suspend fun init(): Unit = coroutineScope {
check(bot.isActive) { "bot is dead therefore network can't init" }
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" }
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
bot.qqs.delegate.clear()
@ -494,6 +498,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
* 发送一个包, 但不期待任何返回.
*/
suspend fun OutgoingPacket.sendWithoutExpect() {
check(bot.isActive) { "bot is dead therefore can't send any packet" }
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" }
logger.info("Send: ${this.commandName}")
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
channel.send(delegate)
@ -509,6 +515,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
require(timeoutMillis > 0) { "timeoutMillis must > 0" }
require(retry >= 0) { "retry must >= 0" }
check(bot.isActive) { "bot is dead therefore can't send any packet" }
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" }
var lastException: Exception? = null
if (retry == 0) {
val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)

View File

@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE")
@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE", "UnusedImport")
package net.mamoe.mirai
@ -35,7 +35,8 @@ import kotlin.jvm.JvmStatic
*
* : Bot 为全协程实现, 没有其他任务时若不使用 [join], 主线程将会退出.
*
* @see Contact
* @see Contact 联系人
* @see kotlinx.coroutines.isActive 判断 [Bot] 是否正常运行中. (在线, 且没有被 [close])
*/
@UseExperimental(MiraiInternalAPI::class)
abstract class Bot : CoroutineScope {
@ -195,7 +196,9 @@ abstract class Bot : CoroutineScope {
/**
* 登录, 或重新登录.
* 重新登录时不会再次拉取联系人列表.
* 这个函数总是关闭一切现有网路任务, 然后重新登录并重新缓存好友列表和群列表.
*
* 一般情况下不需要重新登录. Mirai 能够自动处理掉线情况.
*
* 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.relogin]
*
@ -231,24 +234,19 @@ abstract class Bot : CoroutineScope {
// endregion
/**
* 关闭这个 [Bot], 停止一切相关活动. 所有引用都会被释放.
* 关闭这个 [Bot], 立即取消 [Bot] [kotlinx.coroutines.SupervisorJob].
* 之后 [kotlinx.coroutines.isActive] 将会返回 `false`.
*
* : 不可重新登录. 必须重新实例化一个 [Bot].
* **:** 不可重新登录. 必须重新实例化一个 [Bot].
*
* @param cause 原因. null 时视为正常关闭, null 时视为异常关闭
*
* @see closeAndJoin
* @see closeAndJoin 取消并 [Bot.join], 以确保 [Bot] 相关的活动被完全关闭
*/
abstract fun close(cause: Throwable? = null)
// region extensions
@Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this.toLong())"))
fun Int.qq(): QQ = getFriend(this.toLong())
@Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this)"))
fun Long.qq(): QQ = getFriend(this)
final override fun toString(): String {
return "Bot(${uin})"
}

View File

@ -89,22 +89,17 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
private val offlineListener: Listener<BotOfflineEvent> = this.subscribeAlways { event ->
when (event) {
is BotOfflineEvent.Dropped -> {
if (!_network.isActive) {
return@subscribeAlways
}
bot.logger.info("Connection dropped or lost by server, retrying login")
var lastFailedException: Throwable? = null
repeat(configuration.reconnectionRetryTimes) {
try {
network.relogin()
logger.info("Reconnected successfully")
return@subscribeAlways
} catch (e: Throwable) {
lastFailedException = e
delay(configuration.reconnectPeriodMillis)
}
}
if (lastFailedException != null) {
throw lastFailedException!!
}
tryNTimesOrException(configuration.reconnectionRetryTimes) {
delay(configuration.reconnectPeriodMillis)
network.relogin()
logger.info("Reconnected successfully")
return@subscribeAlways
}?.let { throw it }
}
is BotOfflineEvent.Active -> {
val msg = if (event.cause == null) {
@ -112,12 +107,12 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
} else {
" with exception: " + event.cause.message
}
bot.logger.info("Bot is closed manually$msg")
close(CancellationException(event.toString()))
bot.logger.info { "Bot is closed manually$msg" }
closeAndJoin(CancellationException(event.toString()))
}
is BotOfflineEvent.Force -> {
bot.logger.info("Connection occupied by another android device: ${event.message}")
close(ForceOfflineException(event.toString()))
bot.logger.info { "Connection occupied by another android device: ${event.message}" }
closeAndJoin(ForceOfflineException(event.toString()))
}
}
}
@ -176,15 +171,19 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
@UseExperimental(MiraiInternalAPI::class)
override fun close(cause: Throwable?) {
if (!this.botJob.isActive) {
// already cancelled
return
}
kotlin.runCatching {
if (cause == null) {
this.botJob.cancel()
network.close()
this.botJob.complete()
offlineListener.complete()
offlineListener.cancel()
} else {
this.botJob.cancel(CancellationException("bot cancelled", cause))
network.close(cause)
this.botJob.completeExceptionally(cause)
offlineListener.completeExceptionally(cause)
offlineListener.cancel(CancellationException("bot cancelled", cause))
}
}
groups.delegate.clear()