Ensure references is released after Job cancelling

This commit is contained in:
Him188 2020-03-22 15:57:43 +08:00
parent 9b191f6763
commit 8e37cdbf93
3 changed files with 32 additions and 22 deletions

View File

@ -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<String> {
url("https://qqweb.qq.com/c/activedata/get_mygroup_data")
parameter("bkn",bkn)
parameter("gc",groupId)
parameter("bkn", bkn)
parameter("gc", groupId)
headers {
append(

View File

@ -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<KnownPacketFactories.IncomingPacket<*>>? =
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()

View File

@ -35,9 +35,14 @@ abstract class BotImpl<N : BotNetworkHandler> 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<N : BotNetworkHandler> 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 }
}
}