mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-01 12:28:38 +08:00
[core] Introduce CacheValidator for validating caches (#2388)
* [core] Export DeviceInfo.serializer() to mirai-core * [core] Introduce CacheValidator for validating caches
This commit is contained in:
parent
6365e23f2c
commit
553ea9abbc
@ -118,6 +118,8 @@ public expect class DeviceInfo(
|
|||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
public fun random(random: Random): DeviceInfo
|
public fun random(random: Random): DeviceInfo
|
||||||
|
|
||||||
|
public fun serializer(): KSerializer<DeviceInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +52,7 @@ import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
|
|||||||
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.utils.ImagePatcher
|
import net.mamoe.mirai.internal.utils.ImagePatcher
|
||||||
import net.mamoe.mirai.internal.utils.ImagePatcherImpl
|
import net.mamoe.mirai.internal.utils.ImagePatcherImpl
|
||||||
|
import net.mamoe.mirai.internal.utils.actualCacheDir
|
||||||
import net.mamoe.mirai.internal.utils.subLogger
|
import net.mamoe.mirai.internal.utils.subLogger
|
||||||
import net.mamoe.mirai.utils.BotConfiguration
|
import net.mamoe.mirai.utils.BotConfiguration
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
@ -208,6 +209,14 @@ internal open class QQAndroidBot constructor(
|
|||||||
|
|
||||||
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
|
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
|
||||||
set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
|
set(SsoProcessor, SsoProcessorImpl(get(SsoProcessorContext)))
|
||||||
|
|
||||||
|
val cacheValidator = CacheValidatorImpl(
|
||||||
|
get(SsoProcessorContext),
|
||||||
|
configuration.actualCacheDir().resolve("validator.bin"),
|
||||||
|
networkLogger.subLogger("CacheValidator"),
|
||||||
|
)
|
||||||
|
set(CacheValidator, cacheValidator)
|
||||||
|
|
||||||
set(HeartbeatProcessor, HeartbeatProcessorImpl())
|
set(HeartbeatProcessor, HeartbeatProcessorImpl())
|
||||||
set(HeartbeatScheduler, TimeBasedHeartbeatSchedulerImpl(networkLogger.subLogger("HeartbeatScheduler")))
|
set(HeartbeatScheduler, TimeBasedHeartbeatSchedulerImpl(networkLogger.subLogger("HeartbeatScheduler")))
|
||||||
set(HttpClientProvider, HttpClientProviderImpl())
|
set(HttpClientProvider, HttpClientProviderImpl())
|
||||||
@ -251,6 +260,9 @@ internal open class QQAndroidBot constructor(
|
|||||||
configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager")),
|
configuration.createAccountsSecretsManager(bot.logger.subLogger("AccountSecretsManager")),
|
||||||
)
|
)
|
||||||
set(ImagePatcher, ImagePatcherImpl())
|
set(ImagePatcher, ImagePatcherImpl())
|
||||||
|
|
||||||
|
cacheValidator.register(get(AccountSecretsManager))
|
||||||
|
cacheValidator.register(get(BdhSessionSyncer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,10 +35,10 @@ import kotlin.jvm.Volatile
|
|||||||
* @see FileCacheAccountSecretsManager
|
* @see FileCacheAccountSecretsManager
|
||||||
* @see CombinedAccountSecretsManager
|
* @see CombinedAccountSecretsManager
|
||||||
*/
|
*/
|
||||||
internal interface AccountSecretsManager {
|
internal interface AccountSecretsManager : Cacheable {
|
||||||
fun saveSecrets(account: BotAccount, secrets: AccountSecrets)
|
fun saveSecrets(account: BotAccount, secrets: AccountSecrets)
|
||||||
fun getSecrets(account: BotAccount): AccountSecrets?
|
fun getSecrets(account: BotAccount): AccountSecrets?
|
||||||
fun invalidate()
|
override fun invalidate()
|
||||||
|
|
||||||
companion object : ComponentKey<AccountSecretsManager>
|
companion object : ComponentKey<AccountSecretsManager>
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import net.mamoe.mirai.internal.utils.actualCacheDir
|
|||||||
import net.mamoe.mirai.utils.*
|
import net.mamoe.mirai.utils.*
|
||||||
import kotlin.jvm.Volatile
|
import kotlin.jvm.Volatile
|
||||||
|
|
||||||
internal interface BdhSessionSyncer {
|
internal interface BdhSessionSyncer : Cacheable {
|
||||||
val bdhSession: CompletableDeferred<BdhSession>
|
val bdhSession: CompletableDeferred<BdhSession>
|
||||||
val hasSession: Boolean
|
val hasSession: Boolean
|
||||||
|
|
||||||
@ -77,6 +77,11 @@ internal class BdhSessionSyncerImpl(
|
|||||||
private val serverListCacheFile: MiraiFile
|
private val serverListCacheFile: MiraiFile
|
||||||
get() = configuration.actualCacheDir().resolve("servers.json")
|
get() = configuration.actualCacheDir().resolve("servers.json")
|
||||||
|
|
||||||
|
override fun invalidate() {
|
||||||
|
sessionCacheFile.delete()
|
||||||
|
serverListCacheFile.delete()
|
||||||
|
}
|
||||||
|
|
||||||
override fun loadServerListFromCache() {
|
override fun loadServerListFromCache() {
|
||||||
val serverListCacheFile = this.serverListCacheFile
|
val serverListCacheFile = this.serverListCacheFile
|
||||||
if (serverListCacheFile.isFile) {
|
if (serverListCacheFile.isFile) {
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.components
|
||||||
|
|
||||||
|
import io.ktor.utils.io.core.*
|
||||||
|
import net.mamoe.mirai.internal.network.ProtoBufForCache
|
||||||
|
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||||
|
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal
|
||||||
|
import net.mamoe.mirai.internal.utils.io.writeShortLVString
|
||||||
|
import net.mamoe.mirai.utils.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator for checking caches is usable for current bot or not.
|
||||||
|
*/
|
||||||
|
internal interface CacheValidator {
|
||||||
|
fun register(cache: Cacheable)
|
||||||
|
|
||||||
|
fun validate()
|
||||||
|
|
||||||
|
companion object : ComponentKey<CacheValidator>
|
||||||
|
}
|
||||||
|
|
||||||
|
internal interface Cacheable {
|
||||||
|
fun invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CacheValidatorImpl(
|
||||||
|
private val ssoProcessorContext: SsoProcessorContext,
|
||||||
|
private val hashFile: MiraiFile,
|
||||||
|
private val logger: MiraiLogger,
|
||||||
|
) : CacheValidator {
|
||||||
|
private val caches: MutableList<Cacheable> = mutableListOf()
|
||||||
|
|
||||||
|
override fun register(cache: Cacheable) {
|
||||||
|
caches.add(cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun validate() {
|
||||||
|
|
||||||
|
val hash: ByteArray = buildPacket {
|
||||||
|
val botConf = ssoProcessorContext.configuration
|
||||||
|
writeInt(botConf.protocol.ordinal)
|
||||||
|
val internalProtocol = MiraiProtocolInternal[botConf.protocol]
|
||||||
|
writeShortLVString(internalProtocol.apkId)
|
||||||
|
writeLong(internalProtocol.id)
|
||||||
|
writeShortLVString(internalProtocol.sdkVer)
|
||||||
|
writeInt(internalProtocol.miscBitMap)
|
||||||
|
writeInt(internalProtocol.subSigMap)
|
||||||
|
writeInt(internalProtocol.mainSigMap)
|
||||||
|
writeShortLVString(internalProtocol.sign)
|
||||||
|
writeLong(internalProtocol.buildTime)
|
||||||
|
writeInt(internalProtocol.ssoVersion)
|
||||||
|
|
||||||
|
val device = ssoProcessorContext.device
|
||||||
|
|
||||||
|
@Suppress("INVISIBLE_MEMBER")
|
||||||
|
writeFully(ProtoBufForCache.encodeToByteArray(DeviceInfo.serializer(), device))
|
||||||
|
}.let { pkg ->
|
||||||
|
try {
|
||||||
|
pkg.readBytes()
|
||||||
|
} finally {
|
||||||
|
pkg.release()
|
||||||
|
}
|
||||||
|
}.sha1()
|
||||||
|
|
||||||
|
if (!hashFile.exists()) {
|
||||||
|
logger.verbose { "Invalidate caches because hash file not available." }
|
||||||
|
|
||||||
|
invalidate()
|
||||||
|
|
||||||
|
kotlin.runCatching {
|
||||||
|
hashFile.writeBytes(hash)
|
||||||
|
}.onFailure { logger.warning("Exception in writing hash to validation file", it) }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!hashFile.isFile) {
|
||||||
|
logger.verbose { "hash file isn't a file." }
|
||||||
|
invalidate()
|
||||||
|
|
||||||
|
kotlin.runCatching {
|
||||||
|
hashFile.deleteRecursively()
|
||||||
|
hashFile.writeBytes(hash)
|
||||||
|
}.onFailure { logger.warning("Exception in writing hash to validation file", it) }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val hashInFile = hashFile.readBytes()
|
||||||
|
if (hashInFile.contentEquals(hash)) {
|
||||||
|
logger.verbose { "Validated caches." }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.verbose { "Hash not match. Invaliding caches....." }
|
||||||
|
invalidate()
|
||||||
|
|
||||||
|
hashFile.writeBytes(hash)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
logger.warning("Exception in validation. Invalidating.....", e)
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidate() {
|
||||||
|
caches.forEach { it.invalidate() }
|
||||||
|
}
|
||||||
|
}
|
@ -146,6 +146,8 @@ internal class SsoProcessorImpl(
|
|||||||
* Do login. Throws [LoginFailedException] if failed
|
* Do login. Throws [LoginFailedException] if failed
|
||||||
*/
|
*/
|
||||||
override suspend fun login(handler: NetworkHandler) = withExceptionCollector {
|
override suspend fun login(handler: NetworkHandler) = withExceptionCollector {
|
||||||
|
components[CacheValidator].validate()
|
||||||
|
|
||||||
components[BdhSessionSyncer].loadServerListFromCache()
|
components[BdhSessionSyncer].loadServerListFromCache()
|
||||||
try {
|
try {
|
||||||
if (client.wLoginSigInfoInitialized) {
|
if (client.wLoginSigInfoInitialized) {
|
||||||
|
Loading…
Reference in New Issue
Block a user