Commit b2e0114e authored by Him188's avatar Him188

Adjust job cancelling hence fix #65

parent 0643e9ea
......@@ -78,7 +78,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} catch (e: CancellationException) {
return@launch
} catch (e: Throwable) {
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)
......
......@@ -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})"
}
......
......@@ -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 {
tryNTimesOrException(configuration.reconnectionRetryTimes) {
delay(configuration.reconnectPeriodMillis)
network.relogin()
logger.info("Reconnected successfully")
return@subscribeAlways
} catch (e: Throwable) {
lastFailedException = e
delay(configuration.reconnectPeriodMillis)
}
}
if (lastFailedException != null) {
throw lastFailedException!!
}
}?.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()
......
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