Components misc implementations including (ABI changes):

- ComponentStorage and its impls
- ContactCacheService
- ContactUpdater
- HeartbeatProcessor
- SsoProcessor
- QQABot
This commit is contained in:
Him188 2021-04-24 12:05:50 +08:00
parent 7f2f1e9759
commit 4f77abca87
10 changed files with 105 additions and 18 deletions

View File

@ -105,7 +105,7 @@ internal class QQAndroidBot constructor(
val components = this // avoid mistakes val components = this // avoid mistakes
set(SsoProcessorContext, SsoProcessorContextImpl(bot)) set(SsoProcessorContext, SsoProcessorContextImpl(bot))
set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext))) set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
set(HeartbeatProcessor, HeartbeatProcessor()) set(HeartbeatProcessor, HeartbeatProcessorImpl())
set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger)) set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger))
set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger)) set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger))

View File

@ -12,9 +12,13 @@ package net.mamoe.mirai.internal.network.component
import org.jetbrains.annotations.TestOnly 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 MutableComponentStorage
* @see ConcurrentComponentStorage * @see ConcurrentComponentStorage
* @see plus
*/ */
internal interface ComponentStorage { internal interface ComponentStorage {
@get:TestOnly @get:TestOnly
@ -24,6 +28,39 @@ internal interface ComponentStorage {
operator fun <T : Any> get(key: ComponentKey<T>): T operator fun <T : Any> get(key: ComponentKey<T>): T
fun <T : Any> getOrNull(key: ComponentKey<T>): T? fun <T : Any> getOrNull(key: ComponentKey<T>): T?
val keys: Set<ComponentKey<*>>
override fun toString(): String 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<ComponentKey<*>> get() = main.keys + fallback.keys
override val size: Int get() = keys.size
override fun <T : Any> get(key: ComponentKey<T>): T {
return main.getOrNull(key) ?: fallback.getOrNull(key) ?: main[key] // let `main` throw exception
}
override fun <T : Any> getOrNull(key: ComponentKey<T>): 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("}")
}
}

View File

@ -20,6 +20,7 @@ internal class ConcurrentComponentStorage(
) : ComponentStorage, MutableComponentStorage { ) : ComponentStorage, MutableComponentStorage {
private val map = ConcurrentHashMap<ComponentKey<*>, Any?>() private val map = ConcurrentHashMap<ComponentKey<*>, Any?>()
override val keys: Set<ComponentKey<*>> get() = map.keys
override val size: Int get() = map.size override val size: Int get() = map.size
override operator fun <T : Any> get(key: ComponentKey<T>): T { override operator fun <T : Any> get(key: ComponentKey<T>): T {

View File

@ -9,7 +9,14 @@
package net.mamoe.mirai.internal.network.component package net.mamoe.mirai.internal.network.component
/**
* Should not be thrown normally.
*/
internal data class NoSuchComponentException( internal data class NoSuchComponentException(
val key: ComponentKey<*>, val key: ComponentKey<*>,
val storage: ComponentStorage val storage: ComponentStorage
) : NoSuchElementException("No such component: $key") ) : NoSuchElementException() {
override val message: String by lazy {
"No such component '$key' in storage: \n$storage"
}
}

View File

@ -16,6 +16,7 @@ import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.internal.network.component.ComponentKey import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.internal.network.component.ComponentStorage 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.NetworkHandler.State
import net.mamoe.mirai.internal.network.handler.state.JobAttachStateObserver import net.mamoe.mirai.internal.network.handler.state.JobAttachStateObserver
import net.mamoe.mirai.internal.network.handler.state.StateObserver 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.MiraiLogger
import net.mamoe.mirai.utils.info 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 { internal interface BotInitProcessor {
suspend fun init() suspend fun init()

View File

@ -22,13 +22,16 @@ import net.mamoe.mirai.utils.loadNotBlankAs
import net.mamoe.mirai.utils.runBIO import net.mamoe.mirai.utils.runBIO
/** /**
* Maintains cache. Used by [ContactUpdater]. * Strategy of caching contacts. Used by [ContactUpdater].
*/ */
internal interface ContactCacheService { internal interface ContactCacheService {
val friendListCache: FriendListCache? val friendListCache: FriendListCache? // from old code
val groupMemberListCaches: GroupMemberListCaches? val groupMemberListCaches: GroupMemberListCaches? // from old code
fun saveFriendCache() /**
* Implementation does not need to be thread-safe.
*/
fun saveFriendCache() // from old code
companion object : ComponentKey<ContactCacheService> companion object : ComponentKey<ContactCacheService>
} }

View File

@ -18,6 +18,7 @@ import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.data.FriendInfo
import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.QQAndroidBot
@ -47,11 +48,23 @@ import net.mamoe.mirai.utils.retryCatching
import net.mamoe.mirai.utils.verbose import net.mamoe.mirai.utils.verbose
/** /**
* Uses [ContactCacheService] * Manager of caches for [Contact]s.
*
* Uses [ContactCacheService].
*/ */
internal interface ContactUpdater { internal interface ContactUpdater {
/**
* Load all caches to the bot this [ContactUpdater] works for.
*
* Implementation must be thread-safe.
*/
suspend fun loadAll(registerResp: SvcRespRegister) suspend fun loadAll(registerResp: SvcRespRegister)
/**
* Closes all contacts and save them to cache if needed.
*
* Implementation must be thread-safe.
*/
fun closeAllContacts(e: CancellationException) fun closeAllContacts(e: CancellationException)
companion object : ComponentKey<ContactUpdater> companion object : ComponentKey<ContactUpdater>

View File

@ -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.login.StatSvc
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
internal class HeartbeatProcessor { internal interface HeartbeatProcessor {
@Throws(Exception::class) @Throws(Exception::class)
suspend fun doHeartbeatNow(networkHandler: NetworkHandler) { suspend fun doHeartbeatNow(networkHandler: NetworkHandler)
companion object : ComponentKey<HeartbeatProcessor>
}
internal class HeartbeatProcessorImpl : HeartbeatProcessor {
@Throws(Exception::class)
override suspend fun doHeartbeatNow(networkHandler: NetworkHandler) {
StatSvc.SimpleGet(networkHandler.context.bot.client).sendAndExpect( StatSvc.SimpleGet(networkHandler.context.bot.client).sendAndExpect(
networkHandler, networkHandler,
timeoutMillis = networkHandler.context[SsoProcessorContext].configuration.heartbeatTimeoutMillis, timeoutMillis = networkHandler.context[SsoProcessorContext].configuration.heartbeatTimeoutMillis,
retry = 2 retry = 2
) )
} }
companion object : ComponentKey<HeartbeatProcessor>
} }

View File

@ -28,10 +28,27 @@ internal data class ServerAddress(
fun toSocketAddress(): InetSocketAddress = InetSocketAddress.createUnresolved(host, port) 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 { internal interface ServerList {
/**
* Set preferred so not using [DEFAULT_SERVER_LIST].
*/
fun setPreferred(list: Collection<ServerAddress>) fun setPreferred(list: Collection<ServerAddress>)
/**
* Might return [DEFAULT_SERVER_LIST] if not present.
*/
fun getPreferred(): Set<ServerAddress> fun getPreferred(): Set<ServerAddress>
/**
* Refill the queue. Mostly do not call this function.
*/
fun refresh() fun refresh()
/** /**
@ -60,9 +77,6 @@ internal interface ServerList {
} }
} }
/**
* Queue of servers. Pop each time when trying to connect.
*/
internal class ServerListImpl( internal class ServerListImpl(
initial: Collection<ServerAddress> = emptyList() initial: Collection<ServerAddress> = emptyList()
) : ServerList { ) : ServerList {

View File

@ -41,7 +41,6 @@ import net.mamoe.mirai.utils.withExceptionCollector
* Handles login, and acts also as a mediator of [BotInitProcessor], [] * Handles login, and acts also as a mediator of [BotInitProcessor], []
*/ */
internal interface SsoProcessor { internal interface SsoProcessor {
val ssoContext: SsoProcessorContext
val client: QQAndroidClient val client: QQAndroidClient
val ssoSession: SsoSession val ssoSession: SsoSession
@ -50,7 +49,7 @@ internal interface SsoProcessor {
* *
* E.g. start heartbeat job for [NetworkHandler.State.OK]. * E.g. start heartbeat job for [NetworkHandler.State.OK].
*/ */
fun createObserverChain(): StateObserver fun createObserverChain(): StateObserver // todo not used
/** /**
* Do login. Throws [LoginFailedException] if failed * Do login. Throws [LoginFailedException] if failed
@ -69,7 +68,7 @@ internal interface SsoProcessor {
* Used by [NettyNetworkHandler.StateConnecting]. * Used by [NettyNetworkHandler.StateConnecting].
*/ */
internal class SsoProcessorImpl( internal class SsoProcessorImpl(
override val ssoContext: SsoProcessorContext, val ssoContext: SsoProcessorContext,
) : SsoProcessor { ) : SsoProcessor {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////