mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-10 19:54:51 +08:00
Extract sync logic
This commit is contained in:
parent
076cd4997d
commit
f9ddf74d8e
@ -63,6 +63,22 @@ public fun CoroutineScope.childScope(
|
|||||||
public fun CoroutineContext.childScope(
|
public fun CoroutineContext.childScope(
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
): CoroutineScope {
|
): CoroutineScope {
|
||||||
|
return CoroutineScope(this.childScopeContext(coroutineContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a child scope of the receiver context scope.
|
||||||
|
*/
|
||||||
|
public fun CoroutineContext.childScopeContext(
|
||||||
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
|
): CoroutineContext {
|
||||||
val ctx = this + coroutineContext
|
val ctx = this + coroutineContext
|
||||||
return CoroutineScope(ctx + SupervisorJob(ctx.job))
|
return ctx + SupervisorJob(ctx.job)
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun <E : U, U : CoroutineContext.Element> CoroutineContext.getOrElse(
|
||||||
|
key: CoroutineContext.Key<E>,
|
||||||
|
default: () -> U
|
||||||
|
): U {
|
||||||
|
return this[key] ?: default()
|
||||||
}
|
}
|
@ -18,27 +18,24 @@
|
|||||||
package net.mamoe.mirai.internal
|
package net.mamoe.mirai.internal
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.Mirai
|
import net.mamoe.mirai.Mirai
|
||||||
import net.mamoe.mirai.contact.*
|
import net.mamoe.mirai.contact.*
|
||||||
import net.mamoe.mirai.event.ConcurrencyKind
|
|
||||||
import net.mamoe.mirai.event.EventChannel
|
import net.mamoe.mirai.event.EventChannel
|
||||||
import net.mamoe.mirai.event.EventPriority.MONITOR
|
|
||||||
import net.mamoe.mirai.event.GlobalEventChannel
|
import net.mamoe.mirai.event.GlobalEventChannel
|
||||||
import net.mamoe.mirai.event.Listener
|
|
||||||
import net.mamoe.mirai.event.events.BotEvent
|
import net.mamoe.mirai.event.events.BotEvent
|
||||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
|
||||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
||||||
import net.mamoe.mirai.internal.contact.uin
|
import net.mamoe.mirai.internal.contact.uin
|
||||||
|
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
||||||
import net.mamoe.mirai.supervisorJob
|
import net.mamoe.mirai.supervisorJob
|
||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.measureTime
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protocol-irrelevant implementations
|
||||||
|
*/
|
||||||
internal abstract class AbstractBot constructor(
|
internal abstract class AbstractBot constructor(
|
||||||
final override val configuration: BotConfiguration,
|
final override val configuration: BotConfiguration,
|
||||||
final override val id: Long,
|
final override val id: Long,
|
||||||
@ -48,20 +45,17 @@ internal abstract class AbstractBot constructor(
|
|||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// FASTEST INIT
|
// FASTEST INIT
|
||||||
private val supervisor = SupervisorJob(configuration.parentCoroutineContext[Job])
|
|
||||||
|
|
||||||
final override val logger: MiraiLogger by lazy { configuration.botLoggerSupplier(this) }
|
final override val logger: MiraiLogger by lazy { configuration.botLoggerSupplier(this) }
|
||||||
|
|
||||||
final override val coroutineContext: CoroutineContext = // for id
|
final override val coroutineContext: CoroutineContext = configuration.parentCoroutineContext.childScopeContext(
|
||||||
configuration.parentCoroutineContext
|
configuration.parentCoroutineContext.getOrElse(CoroutineExceptionHandler) {
|
||||||
.plus(supervisor)
|
CoroutineExceptionHandler { _, e ->
|
||||||
.plus(
|
logger.error("An exception was thrown under a coroutine of Bot", e)
|
||||||
configuration.parentCoroutineContext[CoroutineExceptionHandler]
|
}
|
||||||
?: CoroutineExceptionHandler { _, e ->
|
} + CoroutineName("Mirai Bot")
|
||||||
logger.error("An exception was thrown under a coroutine of Bot", e)
|
)
|
||||||
}
|
|
||||||
)
|
abstract val components: ConcurrentComponentStorage
|
||||||
.plus(CoroutineName("Mirai Bot"))
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@Suppress("LeakingThis")
|
@Suppress("LeakingThis")
|
||||||
@ -87,86 +81,6 @@ internal abstract class AbstractBot constructor(
|
|||||||
final override val asFriend: Friend by lazy { Mirai.newFriend(this, FriendInfoImpl(uin, nick, "")) }
|
final override val asFriend: Friend by lazy { Mirai.newFriend(this, FriendInfoImpl(uin, nick, "")) }
|
||||||
final override val asStranger: Stranger by lazy { Mirai.newStranger(bot, StrangerInfoImpl(bot.id, bot.nick)) }
|
final override val asStranger: Stranger by lazy { Mirai.newStranger(bot, StrangerInfoImpl(bot.id, bot.nick)) }
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// sync (// TODO: 2021/4/14 extract sync logic
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
val otherClientsLock = Mutex() // lock sync
|
|
||||||
|
|
||||||
// TODO: 2021/4/14 extract offlineListener
|
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
@Suppress("unused")
|
|
||||||
private val offlineListener: Listener<BotOfflineEvent> =
|
|
||||||
this@AbstractBot.eventChannel.parentJob(supervisor).subscribeAlways(
|
|
||||||
priority = MONITOR,
|
|
||||||
concurrency = ConcurrencyKind.LOCKED
|
|
||||||
) { event ->
|
|
||||||
val bot = bot.asQQAndroidBot()
|
|
||||||
if (
|
|
||||||
!event.bot.isActive // bot closed
|
|
||||||
// || _isConnecting // bot 还在登入 // TODO: 2021/4/14 处理还在登入?
|
|
||||||
) {
|
|
||||||
// Close network to avoid endless reconnection while network is ok
|
|
||||||
// https://github.com/mamoe/mirai/issues/894
|
|
||||||
kotlin.runCatching { network.close(null) }
|
|
||||||
return@subscribeAlways
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (network.areYouOk() && event !is BotOfflineEvent.Force && event !is BotOfflineEvent.MsfOffline) {
|
|
||||||
// network 运行正常
|
|
||||||
return@subscribeAlways
|
|
||||||
}*/
|
|
||||||
when (event) {
|
|
||||||
is BotOfflineEvent.Active -> {
|
|
||||||
val cause = event.cause
|
|
||||||
val msg = if (cause == null) "" else " with exception: $cause"
|
|
||||||
bot.logger.info("Bot is closed manually $msg", cause)
|
|
||||||
network.close(null)
|
|
||||||
}
|
|
||||||
is BotOfflineEvent.Force -> {
|
|
||||||
bot.logger.info { "Connection occupied by another android device: ${event.message}" }
|
|
||||||
bot.asQQAndroidBot().accountSecretsFile.delete()
|
|
||||||
bot.client = bot.initClient()
|
|
||||||
if (event.reconnect) {
|
|
||||||
bot.logger.info { "Reconnecting..." }
|
|
||||||
// delay(3000)
|
|
||||||
} else {
|
|
||||||
network.close(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is BotOfflineEvent.MsfOffline,
|
|
||||||
is BotOfflineEvent.Dropped,
|
|
||||||
is BotOfflineEvent.RequireReconnect,
|
|
||||||
is BotOfflineEvent.PacketFactoryErrorCode
|
|
||||||
-> {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.reconnect) {
|
|
||||||
if (!network.isOk()) {
|
|
||||||
// normally closed
|
|
||||||
return@subscribeAlways
|
|
||||||
}
|
|
||||||
|
|
||||||
val causeMessage = event.castOrNull<BotOfflineEvent.CauseAware>()?.cause?.toString() ?: event.toString()
|
|
||||||
bot.logger.info { "Connection lost, retrying login ($causeMessage)" }
|
|
||||||
|
|
||||||
bot.launch {
|
|
||||||
val success: Boolean
|
|
||||||
val time = measureTime {
|
|
||||||
success = TODO("relogin")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
logger.info { "Reconnected successfully in ${time.toHumanReadableString()}" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// network
|
// network
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
@ -191,7 +105,6 @@ internal abstract class AbstractBot constructor(
|
|||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
network.close(throwable)
|
network.close(throwable)
|
||||||
}
|
}
|
||||||
offlineListener.cancel(CancellationException("Bot cancelled", throwable))
|
|
||||||
|
|
||||||
// help GC release instances
|
// help GC release instances
|
||||||
groups.forEach {
|
groups.forEach {
|
||||||
|
@ -121,7 +121,7 @@ internal open class QQAndroidBot constructor(
|
|||||||
|
|
||||||
|
|
||||||
private val networkLogger: MiraiLogger by lazy { configuration.networkLoggerSupplier(this) }
|
private val networkLogger: MiraiLogger by lazy { configuration.networkLoggerSupplier(this) }
|
||||||
internal val components: ConcurrentComponentStorage by lazy {
|
override val components: ConcurrentComponentStorage by lazy {
|
||||||
ConcurrentComponentStorage().apply {
|
ConcurrentComponentStorage().apply {
|
||||||
val components = this // avoid mistakes
|
val components = this // avoid mistakes
|
||||||
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
|
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
|
||||||
|
@ -53,6 +53,8 @@ import net.mamoe.mirai.utils.verbose
|
|||||||
* Uses [ContactCacheService].
|
* Uses [ContactCacheService].
|
||||||
*/
|
*/
|
||||||
internal interface ContactUpdater {
|
internal interface ContactUpdater {
|
||||||
|
val otherClientsLock: Mutex
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load all caches to the bot this [ContactUpdater] works for.
|
* Load all caches to the bot this [ContactUpdater] works for.
|
||||||
*
|
*
|
||||||
@ -75,6 +77,7 @@ internal class ContactUpdaterImpl(
|
|||||||
val components: ComponentStorage,
|
val components: ComponentStorage,
|
||||||
private val logger: MiraiLogger,
|
private val logger: MiraiLogger,
|
||||||
) : ContactUpdater {
|
) : ContactUpdater {
|
||||||
|
override val otherClientsLock: Mutex = Mutex()
|
||||||
private val cacheService get() = components[ContactCacheService]
|
private val cacheService get() = components[ContactCacheService]
|
||||||
private val lock = Mutex()
|
private val lock = Mutex()
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import net.mamoe.mirai.internal.contact.appId
|
|||||||
import net.mamoe.mirai.internal.contact.createOtherClient
|
import net.mamoe.mirai.internal.contact.createOtherClient
|
||||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
|
import net.mamoe.mirai.internal.network.components.ContactUpdater
|
||||||
import net.mamoe.mirai.internal.network.handler.logger
|
import net.mamoe.mirai.internal.network.handler.logger
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||||
@ -36,7 +37,7 @@ internal object MessageSvcRequestPushStatus : IncomingPacketFactory<Packet?>(
|
|||||||
) {
|
) {
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
|
||||||
val packet = readUniPacket(RequestPushStatus.serializer())
|
val packet = readUniPacket(RequestPushStatus.serializer())
|
||||||
bot.otherClientsLock.withLock {
|
bot.components[ContactUpdater].otherClientsLock.withLock {
|
||||||
val instanceInfo = packet.vecInstanceList?.firstOrNull()
|
val instanceInfo = packet.vecInstanceList?.firstOrNull()
|
||||||
val appId = instanceInfo?.iAppId ?: 1
|
val appId = instanceInfo?.iAppId ?: 1
|
||||||
return when (packet.status.toInt()) {
|
return when (packet.status.toInt()) {
|
||||||
|
@ -29,6 +29,7 @@ import net.mamoe.mirai.internal.contact.createOtherClient
|
|||||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||||
import net.mamoe.mirai.internal.network.*
|
import net.mamoe.mirai.internal.network.*
|
||||||
import net.mamoe.mirai.internal.network.components.ContactCacheService
|
import net.mamoe.mirai.internal.network.components.ContactCacheService
|
||||||
|
import net.mamoe.mirai.internal.network.components.ContactUpdater
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.*
|
import net.mamoe.mirai.internal.network.protocol.data.jce.*
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
|
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline
|
import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline
|
||||||
@ -232,11 +233,6 @@ internal class StatSvc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun String.ipToLong(): Long {
|
|
||||||
return split('.').foldIndexed(0L) { index: Int, acc: Long, s: String ->
|
|
||||||
acc or (((s.toLongOrNull() ?: 0) shl (index * 16)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object ReqMSFOffline :
|
internal object ReqMSFOffline :
|
||||||
@ -283,7 +279,7 @@ internal class StatSvc {
|
|||||||
IncomingPacketFactory<Packet?>("StatSvc.SvcReqMSFLoginNotify", "StatSvc.SvcReqMSFLoginNotify") {
|
IncomingPacketFactory<Packet?>("StatSvc.SvcReqMSFLoginNotify", "StatSvc.SvcReqMSFLoginNotify") {
|
||||||
|
|
||||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? =
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? =
|
||||||
bot.otherClientsLock.withLock {
|
bot.components[ContactUpdater].otherClientsLock.withLock {
|
||||||
val notify = readUniPacket(SvcReqMSFLoginNotifyData.serializer())
|
val notify = readUniPacket(SvcReqMSFLoginNotifyData.serializer())
|
||||||
|
|
||||||
val appId = notify.iAppId.toInt()
|
val appId = notify.iAppId.toInt()
|
||||||
|
Loading…
Reference in New Issue
Block a user