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
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
set(HeartbeatProcessor, HeartbeatProcessor())
set(HeartbeatProcessor, HeartbeatProcessorImpl())
set(KeyRefreshProcessor, KeyRefreshProcessorImpl(networkLogger))
set(ConfigPushProcessor, ConfigPushProcessorImpl(networkLogger))

View File

@ -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 <T : Any> get(key: ComponentKey<T>): T
fun <T : Any> getOrNull(key: ComponentKey<T>): T?
val keys: Set<ComponentKey<*>>
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 {
private val map = ConcurrentHashMap<ComponentKey<*>, Any?>()
override val keys: Set<ComponentKey<*>> get() = map.keys
override val size: Int get() = map.size
override operator fun <T : Any> get(key: ComponentKey<T>): T {

View File

@ -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")
) : 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.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()

View File

@ -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<ContactCacheService>
}

View File

@ -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<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.sendAndExpect
internal class HeartbeatProcessor {
internal interface HeartbeatProcessor {
@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(
networkHandler,
timeoutMillis = networkHandler.context[SsoProcessorContext].configuration.heartbeatTimeoutMillis,
retry = 2
)
}
companion object : ComponentKey<HeartbeatProcessor>
}

View File

@ -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<ServerAddress>)
/**
* Might return [DEFAULT_SERVER_LIST] if not present.
*/
fun getPreferred(): Set<ServerAddress>
/**
* 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<ServerAddress> = emptyList()
) : ServerList {

View File

@ -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 {
///////////////////////////////////////////////////////////////////////////