From 4f77abca87fdc276e748f8807c78481f6c87f756 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 24 Apr 2021 12:05:50 +0800 Subject: [PATCH] Components misc implementations including (ABI changes): - ComponentStorage and its impls - ContactCacheService - ContactUpdater - HeartbeatProcessor - SsoProcessor - QQABot --- .../src/commonMain/kotlin/QQAndroidBot.kt | 2 +- .../network/component/ComponentStorage.kt | 39 ++++++++++++++++++- .../component/ConcurrentComponentStorage.kt | 1 + .../component/NoSuchComponentException.kt | 9 ++++- .../network/components/BotInitProcessor.kt | 8 ++++ .../network/components/ContactCacheService.kt | 11 ++++-- .../network/components/ContactUpdater.kt | 15 ++++++- .../network/components/HeartbeatProcessor.kt | 13 +++++-- .../kotlin/network/components/ServerList.kt | 20 ++++++++-- .../kotlin/network/components/SsoProcessor.kt | 5 +-- 10 files changed, 105 insertions(+), 18 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index c3814f94a..c6f5bd88a 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -105,7 +105,7 @@ internal class QQAndroidBot constructor( val components = this // avoid mistakes set(SsoProcessorContext, SsoProcessorContextImpl(bot)) set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext))) - set(HeartbeatProcessor, HeartbeatProcessor()) + set(HeartbeatProcessor, HeartbeatProcessorImpl()) set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger)) set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger)) diff --git a/mirai-core/src/commonMain/kotlin/network/component/ComponentStorage.kt b/mirai-core/src/commonMain/kotlin/network/component/ComponentStorage.kt index f89ab5859..4af814a5d 100644 --- a/mirai-core/src/commonMain/kotlin/network/component/ComponentStorage.kt +++ b/mirai-core/src/commonMain/kotlin/network/component/ComponentStorage.kt @@ -12,9 +12,13 @@ package net.mamoe.mirai.internal.network.component import org.jetbrains.annotations.TestOnly /** - * Facade for [component][ComponentKey]s. Implementation must be thread-safe. + * Mediator for [component][ComponentKey]s accessing each other. + * + * Implementation must be thread-safe. + * * @see MutableComponentStorage * @see ConcurrentComponentStorage + * @see plus */ internal interface ComponentStorage { @get:TestOnly @@ -24,6 +28,39 @@ internal interface ComponentStorage { operator fun get(key: ComponentKey): T fun getOrNull(key: ComponentKey): T? + val keys: Set> + override fun toString(): String } +internal operator fun ComponentStorage.plus(fallback: ComponentStorage): ComponentStorage = + CombinedComponentStorage(this, fallback) + +private class CombinedComponentStorage( + val main: ComponentStorage, + val fallback: ComponentStorage, +) : ComponentStorage { + override val keys: Set> get() = main.keys + fallback.keys + override val size: Int get() = keys.size + + override fun get(key: ComponentKey): T { + return main.getOrNull(key) ?: fallback.getOrNull(key) ?: main[key] // let `main` throw exception + } + + override fun getOrNull(key: ComponentKey): T? { + return main.getOrNull(key) ?: fallback.getOrNull(key) + } + + override fun toString(): String = buildString { + appendLine("CombinedComponentStorage {") + appendLine("* main:") + main.toString().lines().forEach { + append(" ").appendLine(it) + } + appendLine("*** fallback:") + fallback.toString().lines().forEach { + append(" ").appendLine(it) + } + appendLine("}") + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/component/ConcurrentComponentStorage.kt b/mirai-core/src/commonMain/kotlin/network/component/ConcurrentComponentStorage.kt index 5f51ffb15..ff78a0186 100644 --- a/mirai-core/src/commonMain/kotlin/network/component/ConcurrentComponentStorage.kt +++ b/mirai-core/src/commonMain/kotlin/network/component/ConcurrentComponentStorage.kt @@ -20,6 +20,7 @@ internal class ConcurrentComponentStorage( ) : ComponentStorage, MutableComponentStorage { private val map = ConcurrentHashMap, Any?>() + override val keys: Set> get() = map.keys override val size: Int get() = map.size override operator fun get(key: ComponentKey): T { diff --git a/mirai-core/src/commonMain/kotlin/network/component/NoSuchComponentException.kt b/mirai-core/src/commonMain/kotlin/network/component/NoSuchComponentException.kt index ae320f5b3..67d41feea 100644 --- a/mirai-core/src/commonMain/kotlin/network/component/NoSuchComponentException.kt +++ b/mirai-core/src/commonMain/kotlin/network/component/NoSuchComponentException.kt @@ -9,7 +9,14 @@ package net.mamoe.mirai.internal.network.component +/** + * Should not be thrown normally. + */ internal data class NoSuchComponentException( val key: ComponentKey<*>, val storage: ComponentStorage -) : NoSuchElementException("No such component: $key") \ No newline at end of file +) : NoSuchElementException() { + override val message: String by lazy { + "No such component '$key' in storage: \n$storage" + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt b/mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt index 5eb9a63da..60e818f3f 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt @@ -16,6 +16,7 @@ import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.component.ComponentKey import net.mamoe.mirai.internal.network.component.ComponentStorage +import net.mamoe.mirai.internal.network.handler.NetworkHandler import net.mamoe.mirai.internal.network.handler.NetworkHandler.State import net.mamoe.mirai.internal.network.handler.state.JobAttachStateObserver import net.mamoe.mirai.internal.network.handler.state.StateObserver @@ -28,6 +29,13 @@ import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.info + +/** + * Facade of [ContactUpdater], [OtherClientUpdater], [ConfigPushSyncer]. + * Handles initialization jobs after successful logon. + * + * Attached to handler state [NetworkHandler.State.LOADING] [as state observer][asObserver]. + */ internal interface BotInitProcessor { suspend fun init() diff --git a/mirai-core/src/commonMain/kotlin/network/components/ContactCacheService.kt b/mirai-core/src/commonMain/kotlin/network/components/ContactCacheService.kt index 8561f8791..5deecc3c2 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/ContactCacheService.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/ContactCacheService.kt @@ -22,13 +22,16 @@ import net.mamoe.mirai.utils.loadNotBlankAs import net.mamoe.mirai.utils.runBIO /** - * Maintains cache. Used by [ContactUpdater]. + * Strategy of caching contacts. Used by [ContactUpdater]. */ internal interface ContactCacheService { - val friendListCache: FriendListCache? - val groupMemberListCaches: GroupMemberListCaches? + val friendListCache: FriendListCache? // from old code + val groupMemberListCaches: GroupMemberListCaches? // from old code - fun saveFriendCache() + /** + * Implementation does not need to be thread-safe. + */ + fun saveFriendCache() // from old code companion object : ComponentKey } diff --git a/mirai-core/src/commonMain/kotlin/network/components/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/components/ContactUpdater.kt index f22c3ebb1..399456541 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/ContactUpdater.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/ContactUpdater.kt @@ -18,6 +18,7 @@ import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withPermit import net.mamoe.mirai.Mirai +import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.internal.QQAndroidBot @@ -47,11 +48,23 @@ import net.mamoe.mirai.utils.retryCatching import net.mamoe.mirai.utils.verbose /** - * Uses [ContactCacheService] + * Manager of caches for [Contact]s. + * + * Uses [ContactCacheService]. */ internal interface ContactUpdater { + /** + * Load all caches to the bot this [ContactUpdater] works for. + * + * Implementation must be thread-safe. + */ suspend fun loadAll(registerResp: SvcRespRegister) + /** + * Closes all contacts and save them to cache if needed. + * + * Implementation must be thread-safe. + */ fun closeAllContacts(e: CancellationException) companion object : ComponentKey diff --git a/mirai-core/src/commonMain/kotlin/network/components/HeartbeatProcessor.kt b/mirai-core/src/commonMain/kotlin/network/components/HeartbeatProcessor.kt index 9d5b0d709..ebeb86c42 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/HeartbeatProcessor.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/HeartbeatProcessor.kt @@ -15,16 +15,21 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect -internal class HeartbeatProcessor { +internal interface HeartbeatProcessor { @Throws(Exception::class) - suspend fun doHeartbeatNow(networkHandler: NetworkHandler) { + suspend fun doHeartbeatNow(networkHandler: NetworkHandler) + + companion object : ComponentKey +} + +internal class HeartbeatProcessorImpl : HeartbeatProcessor { + @Throws(Exception::class) + override suspend fun doHeartbeatNow(networkHandler: NetworkHandler) { StatSvc.SimpleGet(networkHandler.context.bot.client).sendAndExpect( networkHandler, timeoutMillis = networkHandler.context[SsoProcessorContext].configuration.heartbeatTimeoutMillis, retry = 2 ) } - - companion object : ComponentKey } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt index d5a621ba4..6841b5b46 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt @@ -28,10 +28,27 @@ internal data class ServerAddress( fun toSocketAddress(): InetSocketAddress = InetSocketAddress.createUnresolved(host, port) } +/** + * Self-refillable (similarly circular) queue of servers. Pop each time when trying to connect. + * + * [Preferred][getPreferred] prevails if present than [DEFAULT_SERVER_LIST]. + * + * *+Implementation must be thread-safe**. + */ internal interface ServerList { + /** + * Set preferred so not using [DEFAULT_SERVER_LIST]. + */ fun setPreferred(list: Collection) + + /** + * Might return [DEFAULT_SERVER_LIST] if not present. + */ fun getPreferred(): Set + /** + * Refill the queue. Mostly do not call this function. + */ fun refresh() /** @@ -60,9 +77,6 @@ internal interface ServerList { } } -/** - * Queue of servers. Pop each time when trying to connect. - */ internal class ServerListImpl( initial: Collection = emptyList() ) : ServerList { diff --git a/mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt b/mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt index 33804e888..b16400c00 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt @@ -41,7 +41,6 @@ import net.mamoe.mirai.utils.withExceptionCollector * Handles login, and acts also as a mediator of [BotInitProcessor], [] */ internal interface SsoProcessor { - val ssoContext: SsoProcessorContext val client: QQAndroidClient val ssoSession: SsoSession @@ -50,7 +49,7 @@ internal interface SsoProcessor { * * E.g. start heartbeat job for [NetworkHandler.State.OK]. */ - fun createObserverChain(): StateObserver + fun createObserverChain(): StateObserver // todo not used /** * Do login. Throws [LoginFailedException] if failed @@ -69,7 +68,7 @@ internal interface SsoProcessor { * Used by [NettyNetworkHandler.StateConnecting]. */ internal class SsoProcessorImpl( - override val ssoContext: SsoProcessorContext, + val ssoContext: SsoProcessorContext, ) : SsoProcessor { ///////////////////////////////////////////////////////////////////////////