Commit 9b400622 authored by Him188's avatar Him188

Rework re-init, fix #282

parent 40b8cabd
...@@ -85,6 +85,7 @@ kotlin { ...@@ -85,6 +85,7 @@ kotlin {
val jvmMain by getting { val jvmMain by getting {
dependencies { dependencies {
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
// api(kotlinx("coroutines-debug", "1.3.5"))
api(kotlinx("serialization-runtime", Versions.Kotlin.serialization)) api(kotlinx("serialization-runtime", Versions.Kotlin.serialization))
//api(kotlinx("serialization-protobuf", Versions.Kotlin.serialization)) //api(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
......
...@@ -58,7 +58,6 @@ import kotlin.contracts.ExperimentalContracts ...@@ -58,7 +58,6 @@ import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
import kotlin.jvm.Synchronized
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.random.Random import kotlin.random.Random
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo as JceFriendInfo import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo as JceFriendInfo
...@@ -294,7 +293,7 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -294,7 +293,7 @@ internal abstract class QQAndroidBotBase constructor(
} }
override fun createNetworkHandler(coroutineContext: CoroutineContext): QQAndroidBotNetworkHandler { override fun createNetworkHandler(coroutineContext: CoroutineContext): QQAndroidBotNetworkHandler {
return QQAndroidBotNetworkHandler(this as QQAndroidBot) return QQAndroidBotNetworkHandler(coroutineContext, this as QQAndroidBot)
} }
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList()) override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
......
...@@ -14,6 +14,8 @@ package net.mamoe.mirai.qqandroid.contact ...@@ -14,6 +14,8 @@ package net.mamoe.mirai.qqandroid.contact
import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.io.core.Closeable import kotlinx.io.core.Closeable
import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Friend
...@@ -59,10 +61,12 @@ internal inline fun Friend.checkIsFriendImpl(): FriendImpl { ...@@ -59,10 +61,12 @@ internal inline fun Friend.checkIsFriendImpl(): FriendImpl {
internal class FriendImpl( internal class FriendImpl(
bot: QQAndroidBot, bot: QQAndroidBot,
override val coroutineContext: CoroutineContext, coroutineContext: CoroutineContext,
override val id: Long, override val id: Long,
private val friendInfo: FriendInfo private val friendInfo: FriendInfo
) : Friend() { ) : Friend() {
override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob(coroutineContext[Job])
@Suppress("unused") // bug @Suppress("unused") // bug
val lastMessageSequence: AtomicInt = atomic(-1) val lastMessageSequence: AtomicInt = atomic(-1)
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
package net.mamoe.mirai.qqandroid.contact package net.mamoe.mirai.qqandroid.contact
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.io.core.Closeable import kotlinx.io.core.Closeable
import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.LowLevelAPI
...@@ -28,12 +30,10 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToGroupImpl ...@@ -28,12 +30,10 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceToGroupImpl
import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable import net.mamoe.mirai.qqandroid.message.ensureSequenceIdAvailable
import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull import net.mamoe.mirai.qqandroid.message.firstIsInstanceOrNull
import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
import net.mamoe.mirai.qqandroid.utils.encodeToString
import net.mamoe.mirai.qqandroid.utils.estimateLength import net.mamoe.mirai.qqandroid.utils.estimateLength
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
...@@ -61,13 +61,16 @@ internal fun Group.checkIsGroupImpl() { ...@@ -61,13 +61,16 @@ internal fun Group.checkIsGroupImpl() {
@OptIn(MiraiExperimentalAPI::class, LowLevelAPI::class) @OptIn(MiraiExperimentalAPI::class, LowLevelAPI::class)
@Suppress("PropertyName") @Suppress("PropertyName")
internal class GroupImpl( internal class GroupImpl(
bot: QQAndroidBot, override val coroutineContext: CoroutineContext, bot: QQAndroidBot,
coroutineContext: CoroutineContext,
override val id: Long, override val id: Long,
groupInfo: GroupInfo, groupInfo: GroupInfo,
members: Sequence<MemberInfo> members: Sequence<MemberInfo>
) : Group() { ) : Group() {
companion object; companion object;
override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob(coroutineContext[Job])
override val bot: QQAndroidBot by bot.unsafeWeakRef() override val bot: QQAndroidBot by bot.unsafeWeakRef()
val uin: Long = groupInfo.uin val uin: Long = groupInfo.uin
......
...@@ -13,6 +13,8 @@ package net.mamoe.mirai.qqandroid.contact ...@@ -13,6 +13,8 @@ package net.mamoe.mirai.qqandroid.contact
import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic import kotlinx.atomicfu.atomic
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
...@@ -42,10 +44,11 @@ import kotlin.jvm.JvmSynthetic ...@@ -42,10 +44,11 @@ import kotlin.jvm.JvmSynthetic
internal class MemberImpl constructor( internal class MemberImpl constructor(
val qq: FriendImpl, // 不要 WeakRef val qq: FriendImpl, // 不要 WeakRef
group: GroupImpl, group: GroupImpl,
override val coroutineContext: CoroutineContext, coroutineContext: CoroutineContext,
memberInfo: MemberInfo memberInfo: MemberInfo
) : Member() { ) : Member() {
override val group: GroupImpl by group.unsafeWeakRef() override val group: GroupImpl by group.unsafeWeakRef()
override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob(coroutineContext[Job])
@Suppress("unused") // false positive @Suppress("unused") // false positive
val lastMessageSequence: AtomicInt = atomic(-1) val lastMessageSequence: AtomicInt = atomic(-1)
......
...@@ -46,18 +46,19 @@ import net.mamoe.mirai.qqandroid.utils.retryCatching ...@@ -46,18 +46,19 @@ import net.mamoe.mirai.qqandroid.utils.retryCatching
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.jvm.Volatile import kotlin.jvm.Volatile
import kotlin.random.Random
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler() { internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bot: QQAndroidBot) : BotNetworkHandler() {
override val bot: QQAndroidBot by bot.unsafeWeakRef() override val bot: QQAndroidBot by bot.unsafeWeakRef()
override val supervisor: CompletableJob = SupervisorJob(bot.coroutineContext[Job]) override val supervisor: CompletableJob = SupervisorJob(coroutineContext[Job])
override val logger: MiraiLogger get() = bot.configuration.networkLoggerSupplier(this) override val logger: MiraiLogger get() = bot.configuration.networkLoggerSupplier(this)
override val coroutineContext: CoroutineContext = bot.coroutineContext + CoroutineExceptionHandler { _, throwable -> override val coroutineContext: CoroutineContext = coroutineContext + CoroutineExceptionHandler { _, throwable ->
logger.error("Exception in NetworkHandler", throwable) logger.error("Exception in NetworkHandler", throwable)
} } + supervisor
private lateinit var channel: PlatformSocket private lateinit var channel: PlatformSocket
...@@ -209,10 +210,17 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -209,10 +210,17 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
internal var pendingIncomingPackets: LockFreeLinkedList<KnownPacketFactories.IncomingPacket<*>>? = internal var pendingIncomingPackets: LockFreeLinkedList<KnownPacketFactories.IncomingPacket<*>>? =
LockFreeLinkedList() LockFreeLinkedList()
private var initFriendOk = false
private var initGroupOk = false
/** /**
* Don't use concurrently * Don't use concurrently
*/ */
suspend fun reloadFriendList() { suspend fun reloadFriendList() {
if (initFriendOk) {
return
}
logger.info { "开始加载好友信息" } logger.info { "开始加载好友信息" }
var currentFriendCount = 0 var currentFriendCount = 0
var totalFriendCount: Short var totalFriendCount: Short
...@@ -242,6 +250,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -242,6 +250,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
// delay(200) // delay(200)
} }
logger.info { "好友列表加载完成, 共 ${currentFriendCount}个" } logger.info { "好友列表加载完成, 共 ${currentFriendCount}个" }
initFriendOk = true
} }
suspend fun StTroopNum.reloadGroup() { suspend fun StTroopNum.reloadGroup() {
...@@ -280,20 +289,25 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -280,20 +289,25 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
suspend fun reloadGroupList() { suspend fun reloadGroupList() {
if (initGroupOk) {
return
}
logger.info { "开始加载群组列表与群成员列表" } logger.info { "开始加载群组列表与群成员列表" }
val troopListData = FriendList.GetTroopListSimplify(bot.client) val troopListData = FriendList.GetTroopListSimplify(bot.client)
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 3) .sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 5)
troopListData.groups.chunked(50).forEach { chunk -> troopListData.groups.chunked(30).forEach { chunk ->
coroutineScope { coroutineScope {
chunk.forEach { chunk.forEach {
launch { launch {
retryCatching(3) { it.reloadGroup() }.getOrThrow() retryCatching(5) { it.reloadGroup() }.getOrThrow()
} }
} }
} }
} }
logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}个" } logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}个" }
initGroupOk = true
} }
@OptIn(MiraiExperimentalAPI::class, ExperimentalTime::class) @OptIn(MiraiExperimentalAPI::class, ExperimentalTime::class)
...@@ -302,9 +316,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -302,9 +316,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" }
CancellationException("re-init").let { reInitCancellationException -> CancellationException("re-init").let { reInitCancellationException ->
if (!initFriendOk) {
bot.friends.delegate.clear { it.cancel(reInitCancellationException) } bot.friends.delegate.clear { it.cancel(reInitCancellationException) }
}
if (!initGroupOk) {
bot.groups.delegate.clear { it.cancel(reInitCancellationException) } bot.groups.delegate.clear { it.cancel(reInitCancellationException) }
} }
}
if (!pendingEnabled) { if (!pendingEnabled) {
pendingIncomingPackets = LockFreeLinkedList() pendingIncomingPackets = LockFreeLinkedList()
...@@ -313,7 +331,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -313,7 +331,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
coroutineScope { coroutineScope {
launch { reloadFriendList() } launch { reloadFriendList() }
launch { reloadGroupList() } launch {
if (Random.nextInt() > 50) {
error("boom")
}
reloadGroupList()
}
} }
this@QQAndroidBotNetworkHandler.launch { this@QQAndroidBotNetworkHandler.launch {
...@@ -325,7 +348,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -325,7 +348,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
when (resp) { when (resp) {
null -> logger.info { "Missing ConfigPushSvc.PushReq." } null -> logger.info { "Missing ConfigPushSvc.PushReq." }
is ConfigPushSvc.PushReq.PushReqResponse.Success -> { is ConfigPushSvc.PushReq.PushReqResponse.Success -> {
logger.info { "ConfigPushSvc.PushReq: success" } logger.info { "ConfigPushSvc.PushReq: Success" }
} }
is ConfigPushSvc.PushReq.PushReqResponse.ChangeServer -> { is ConfigPushSvc.PushReq.PushReqResponse.ChangeServer -> {
logger.info { "Server requires reconnect." } logger.info { "Server requires reconnect." }
...@@ -340,15 +363,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -340,15 +363,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
} }
logger.info { "Syncing friend message history..." }
withTimeoutOrNull(30000) { withTimeoutOrNull(30000) {
launch { syncFromEvent<MessageSvc.PbGetMsg.GetMsgSuccess, Unit> { Unit } } launch { syncFromEvent<MessageSvc.PbGetMsg.GetMsgSuccess, Unit> { Unit } }
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>() MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<Packet>()
} ?: error("timeout syncing friend message history") } ?: error("timeout syncing friend message history")
logger.info { "Syncing friend message history: Success" }
bot.firstLoginSucceed = true bot.firstLoginSucceed = true
_pendingEnabled.value = false _pendingEnabled.value = false
pendingIncomingPackets?.forEach { pendingIncomingPackets?.forEach {
runCatching {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
KnownPacketFactories.handleIncomingPacket( KnownPacketFactories.handleIncomingPacket(
it as KnownPacketFactories.IncomingPacket<Packet>, it as KnownPacketFactories.IncomingPacket<Packet>,
...@@ -356,12 +382,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -356,12 +382,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
it.flag2, it.flag2,
it.consumer it.consumer
) )
}.getOrElse {
logger.error("Exception on processing pendingIncomingPackets", it)
}
} }
val list = pendingIncomingPackets val list = pendingIncomingPackets
pendingIncomingPackets = null // release, help gc pendingIncomingPackets = null // release, help gc
list?.clear() // help gc list?.clear() // help gc
runCatching {
BotOnlineEvent(bot).broadcast() BotOnlineEvent(bot).broadcast()
}.getOrElse {
logger.error("Exception on broadcasting BotOnlineEvent", it)
}
Unit // dont remove. can help type inference Unit // dont remove. can help type inference
} }
...@@ -583,9 +617,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -583,9 +617,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
* 不推荐使用它, 可能产生意外的情况. * 不推荐使用它, 可能产生意外的情况.
*/ */
suspend fun OutgoingPacket.sendWithoutExpect() { suspend fun OutgoingPacket.sendWithoutExpect() {
check(bot.isActive) { "bot is dead therefore can't send any packet" } check(bot.isActive) { "bot is dead therefore can't send ${this.commandName}" }
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" }
logger.verbose("Send: ${this.commandName}") logger.verbose { "Send: ${this.commandName}" }
channel.send(delegate) channel.send(delegate)
} }
...@@ -598,7 +632,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -598,7 +632,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
require(timeoutMillis > 100) { "timeoutMillis must > 100" } require(timeoutMillis > 100) { "timeoutMillis must > 100" }
require(retry >= 0) { "retry must >= 0" } require(retry >= 0) { "retry must >= 0" }
check(bot.isActive) { "bot is dead therefore can't send any packet" } check(bot.isActive) { "bot is dead therefore can't send ${this.commandName}" }
check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" }
suspend fun doSendAndReceive(handler: PacketListener, data: Any, length: Int): E { suspend fun doSendAndReceive(handler: PacketListener, data: Any, length: Int): E {
...@@ -607,8 +641,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -607,8 +641,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
is ByteReadPacket -> channel.send(data) is ByteReadPacket -> channel.send(data)
else -> error("Internal error: unexpected data type: ${data::class.simpleName}") else -> error("Internal error: unexpected data type: ${data::class.simpleName}")
} }
logger.verbose { "Send: $commandName" }
logger.verbose { "Send done: $commandName" }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return withTimeoutOrNull(timeoutMillis) { return withTimeoutOrNull(timeoutMillis) {
...@@ -651,6 +684,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -651,6 +684,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
this.commandName == commandName && this.sequenceId == sequenceId this.commandName == commandName && this.sequenceId == sequenceId
} }
init {
this.supervisor.invokeOnCompletion {
close(it)
}
}
override fun close(cause: Throwable?) { override fun close(cause: Throwable?) {
if (::channel.isInitialized) { if (::channel.isInitialized) {
channel.close() channel.close()
......
...@@ -173,7 +173,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -173,7 +173,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
if (e.killBot) { if (e.killBot) {
throw e throw e
} else { } else {
logger.warning("Login failed. Retrying in 3s...") logger.warning { "Login failed. Retrying in 3s..." }
_network.closeAndJoin(e) _network.closeAndJoin(e)
delay(3000) delay(3000)
continue continue
...@@ -182,35 +182,34 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -182,35 +182,34 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
network.logger.error(e) network.logger.error(e)
_network.closeAndJoin(e) _network.closeAndJoin(e)
} }
logger.warning("Login failed. Retrying in 3s...") logger.warning { "Login failed. Retrying in 3s..." }
delay(3000) delay(3000)
} }
} }
suspend fun doInit() { suspend fun doInit() {
retryCatching(2) { count, lastException -> retryCatching(5) { count, lastException ->
if (count != 0) { if (count != 0) {
if (!isActive) { if (!isActive) {
logger.error("Cannot init due to fatal error") logger.error("Cannot init due to fatal error")
if (lastException == null) { throw lastException ?: error("<No lastException>")
logger.error("<no exception>")
} else {
logger.error(lastException)
}
} }
logger.warning("Init failed. Retrying in 3s...") logger.warning { "Init failed. Retrying in 3s..." }
delay(3000) delay(3000)
} }
_network.init() _network.init()
}.getOrElse { }.getOrElse {
network.logger.error(it) logger.error { "Cannot init. some features may be affected" }
logger.error("Cannot init. some features may be affected") throw it // abort
} }
} }
// logger.info("Initializing BotNetworkHandler") // logger.info("Initializing BotNetworkHandler")
if (::_network.isInitialized) { if (::_network.isInitialized) {
_network.cancel(CancellationException("manual re-login", cause = cause))
BotReloginEvent(this, cause).broadcast() BotReloginEvent(this, cause).broadcast()
doRelogin() doRelogin()
return return
...@@ -220,7 +219,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -220,7 +219,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
doInit() doInit()
} }
logger.info("Logging in...") logger.info { "Logging in..." }
if (::_network.isInitialized) { if (::_network.isInitialized) {
network.withConnectionLock { network.withConnectionLock {
@OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class) @OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class)
...@@ -230,7 +229,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -230,7 +229,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
@OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class) @OptIn(ThisApiMustBeUsedInWithConnectionLockBlock::class)
reinitializeNetworkHandler(null) reinitializeNetworkHandler(null)
} }
logger.info("Login successful") logger.info { "Login successful" }
} }
protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N
...@@ -241,7 +240,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -241,7 +240,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
init { init {
coroutineContext[Job]!!.invokeOnCompletion { throwable -> coroutineContext[Job]!!.invokeOnCompletion { throwable ->
network.close(throwable) network.close(throwable)
offlineListener.cancel(CancellationException("bot cancelled", throwable)) offlineListener.cancel(CancellationException("Bot cancelled", throwable))
groups.delegate.clear() // job is cancelled, so child jobs are to be cancelled groups.delegate.clear() // job is cancelled, so child jobs are to be cancelled
friends.delegate.clear() friends.delegate.clear()
......
...@@ -40,6 +40,7 @@ import net.mamoe.mirai.utils.WeakRefProperty ...@@ -40,6 +40,7 @@ import net.mamoe.mirai.utils.WeakRefProperty
* *
* @suppress 此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告. * @suppress 此为**内部 API**, 可能在任意时刻被改动, 且不会给出任何警告.
*/ */
@MiraiInternalAPI
@Suppress("PropertyName") @Suppress("PropertyName")
abstract class BotNetworkHandler : CoroutineScope { abstract class BotNetworkHandler : CoroutineScope {
...@@ -122,6 +123,7 @@ abstract class BotNetworkHandler : CoroutineScope { ...@@ -122,6 +123,7 @@ abstract class BotNetworkHandler : CoroutineScope {
} }
} }
@MiraiInternalAPI
@OptIn(MiraiInternalAPI::class) @OptIn(MiraiInternalAPI::class)
suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) { suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) {
this.close(cause) this.close(cause)
......
...@@ -31,6 +31,7 @@ open class BotConfiguration { ...@@ -31,6 +31,7 @@ open class BotConfiguration {
/** /**
* 网络层日志构造器 * 网络层日志构造器
*/ */
@OptIn(MiraiInternalAPI::class)
var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.id})") } var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.id})") }
/** /**
...@@ -85,6 +86,7 @@ open class BotConfiguration { ...@@ -85,6 +86,7 @@ open class BotConfiguration {
/** /**
* 不显示网络日志 * 不显示网络日志
*/ */
@OptIn(MiraiInternalAPI::class)
@ConfigurationDsl @ConfigurationDsl
fun noNetworkLog() { fun noNetworkLog() {
networkLoggerSupplier = { _: BotNetworkHandler -> SilentLogger } networkLoggerSupplier = { _: BotNetworkHandler -> SilentLogger }
......
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