diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index 9f1139d34..91458cd05 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -14,10 +14,8 @@ import io.ktor.client.request.* import io.ktor.client.request.forms.MultiPartFormDataContent import io.ktor.client.request.forms.formData import io.ktor.client.statement.HttpResponse -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.async +import kotlinx.coroutines.* import kotlinx.coroutines.io.ByteReadChannel -import kotlinx.coroutines.withContext import kotlinx.serialization.UnstableDefault import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonConfiguration @@ -342,14 +340,15 @@ internal abstract class QQAndroidBotBase constructor( return json.parse(GroupAnnouncement.serializer(), rep) } + @LowLevelAPI @MiraiExperimentalAPI override suspend fun _lowLevelGetGroupActiveData(groupId: Long): GroupActiveData { val data = network.async { HttpClient().get { url("https://qqweb.qq.com/c/activedata/get_mygroup_data") - parameter("bkn",bkn) - parameter("gc",groupId) + parameter("bkn", bkn) + parameter("gc", groupId) headers { append( diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 7d371c144..14c2c42c8 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -180,6 +180,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler // caches private val _pendingEnabled = atomic(true) internal val pendingEnabled get() = _pendingEnabled.value + @Volatile internal var pendingIncomingPackets: LockFreeLinkedList>? = LockFreeLinkedList() @@ -189,8 +190,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler check(bot.isActive) { "bot is dead therefore network can't init" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" } - bot.friends.delegate.clear() - bot.groups.delegate.clear() + CancellationException("re-init").let { reInitCancellationException -> + bot.friends.delegate.clear { it.cancel(reInitCancellationException) } + bot.groups.delegate.clear { it.cancel(reInitCancellationException) } + } if (!pendingEnabled) { pendingIncomingPackets = LockFreeLinkedList() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index 1d269fcc5..b821cd54c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -35,9 +35,14 @@ abstract class BotImpl constructor( val configuration: BotConfiguration ) : Bot(), CoroutineScope { private val botJob = SupervisorJob(configuration.parentCoroutineContext[Job]) - override val coroutineContext: CoroutineContext = + final override val coroutineContext: CoroutineContext = configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler] - ?: CoroutineExceptionHandler { _, e -> logger.error("An exception was thrown under a coroutine of Bot", e) }) + ?: CoroutineExceptionHandler { _, e -> + logger.error( + "An exception was thrown under a coroutine of Bot", + e + ) + }) override val context: Context by context.unsafeWeakRef() @OptIn(LowLevelAPI::class) @@ -173,25 +178,28 @@ abstract class BotImpl constructor( // endregion + + init { + coroutineContext[Job]!!.invokeOnCompletion { throwable -> + network.close(throwable) + offlineListener.cancel(CancellationException("bot cancelled", throwable)) + + groups.delegate.clear() // job is cancelled, so child jobs are to be cancelled + friends.delegate.clear() + instances.removeIf { it.get()?.uin == this.uin } + } + } + @OptIn(MiraiInternalAPI::class) override fun close(cause: Throwable?) { if (!this.botJob.isActive) { // already cancelled return } - kotlin.runCatching { - if (cause == null) { - this.botJob.cancel() - network.close() - offlineListener.cancel() - } else { - this.botJob.cancel(CancellationException("bot cancelled", cause)) - network.close(cause) - offlineListener.cancel(CancellationException("bot cancelled", cause)) - } + if (cause == null) { + this.botJob.cancel() + } else { + this.botJob.cancel(CancellationException("bot cancelled", cause)) } - groups.delegate.clear() - friends.delegate.clear() - instances.removeIf { it.get()?.uin == this.uin } } }