From 311df7d22b69c2c9fc878179c4a02ce545d07816 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 6 Feb 2021 19:53:51 +0800 Subject: [PATCH 01/11] Extract contact sync logic to ContactUpdater for future caching #408 --- .../src/commonMain/kotlin/event/events/bot.kt | 14 +- .../src/commonMain/kotlin/QQAndroidBot.kt | 2 +- .../commonMain/kotlin/contact/GroupImpl.kt | 2 +- .../kotlin/network/BotNetworkHandler.kt | 3 +- .../kotlin/network/ContactUpdater.kt | 178 ++++++++++++++++ .../QQAndroidBotNetworkHandler.kt | 194 +++--------------- .../protocol/data/jce/SvcReqRegister.kt | 4 +- .../protocol/packet/OutgoingPacketAndroid.kt | 2 +- 8 files changed, 225 insertions(+), 174 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt rename mirai-core/src/commonMain/kotlin/network/{ => handler}/QQAndroidBotNetworkHandler.kt (82%) diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt b/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt index e8360d59c..0b4f2b08e 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/bot.kt @@ -25,7 +25,7 @@ import net.mamoe.mirai.utils.MiraiInternalApi /** * [Bot] 登录完成, 好友列表, 群组列表初始化完成 */ -public data class BotOnlineEvent internal constructor( +public data class BotOnlineEvent @MiraiInternalApi public constructor( public override val bot: Bot ) : BotActiveEvent, AbstractEvent() @@ -55,7 +55,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { /** * 被挤下线. 默认不会自动重连. 可将 [reconnect] 改为 `true` 以重连. */ - public data class Force internal constructor( + public data class Force @MiraiInternalApi public constructor( public override val bot: Bot, public val title: String, public val message: String, @@ -67,7 +67,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { * 被服务器断开 */ @MiraiInternalApi("This is very experimental and might be changed") - public data class MsfOffline internal constructor( + public data class MsfOffline @MiraiInternalApi public constructor( public override val bot: Bot, public override val cause: Throwable? ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { @@ -77,7 +77,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { /** * 因网络问题而掉线 */ - public data class Dropped internal constructor( + public data class Dropped @MiraiInternalApi public constructor( public override val bot: Bot, public override val cause: Throwable? ) : BotOfflineEvent(), Packet, BotPassiveEvent, CauseAware { @@ -88,7 +88,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { * 因 returnCode = -10008 等原因掉线 */ @MiraiInternalApi("This is very experimental and might be changed") - public data class PacketFactoryErrorCode internal constructor( + public data class PacketFactoryErrorCode @MiraiInternalApi public constructor( val returnCode: Int, public override val bot: Bot, public override val cause: Throwable @@ -100,7 +100,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { * 服务器主动要求更换另一个服务器 */ @MiraiInternalApi - public data class RequireReconnect internal constructor( + public data class RequireReconnect @MiraiInternalApi public constructor( public override val bot: Bot ) : BotOfflineEvent(), Packet, BotPassiveEvent { override var reconnect: Boolean = true @@ -115,7 +115,7 @@ public sealed class BotOfflineEvent : BotEvent, AbstractEvent() { /** * [Bot] 主动或被动重新登录. 在此事件广播前就已经登录完毕. */ -public data class BotReloginEvent internal constructor( +public data class BotReloginEvent @MiraiInternalApi public constructor( public override val bot: Bot, public val cause: Throwable? ) : BotEvent, BotActiveEvent, AbstractEvent() diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index d16f89425..27334c1b4 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -24,8 +24,8 @@ import net.mamoe.mirai.internal.contact.checkIsGroupImpl import net.mamoe.mirai.internal.contact.uin import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.network.Packet -import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType import net.mamoe.mirai.internal.network.protocol.packet.chat.* diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt index 8da6c298e..a9af1ca50 100644 --- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt @@ -22,7 +22,7 @@ import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.network.BdhSession -import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler +import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.highway.* import net.mamoe.mirai.internal.network.highway.ResourceKind.GROUP_IMAGE import net.mamoe.mirai.internal.network.highway.ResourceKind.GROUP_VOICE diff --git a/mirai-core/src/commonMain/kotlin/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/BotNetworkHandler.kt index bccd1b868..d33fd66d1 100644 --- a/mirai-core/src/commonMain/kotlin/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/BotNetworkHandler.kt @@ -18,6 +18,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import net.mamoe.mirai.Bot +import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.utils.MiraiInternalApi import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.WeakRefProperty @@ -46,7 +47,7 @@ internal abstract class BotNetworkHandler : CoroutineScope { * 所属 [Bot]. 为弱引用 */ @WeakRefProperty - abstract val bot: Bot + abstract val bot: QQAndroidBot /** * 监管 child [Job]s diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt new file mode 100644 index 000000000..f5029e955 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt @@ -0,0 +1,178 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.network + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.cancel +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit +import net.mamoe.mirai.Mirai +import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum +import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl +import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement +import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList +import net.mamoe.mirai.internal.network.protocol.packet.list.StrangerList +import net.mamoe.mirai.utils.info +import net.mamoe.mirai.utils.retryCatching +import net.mamoe.mirai.utils.verbose + +internal interface ContactUpdater { + suspend fun loadAll() + + fun closeAllContacts(e: CancellationException) +} + +internal class ContactUpdaterImpl( + val bot: QQAndroidBot, +) : ContactUpdater { + @Synchronized + override suspend fun loadAll() { + coroutineScope { + launch { reloadFriendList() } + launch { reloadGroupList() } + launch { reloadStrangerList() } + } + } + + @Synchronized + override fun closeAllContacts(e: CancellationException) { + if (!initFriendOk) { + bot.friends.delegate.removeAll { it.cancel(e); true } + } + if (!initGroupOk) { + bot.groups.delegate.removeAll { it.cancel(e); true } + } + if (!initStrangerOk) { + bot.strangers.delegate.removeAll { it.cancel(e); true } + } + } + + + @Volatile + private var initFriendOk = false + + @Volatile + private var initGroupOk = false + + @Volatile + private var initStrangerOk = false + + /** + * Don't use concurrently + */ + private suspend fun reloadFriendList() = bot.network.run { + if (initFriendOk) { + return + } + + logger.info { "Start loading friend list..." } + var currentFriendCount = 0 + var totalFriendCount: Short + while (true) { + val data = FriendList.GetFriendGroupList( + bot.client, currentFriendCount, 150, 0, 0 + ).sendAndExpect(timeoutMillis = 5000, retry = 2) + + // self info + data.selfInfo?.run { + bot.selfInfo = this +// bot.remark = remark ?: "" +// bot.sex = sex + } + + totalFriendCount = data.totalFriendCount + data.friendList.forEach { + // atomic + bot.friends.delegate.add( + FriendImpl(bot, bot.coroutineContext, it.toMiraiFriendInfo()) + ).also { currentFriendCount++ } + } + logger.verbose { "Loading friend list: ${currentFriendCount}/${totalFriendCount}" } + if (currentFriendCount >= totalFriendCount) { + break + } + // delay(200) + } + logger.info { "Successfully loaded friend list: $currentFriendCount in total" } + initFriendOk = true + } + + private suspend fun StTroopNum.reloadGroup() { + bot.groups.delegate.add( + GroupImpl( + bot = bot, + coroutineContext = bot.coroutineContext, + id = groupCode, + groupInfo = GroupInfoImpl(this), + members = Mirai.getRawGroupMemberList( + bot, + groupUin, + groupCode, + dwGroupOwnerUin + ) + ) + ) + } + + private suspend fun reloadStrangerList() = bot.network.run { + if (initStrangerOk) { + return + } + var currentCount = 0 + logger.info { "Start loading stranger list..." } + val response = StrangerList.GetStrangerList(bot.client) + .sendAndExpect(timeoutMillis = 5000, retry = 2) + + if (response.result == 0) { + response.strangerList.forEach { + // atomic + bot.strangers.delegate.add( + StrangerImpl(bot, bot.coroutineContext, StrangerInfoImpl(it.uin, it.nick.decodeToString())) + ).also { currentCount++ } + } + } + logger.info { "Successfully loaded stranger list: $currentCount in total" } + initStrangerOk = true + + } + + private suspend fun reloadGroupList() = bot.network.run { + if (initGroupOk) { + return + } + logger.info { "Start syncing group config..." } + TroopManagement.GetTroopConfig(bot.client).sendAndExpect() + logger.info { "Successfully synced group config." } + + logger.info { "Start loading group list..." } + val troopListData = FriendList.GetTroopListSimplify(bot.client) + .sendAndExpect(retry = 5) + + val semaphore = Semaphore(30) + + coroutineScope { + troopListData.groups.forEach { group -> + launch { + semaphore.withPermit { + retryCatching(5) { group.reloadGroup() }.getOrThrow() + } + } + } + } + logger.info { "Successfully loaded group list: ${troopListData.groups.size} in total." } + initGroupOk = true + } + + +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt similarity index 82% rename from mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt rename to mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt index 60b66944f..aed759b6d 100644 --- a/mirai-core/src/commonMain/kotlin/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt @@ -7,17 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") -package net.mamoe.mirai.internal.network +package net.mamoe.mirai.internal.network.handler import kotlinx.atomicfu.AtomicRef import kotlinx.atomicfu.atomic import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withLock -import kotlinx.coroutines.sync.withPermit import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.readBytes @@ -29,15 +26,11 @@ import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.* import net.mamoe.mirai.internal.createOtherClient -import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc import net.mamoe.mirai.internal.network.protocol.packet.* import net.mamoe.mirai.internal.network.protocol.packet.KnownPacketFactories.PacketFactoryIllegalStateException -import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl -import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetMsg -import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList -import net.mamoe.mirai.internal.network.protocol.packet.list.StrangerList import net.mamoe.mirai.internal.network.protocol.packet.login.ConfigPushSvc import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc @@ -333,170 +326,22 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo internal var pendingIncomingPackets: ConcurrentLinkedQueue>? = ConcurrentLinkedQueue() - private var initFriendOk = false - private var initGroupOk = false - private var initStrangerOk = false - - /** - * Don't use concurrently - */ - suspend fun reloadFriendList() { - if (initFriendOk) { - return - } - - logger.info { "Start loading friend list..." } - var currentFriendCount = 0 - var totalFriendCount: Short - while (true) { - val data = FriendList.GetFriendGroupList( - bot.client, currentFriendCount, 150, 0, 0 - ).sendAndExpect(timeoutMillis = 5000, retry = 2) - - // self info - data.selfInfo?.run { - bot.selfInfo = this -// bot.remark = remark ?: "" -// bot.sex = sex - } - - totalFriendCount = data.totalFriendCount - data.friendList.forEach { - // atomic - bot.friends.delegate.add( - FriendImpl(bot, bot.coroutineContext, it.toMiraiFriendInfo()) - ).also { currentFriendCount++ } - } - logger.verbose { "Loading friend list: ${currentFriendCount}/${totalFriendCount}" } - if (currentFriendCount >= totalFriendCount) { - break - } - // delay(200) - } - logger.info { "Successfully loaded friend list: $currentFriendCount in total" } - initFriendOk = true - } - - suspend fun StTroopNum.reloadGroup() { - bot.groups.delegate.add( - GroupImpl( - bot = bot, - coroutineContext = bot.coroutineContext, - id = groupCode, - groupInfo = GroupInfoImpl(this), - members = Mirai.getRawGroupMemberList( - bot, - groupUin, - groupCode, - dwGroupOwnerUin - ) - ) - ) - } - - suspend fun reloadStrangerList() { - if (initStrangerOk) { - return - } - var currentCount = 0 - logger.info { "Start loading stranger list..." } - val response = StrangerList.GetStrangerList(bot.client) - .sendAndExpect(timeoutMillis = 5000, retry = 2) - - if (response.result == 0) { - response.strangerList.forEach { - // atomic - bot.strangers.delegate.add( - StrangerImpl(bot, bot.coroutineContext, StrangerInfoImpl(it.uin, it.nick.decodeToString())) - ).also { currentCount++ } - } - } - logger.info { "Successfully loaded stranger list: $currentCount in total" } - initStrangerOk = true - - } - - suspend fun reloadGroupList() { - if (initGroupOk) { - return - } - logger.info { "Start syncing group config..." } - TroopManagement.GetTroopConfig(bot.client).sendAndExpect() - logger.info { "Successfully synced group config." } - - logger.info { "Start loading group list..." } - val troopListData = FriendList.GetTroopListSimplify(bot.client) - .sendAndExpect(retry = 5) - - val semaphore = Semaphore(30) - - coroutineScope { - troopListData.groups.forEach { group -> - launch { - semaphore.withPermit { - retryCatching(5) { group.reloadGroup() }.getOrThrow() - } - } - } - } - logger.info { "Successfully loaded group list: ${troopListData.groups.size} in total." } - initGroupOk = true - } - + private val contactUpdater: ContactUpdater by lazy { ContactUpdaterImpl(bot) } override suspend fun init(): Unit = coroutineScope { check(bot.isActive) { "bot is dead therefore network can't init." } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init." } - CancellationException("re-init").let { reInitCancellationException -> - if (!initFriendOk) { - bot.friends.delegate.removeAll { it.cancel(reInitCancellationException); true } - } - if (!initGroupOk) { - bot.groups.delegate.removeAll { it.cancel(reInitCancellationException); true } - } - if (!initStrangerOk) { - bot.strangers.delegate.removeAll { it.cancel(reInitCancellationException); true } - } - } + contactUpdater.closeAllContacts(CancellationException("re-init")) if (!pendingEnabled) { pendingIncomingPackets = ConcurrentLinkedQueue() _pendingEnabled.value = true } - coroutineScope { - launch { reloadFriendList() } - launch { reloadGroupList() } - launch { reloadStrangerList() } - } + contactUpdater.loadAll() - this@QQAndroidBotNetworkHandler.launch(CoroutineName("Awaiting ConfigPushSvc.PushReq")) { - logger.info { "Awaiting ConfigPushSvc.PushReq." } - when (val resp: ConfigPushSvc.PushReq.PushReqResponse? = nextEventOrNull(20_000)) { - null -> { - kotlin.runCatching { bot.client.bdhSession.completeExceptionally(TimeoutCancellationException("Timeout waiting for ConfigPushSvc.PushReq")) } - logger.warning { "Missing ConfigPushSvc.PushReq. File uploading may be affected." } - } - is ConfigPushSvc.PushReq.PushReqResponse.Success -> { - logger.info { "ConfigPushSvc.PushReq: Success." } - } - is ConfigPushSvc.PushReq.PushReqResponse.ChangeServer -> { - bot.logger.info { "Server requires reconnect." } - bot.logger.info { "Server list: ${resp.serverList.joinToString()}." } - - if (resp.serverList.isNotEmpty()) { - bot.serverList.clear() - resp.serverList.shuffled().forEach { - bot.serverList.add(it.host to it.port) - } - } - - bot.launch { BotOfflineEvent.RequireReconnect(bot).broadcast() } - return@launch - } - } - } + this@QQAndroidBotNetworkHandler.launch(CoroutineName("Awaiting ConfigPushSvc.PushReq"), block= ConfigPushSyncer()) syncMessageSvc() @@ -504,6 +349,33 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo postInitActions() } + private fun BotNetworkHandler.ConfigPushSyncer(): suspend CoroutineScope.() -> Unit = launch@{ + logger.info { "Awaiting ConfigPushSvc.PushReq." } + when (val resp: ConfigPushSvc.PushReq.PushReqResponse? = nextEventOrNull(20_000)) { + null -> { + kotlin.runCatching { bot.client.bdhSession.completeExceptionally(CancellationException("Timeout waiting for ConfigPushSvc.PushReq")) } + logger.warning { "Missing ConfigPushSvc.PushReq. File uploading may be affected." } + } + is ConfigPushSvc.PushReq.PushReqResponse.Success -> { + logger.info { "ConfigPushSvc.PushReq: Success." } + } + is ConfigPushSvc.PushReq.PushReqResponse.ChangeServer -> { + bot.logger.info { "Server requires reconnect." } + bot.logger.info { "Server list: ${resp.serverList.joinToString()}." } + + if (resp.serverList.isNotEmpty()) { + bot.serverList.clear() + resp.serverList.shuffled().forEach { + bot.serverList.add(it.host to it.port) + } + } + + bot.launch { BotOfflineEvent.RequireReconnect(bot).broadcast() } + return@launch + } + } + } + override suspend fun postInitActions() { _pendingEnabled.value = false pendingIncomingPackets?.forEach { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt index d86b55e1e..dd1c5aae6 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt @@ -37,8 +37,8 @@ internal class SvcReqRegister( @TarsId(19) @JvmField val strDevName: String? = null, @TarsId(20) @JvmField val strDevType: String? = null, @TarsId(21) @JvmField val strOSVer: String? = null, - @TarsId(22) @JvmField val bOpenPush: Byte = 1, - @TarsId(23) @JvmField val iLargeSeq: Long = 0L, + @TarsId(22) @JvmField val bOpenPush: Byte, + @TarsId(23) @JvmField val iLargeSeq: Long, @TarsId(24) @JvmField val iLastWatchStartTime: Long = 0L, @TarsId(26) @JvmField val uOldSSOIp: Long = 0L, @TarsId(27) @JvmField val uNewSSOIp: Long = 0L, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt index 72d6058b8..06a0215d5 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/OutgoingPacketAndroid.kt @@ -16,7 +16,7 @@ import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.network.Packet -import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler +import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.utils.io.encryptAndWrite import net.mamoe.mirai.internal.utils.io.writeHex From 9211f697cff685197a0bc67d8e239e57f4e27fed Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 6 Feb 2021 20:22:14 +0800 Subject: [PATCH 02/11] Review contact infos and make them serializable --- .../api/binary-compatibility-validator.api | 8 ++++ .../kotlin/contact/MemberPermission.kt | 1 + .../src/commonMain/kotlin/data/FriendInfo.kt | 9 +++- mirai-core/src/commonMain/kotlin/MiraiImpl.kt | 3 ++ .../src/commonMain/kotlin/QQAndroidBot.kt | 3 +- .../kotlin/contact/AbstractMember.kt | 1 + .../commonMain/kotlin/contact/AbstractUser.kt | 3 -- .../commonMain/kotlin/contact/FriendImpl.kt | 11 +---- .../commonMain/kotlin/contact/GroupImpl.kt | 1 + .../kotlin/contact/SendMessageHandler.kt | 1 + .../commonMain/kotlin/contact/StrangerImpl.kt | 20 ++------- .../kotlin/contact/info/FriendInfoImpl.kt | 21 +++++++++ .../kotlin/contact/info/GroupInfoImpl.kt | 44 +++++++++++++++++++ .../contact/{ => info}/MemberInfoImpl.kt | 8 ++-- .../kotlin/contact/info/StrangerInfoImpl.kt | 23 ++++++++++ .../kotlin/network/ContactUpdater.kt | 12 ++++- .../protocol/packet/chat/TroopManagement.kt | 21 +-------- .../chat/receive/MessageSvc.PbGetMsg.kt | 5 ++- .../chat/receive/OnlinePush.PbPushGroupMsg.kt | 1 + .../chat/receive/OnlinePush.PbPushTransMsg.kt | 1 + .../packet/chat/receive/OnlinePush.ReqPush.kt | 5 ++- 21 files changed, 143 insertions(+), 59 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/contact/info/FriendInfoImpl.kt create mode 100644 mirai-core/src/commonMain/kotlin/contact/info/GroupInfoImpl.kt rename mirai-core/src/commonMain/kotlin/contact/{ => info}/MemberInfoImpl.kt (92%) create mode 100644 mirai-core/src/commonMain/kotlin/contact/info/StrangerInfoImpl.kt diff --git a/binary-compatibility-validator/api/binary-compatibility-validator.api b/binary-compatibility-validator/api/binary-compatibility-validator.api index 2ff6ddf64..df9ae4ce0 100644 --- a/binary-compatibility-validator/api/binary-compatibility-validator.api +++ b/binary-compatibility-validator/api/binary-compatibility-validator.api @@ -623,6 +623,7 @@ public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mira public abstract fun getNick ()Ljava/lang/String; public abstract fun getRemark ()Ljava/lang/String; public abstract fun getUin ()J + public abstract fun setRemark (Ljava/lang/String;)V } public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo { @@ -2077,6 +2078,7 @@ public abstract interface class net/mamoe/mirai/event/events/BotOfflineEvent$Cau } public final class net/mamoe/mirai/event/events/BotOfflineEvent$Dropped : net/mamoe/mirai/event/events/BotOfflineEvent, net/mamoe/mirai/event/events/BotOfflineEvent$CauseAware, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/internal/network/Packet { + public fun (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun component2 ()Ljava/lang/Throwable; public final fun copy (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)Lnet/mamoe/mirai/event/events/BotOfflineEvent$Dropped; @@ -2091,6 +2093,7 @@ public final class net/mamoe/mirai/event/events/BotOfflineEvent$Dropped : net/ma } public final class net/mamoe/mirai/event/events/BotOfflineEvent$Force : net/mamoe/mirai/event/events/BotOfflineEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/internal/network/Packet { + public fun (Lnet/mamoe/mirai/Bot;Ljava/lang/String;Ljava/lang/String;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; @@ -2107,6 +2110,7 @@ public final class net/mamoe/mirai/event/events/BotOfflineEvent$Force : net/mamo } public final class net/mamoe/mirai/event/events/BotOfflineEvent$MsfOffline : net/mamoe/mirai/event/events/BotOfflineEvent, net/mamoe/mirai/event/events/BotOfflineEvent$CauseAware, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/internal/network/Packet { + public fun (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun component2 ()Ljava/lang/Throwable; public final fun copy (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)Lnet/mamoe/mirai/event/events/BotOfflineEvent$MsfOffline; @@ -2121,6 +2125,7 @@ public final class net/mamoe/mirai/event/events/BotOfflineEvent$MsfOffline : net } public final class net/mamoe/mirai/event/events/BotOfflineEvent$PacketFactoryErrorCode : net/mamoe/mirai/event/events/BotOfflineEvent, net/mamoe/mirai/event/events/BotOfflineEvent$CauseAware, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/internal/network/Packet { + public fun (ILnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)V public final fun component1 ()I public final fun component2 ()Lnet/mamoe/mirai/Bot; public final fun component3 ()Ljava/lang/Throwable; @@ -2137,6 +2142,7 @@ public final class net/mamoe/mirai/event/events/BotOfflineEvent$PacketFactoryErr } public final class net/mamoe/mirai/event/events/BotOfflineEvent$RequireReconnect : net/mamoe/mirai/event/events/BotOfflineEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/internal/network/Packet { + public fun (Lnet/mamoe/mirai/Bot;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun copy (Lnet/mamoe/mirai/Bot;)Lnet/mamoe/mirai/event/events/BotOfflineEvent$RequireReconnect; public static synthetic fun copy$default (Lnet/mamoe/mirai/event/events/BotOfflineEvent$RequireReconnect;Lnet/mamoe/mirai/Bot;ILjava/lang/Object;)Lnet/mamoe/mirai/event/events/BotOfflineEvent$RequireReconnect; @@ -2149,6 +2155,7 @@ public final class net/mamoe/mirai/event/events/BotOfflineEvent$RequireReconnect } public final class net/mamoe/mirai/event/events/BotOnlineEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotActiveEvent { + public fun (Lnet/mamoe/mirai/Bot;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun copy (Lnet/mamoe/mirai/Bot;)Lnet/mamoe/mirai/event/events/BotOnlineEvent; public static synthetic fun copy$default (Lnet/mamoe/mirai/event/events/BotOnlineEvent;Lnet/mamoe/mirai/Bot;ILjava/lang/Object;)Lnet/mamoe/mirai/event/events/BotOnlineEvent; @@ -2162,6 +2169,7 @@ public abstract interface class net/mamoe/mirai/event/events/BotPassiveEvent : n } public final class net/mamoe/mirai/event/events/BotReloginEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotActiveEvent, net/mamoe/mirai/event/events/BotEvent { + public fun (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)V public final fun component1 ()Lnet/mamoe/mirai/Bot; public final fun component2 ()Ljava/lang/Throwable; public final fun copy (Lnet/mamoe/mirai/Bot;Ljava/lang/Throwable;)Lnet/mamoe/mirai/event/events/BotReloginEvent; diff --git a/mirai-core-api/src/commonMain/kotlin/contact/MemberPermission.kt b/mirai-core-api/src/commonMain/kotlin/contact/MemberPermission.kt index 7f5c3a58b..43c55be16 100644 --- a/mirai-core-api/src/commonMain/kotlin/contact/MemberPermission.kt +++ b/mirai-core-api/src/commonMain/kotlin/contact/MemberPermission.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.contact +import kotlinx.serialization.Serializable import net.mamoe.mirai.Bot import kotlin.internal.InlineOnly diff --git a/mirai-core-api/src/commonMain/kotlin/data/FriendInfo.kt b/mirai-core-api/src/commonMain/kotlin/data/FriendInfo.kt index a56fb0739..d3a40d835 100644 --- a/mirai-core-api/src/commonMain/kotlin/data/FriendInfo.kt +++ b/mirai-core-api/src/commonMain/kotlin/data/FriendInfo.kt @@ -17,9 +17,16 @@ public interface FriendInfo : UserInfo { public override val nick: String - public override val remark: String + public override var remark: String } + +@Deprecated( + "Moved to net.mamoe.mirai.internal.contact.FriendInfoImpl. Kept for binary compatibility.", + ReplaceWith("FriendInfoImpl", "net.mamoe.mirai.internal.contact.FriendInfoImpl"), + level = DeprecationLevel.HIDDEN +) +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @LowLevelApi public open class FriendInfoImpl( override val uin: Long, diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index fd716b7cc..71d91a3c0 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.internal +import contact.StrangerImpl import io.ktor.client.* import io.ktor.client.engine.okhttp.* import io.ktor.client.features.* @@ -25,6 +26,8 @@ import net.mamoe.mirai.data.* import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.network.highway.* import net.mamoe.mirai.internal.network.protocol.data.jce.SvcDevLoginInfo diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 27334c1b4..0ffc5a2bd 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -18,8 +18,9 @@ import net.mamoe.mirai.LowLevelApi import net.mamoe.mirai.Mirai import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.OtherClientImpl -import net.mamoe.mirai.internal.contact.StrangerInfoImpl +import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.contact.checkIsGroupImpl import net.mamoe.mirai.internal.contact.uin import net.mamoe.mirai.internal.message.* diff --git a/mirai-core/src/commonMain/kotlin/contact/AbstractMember.kt b/mirai-core/src/commonMain/kotlin/contact/AbstractMember.kt index 0e9075df6..8f111dabc 100644 --- a/mirai-core/src/commonMain/kotlin/contact/AbstractMember.kt +++ b/mirai-core/src/commonMain/kotlin/contact/AbstractMember.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.internal.contact import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MemberInfo +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.getValue import net.mamoe.mirai.utils.unsafeWeakRef diff --git a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt index 59d10ce9d..aea2d7c81 100644 --- a/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt +++ b/mirai-core/src/commonMain/kotlin/contact/AbstractUser.kt @@ -40,9 +40,6 @@ import kotlin.coroutines.CoroutineContext internal val User.info: UserInfo? get() = this.castOrNull()?.info -internal open class UserInfoImpl(override val uin: Long, override val nick: String, override val remark: String = "") : - UserInfo - internal abstract class AbstractUser( bot: Bot, coroutineContext: CoroutineContext, diff --git a/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt b/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt index 417f7401d..f4af6ecbb 100644 --- a/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt @@ -23,10 +23,10 @@ import kotlinx.atomicfu.atomic import net.mamoe.mirai.LowLevelApi import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.data.FriendInfo -import net.mamoe.mirai.data.FriendInfoImpl import net.mamoe.mirai.event.events.FriendMessagePostSendEvent import net.mamoe.mirai.event.events.FriendMessagePreSendEvent import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList import net.mamoe.mirai.internal.utils.C2CPkgMsgParsingCache import net.mamoe.mirai.message.MessageReceipt @@ -42,15 +42,6 @@ internal fun net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo.toMir remark ) -@OptIn(ExperimentalContracts::class) -internal inline fun FriendInfo.checkIsInfoImpl(): FriendInfoImpl { - contract { - returns() implies (this@checkIsInfoImpl is FriendInfoImpl) - } - check(this is FriendInfoImpl) { "A FriendInfo instance is not instance of checkIsInfoImpl. Your instance: ${this::class.qualifiedName}" } - return this -} - @OptIn(ExperimentalContracts::class) internal inline fun Friend.checkIsFriendImpl(): FriendImpl { contract { diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt index a9af1ca50..fe26b64de 100644 --- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt @@ -20,6 +20,7 @@ import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.message.* import net.mamoe.mirai.internal.network.BdhSession import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler diff --git a/mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt b/mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt index 6357c4ffa..9fb5a732f 100644 --- a/mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt +++ b/mirai-core/src/commonMain/kotlin/contact/SendMessageHandler.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.internal.contact +import contact.StrangerImpl import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.nextEventOrNull import net.mamoe.mirai.internal.MiraiImpl diff --git a/mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt b/mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt index 7be4301cb..771064c12 100644 --- a/mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/StrangerImpl.kt @@ -15,17 +15,19 @@ "INVISIBLE_REFERENCE" ) -package net.mamoe.mirai.internal.contact +package contact import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.atomic import net.mamoe.mirai.LowLevelApi import net.mamoe.mirai.contact.* -import net.mamoe.mirai.data.FriendInfoImpl import net.mamoe.mirai.data.StrangerInfo import net.mamoe.mirai.event.events.StrangerMessagePostSendEvent import net.mamoe.mirai.event.events.StrangerMessagePreSendEvent import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.AbstractUser +import net.mamoe.mirai.internal.contact.StrangerSendMessageHandler +import net.mamoe.mirai.internal.contact.sendMessageImpl import net.mamoe.mirai.internal.message.OnlineMessageSourceToStrangerImpl import net.mamoe.mirai.internal.network.protocol.packet.list.StrangerList import net.mamoe.mirai.message.MessageReceipt @@ -36,20 +38,6 @@ import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext -internal class StrangerInfoImpl( - override val uin: Long, override val nick: String, override val fromGroup: Long = 0, - override val remark: String = "" -) : StrangerInfo - -@OptIn(ExperimentalContracts::class) -internal inline fun StrangerInfo.checkIsInfoImpl(): FriendInfoImpl { - contract { - returns() implies (this@checkIsInfoImpl is StrangerInfoImpl) - } - check(this is FriendInfoImpl) { "A StrangerInfo instance is not instance of StrangerInfoImpl. Your instance: ${this::class.qualifiedName}" } - return this -} - @OptIn(ExperimentalContracts::class) internal inline fun Stranger.checkIsImpl(): StrangerImpl { contract { diff --git a/mirai-core/src/commonMain/kotlin/contact/info/FriendInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/info/FriendInfoImpl.kt new file mode 100644 index 000000000..c46c8b135 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/contact/info/FriendInfoImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.contact.info + +import kotlinx.serialization.Serializable +import net.mamoe.mirai.data.FriendInfo + +// since 2.4, for serialization +@Serializable +internal data class FriendInfoImpl( + override val uin: Long, + override var nick: String, + override var remark: String, +) : FriendInfo \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/contact/info/GroupInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/info/GroupInfoImpl.kt new file mode 100644 index 000000000..921f41615 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/contact/info/GroupInfoImpl.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2021 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.contact.info + +import kotlinx.serialization.Serializable +import net.mamoe.mirai.data.GroupInfo +import net.mamoe.mirai.internal.network.Packet +import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum + +@Serializable +internal data class GroupInfoImpl( + override val uin: Long, + override val owner: Long, + override val groupCode: Long, + override val memo: String, + override val name: String, + override val allowMemberInvite: Boolean, + override val allowAnonymousChat: Boolean, + override val autoApprove: Boolean, + override val confessTalk: Boolean, + override val muteAll: Boolean, + override val botMuteTimestamp: Int, +) : GroupInfo, Packet, Packet.NoLog { + constructor(stTroopNum: StTroopNum) : this( + uin = stTroopNum.groupUin, + owner = stTroopNum.dwGroupOwnerUin, + groupCode = stTroopNum.groupCode, + memo = stTroopNum.groupMemo, + name = stTroopNum.groupName, + allowMemberInvite = stTroopNum.dwGroupFlagExt?.and(0x000000c0) != 0L, + allowAnonymousChat = stTroopNum.dwGroupFlagExt?.and(0x40000000) == 0L, + autoApprove = stTroopNum.dwGroupFlagExt3?.and(0x00100000) == 0L, + confessTalk = stTroopNum.dwGroupFlagExt3?.and(0x00002000) == 0L, + muteAll = stTroopNum.dwShutUpTimestamp != 0L, + botMuteTimestamp = stTroopNum.dwMyShutUpTimestamp?.toInt() ?: 0, + ) +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt similarity index 92% rename from mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt rename to mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt index 873720bb2..3c653670f 100644 --- a/mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt +++ b/mirai-core/src/commonMain/kotlin/contact/info/MemberInfoImpl.kt @@ -7,15 +7,17 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.internal.contact +package net.mamoe.mirai.internal.contact.info +import kotlinx.serialization.Serializable import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopMemberInfo import net.mamoe.mirai.utils.currentTimeSeconds -internal class MemberInfoImpl( +@Serializable +internal data class MemberInfoImpl( override val uin: Long, override var nick: String, override var permission: MemberPermission, @@ -27,7 +29,7 @@ internal class MemberInfoImpl( override val joinTimestamp: Int = currentTimeSeconds().toInt(), override var lastSpeakTimestamp: Int = 0, override val isOfficialBot: Boolean = false -) : MemberInfo, UserInfoImpl(uin, nick, remark) { +) : MemberInfo { constructor( client: QQAndroidClient, jceInfo: StTroopMemberInfo, diff --git a/mirai-core/src/commonMain/kotlin/contact/info/StrangerInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/info/StrangerInfoImpl.kt new file mode 100644 index 000000000..5a3aef420 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/contact/info/StrangerInfoImpl.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2019-2021 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.contact.info + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.mamoe.mirai.data.StrangerInfo + +@SerialName("StrangerInfo") +@Serializable +internal class StrangerInfoImpl( + override val uin: Long, + override val nick: String, + override val fromGroup: Long = 0, + override val remark: String = "" +) : StrangerInfo \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt index f5029e955..6eff0bc74 100644 --- a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt +++ b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.internal.network +import contact.StrangerImpl import kotlinx.coroutines.CancellationException import kotlinx.coroutines.cancel import kotlinx.coroutines.coroutineScope @@ -17,9 +18,12 @@ import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import net.mamoe.mirai.Mirai import net.mamoe.mirai.internal.QQAndroidBot -import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.FriendImpl +import net.mamoe.mirai.internal.contact.GroupImpl +import net.mamoe.mirai.internal.contact.info.GroupInfoImpl +import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl +import net.mamoe.mirai.internal.contact.toMiraiFriendInfo import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum -import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList import net.mamoe.mirai.internal.network.protocol.packet.list.StrangerList @@ -27,6 +31,10 @@ import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.retryCatching import net.mamoe.mirai.utils.verbose +internal interface ContactCache { + +} + internal interface ContactUpdater { suspend fun loadAll() diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt index cfd8a9847..74f273804 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/TroopManagement.kt @@ -13,14 +13,13 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.readBytes import kotlinx.io.core.toByteArray -import net.mamoe.mirai.LowLevelApi import net.mamoe.mirai.contact.Member import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.info.GroupInfoImpl import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.protocol.data.jce.ModifyGroupCardReq import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPacket -import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum import net.mamoe.mirai.internal.network.protocol.data.jce.stUinInfo import net.mamoe.mirai.internal.network.protocol.data.proto.* import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket @@ -28,24 +27,6 @@ import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket import net.mamoe.mirai.internal.utils.io.serialization.* import net.mamoe.mirai.utils.daysToSeconds -import net.mamoe.mirai.data.GroupInfo as MiraiGroupInfo - -@OptIn(LowLevelApi::class) -internal class GroupInfoImpl( - private val stTroopNum: StTroopNum -) : MiraiGroupInfo, Packet, Packet.NoLog { - override val uin: Long get() = stTroopNum.groupUin - override val owner: Long get() = stTroopNum.dwGroupOwnerUin - override val groupCode: Long get() = stTroopNum.groupCode - override val memo: String get() = stTroopNum.groupMemo - override val name: String get() = stTroopNum.groupName - override val allowMemberInvite get() = stTroopNum.dwGroupFlagExt?.and(0x000000c0) != 0L - override val allowAnonymousChat get() = stTroopNum.dwGroupFlagExt?.and(0x40000000) == 0L - override val autoApprove get() = stTroopNum.dwGroupFlagExt3?.and(0x00100000) == 0L - override val confessTalk get() = stTroopNum.dwGroupFlagExt3?.and(0x00002000) == 0L - override val muteAll: Boolean get() = stTroopNum.dwShutUpTimestamp != 0L - override val botMuteTimestamp: Int get() = stTroopNum.dwMyShutUpTimestamp?.toInt() ?: 0 -} internal class TroopManagement { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt index 9c2440a7f..19e85038c 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt @@ -11,6 +11,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.chat.receive +import contact.checkIsImpl import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay @@ -29,6 +30,8 @@ import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl +import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.message.OnlineMessageSourceFromFriendImpl import net.mamoe.mirai.internal.message.refine import net.mamoe.mirai.internal.message.toMessageChainOnline @@ -42,7 +45,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket -import net.mamoe.mirai.internal.network.protocol.packet.chat.GroupInfoImpl +import net.mamoe.mirai.internal.contact.info.GroupInfoImpl import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList import net.mamoe.mirai.internal.utils.* diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt index 56809219d..4b351520b 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt @@ -23,6 +23,7 @@ import net.mamoe.mirai.event.events.GroupMessageSyncEvent import net.mamoe.mirai.event.events.MemberCardChangeEvent import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.message.refine import net.mamoe.mirai.internal.message.toMessageChainOnline import net.mamoe.mirai.internal.network.Packet diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt index 817fae3d9..62cffe697 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt @@ -23,6 +23,7 @@ import net.mamoe.mirai.contact.NormalMember import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.message.contextualBugReportException import net.mamoe.mirai.internal.network.MultiPacketByIterable import net.mamoe.mirai.internal.network.Packet diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt index d0175e43b..31c378f35 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt @@ -21,12 +21,13 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import net.mamoe.mirai.Mirai import net.mamoe.mirai.contact.* -import net.mamoe.mirai.data.FriendInfoImpl import net.mamoe.mirai.data.GroupHonorType import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.* +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.network.MultiPacketBySequence import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient @@ -708,7 +709,7 @@ internal object Transformers528 : Map by mapOf( return this.msgFrdRmk.asSequence().mapNotNull { val friend = bot.getFriend(it.fuin) ?: return@mapNotNull null val old: String - friend.checkIsFriendImpl().friendInfo.checkIsInfoImpl() + friend.checkIsFriendImpl().friendInfo .also { info -> old = info.remark } .remark = it.rmkName // TODO: 2020/4/10 ADD REMARK QUERY From 6cb3aed2f0cce06fba39c2168f6e8a1a85f650d7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 6 Feb 2021 20:42:59 +0800 Subject: [PATCH 03/11] Remove unused QQAndroidBot.selfInfo --- mirai-core/src/commonMain/kotlin/QQAndroidBot.kt | 8 -------- .../src/commonMain/kotlin/network/ContactUpdater.kt | 8 -------- 2 files changed, 16 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 0ffc5a2bd..8dc5277fa 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -80,14 +80,6 @@ internal class QQAndroidBot constructor( override lateinit var nick: String - internal var selfInfo: JceFriendInfo? = null - get() = field ?: error("selfInfo is not yet initialized") - set(it) { - checkNotNull(it) - field = it - nick = it.nick - } - override val asFriend: Friend by lazy { @OptIn(LowLevelApi::class) Mirai.newFriend(this, FriendInfoImpl(uin, nick, "")) diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt index 6eff0bc74..43e5a0144 100644 --- a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt +++ b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt @@ -32,7 +32,6 @@ import net.mamoe.mirai.utils.retryCatching import net.mamoe.mirai.utils.verbose internal interface ContactCache { - } internal interface ContactUpdater { @@ -92,13 +91,6 @@ internal class ContactUpdaterImpl( bot.client, currentFriendCount, 150, 0, 0 ).sendAndExpect(timeoutMillis = 5000, retry = 2) - // self info - data.selfInfo?.run { - bot.selfInfo = this -// bot.remark = remark ?: "" -// bot.sex = sex - } - totalFriendCount = data.totalFriendCount data.friendList.forEach { // atomic From 90d4030fe6549914e4de7ed46e780f970beb6c3a Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 6 Feb 2021 22:52:41 +0800 Subject: [PATCH 04/11] Support friend list cache, close #408 --- .../commonMain/kotlin/event/events/friend.kt | 10 +- .../commonMain/kotlin/event/events/types.kt | 2 + .../kotlin/utils/BotConfiguration.kt | 37 +++++++ mirai-core-utils/src/commonMain/kotlin/IO.kt | 10 +- .../src/commonMain/kotlin/Serialization.kt | 24 +++++ .../src/commonMain/kotlin/QQAndroidBot.kt | 49 +++++++-- .../kotlin/network/ContactUpdater.kt | 99 ++++++++++++------- .../kotlin/network/FriendListCache.kt | 30 ++++++ .../handler/QQAndroidBotNetworkHandler.kt | 32 +++--- .../protocol/data/jce/SvcReqRegister.kt | 72 +++++++------- .../protocol/data/jce/SvcRespRegister.kt | 9 ++ .../network/protocol/packet/login/StatSvc.kt | 25 ++--- .../commonMain/kotlin/utils/ScheduledJob.kt | 71 +++++++++++++ .../src/commonTest/kotlin/ScheduledJobTest.kt | 38 +++++++ 14 files changed, 401 insertions(+), 107 deletions(-) create mode 100644 mirai-core-utils/src/commonMain/kotlin/Serialization.kt create mode 100644 mirai-core/src/commonMain/kotlin/network/FriendListCache.kt create mode 100644 mirai-core/src/commonMain/kotlin/utils/ScheduledJob.kt create mode 100644 mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt b/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt index bc309ce55..5a38dd007 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/friend.kt @@ -32,7 +32,7 @@ public data class FriendRemarkChangeEvent internal constructor( public override val friend: Friend, public val oldRemark: String, public val newRemark: String -) : FriendEvent, Packet, AbstractEvent() +) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent /** * 成功添加了一个新好友的事件 @@ -42,14 +42,14 @@ public data class FriendAddEvent @MiraiInternalApi constructor( * 新好友. 已经添加到 [Bot.friends] */ public override val friend: Friend -) : FriendEvent, Packet, AbstractEvent() +) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent /** * 好友已被删除或主动删除的事件. */ public data class FriendDeleteEvent internal constructor( public override val friend: Friend -) : FriendEvent, Packet, AbstractEvent() +) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent /** * 一个账号请求添加机器人为好友的事件 @@ -77,7 +77,7 @@ public data class NewFriendRequestEvent internal constructor( * 群名片或好友昵称 */ public val fromNick: String -) : BotEvent, Packet, AbstractEvent() { +) : BotEvent, Packet, AbstractEvent(), FriendInfoChangeEvent { @JvmField internal val responded: AtomicBoolean = AtomicBoolean(false) @@ -109,7 +109,7 @@ public data class FriendNickChangedEvent internal constructor( public override val friend: Friend, public val from: String, public val to: String -) : FriendEvent, Packet, AbstractEvent() +) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent /** * 好友输入状态改变的事件,当开始输入文字、退出聊天窗口或清空输入框时会触发此事件 diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/types.kt b/mirai-core-api/src/commonMain/kotlin/event/events/types.kt index 69b846251..9e90afb58 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/types.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/types.kt @@ -90,6 +90,8 @@ public interface FriendEvent : BotEvent, UserEvent { override val user: Friend get() = friend } +internal interface FriendInfoChangeEvent : BotEvent // for cache + /** * 有关陌生人的事件 */ diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index ac011c3b7..806fb727b 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -310,6 +310,43 @@ public open class BotConfiguration { // open for Java botLoggerSupplier = { _ -> SilentLogger } } + /////////////////////////////////////////////////////////////////////////// + // Cache + ////////////////////////////////////////////////////////////////////////// + + /** + * 非 `null` 时启用好友列表缓存, 加快初始化速度. 在启用后将会在下载好友列表后保存到文件, 并在修改时自动保存. + * @since 2.4 + * @see enableFriendListCache + */ + public var friendListCache: FriendListCache? = FriendListCache() + + /** + * 好友列表缓存设置. + * @since 2.4 + * @see friendListCache + */ + public class FriendListCache @JvmOverloads constructor( + /** + * 缓存文件位置, 相对于 [workingDir] 的路径. + */ + public val cacheFile: File = File("cache/friendList.json"), + /** + * 在有好友列表修改是 + */ + public val saveIntervalMillis: Long = 60_000, + ) + + /** + * 启用好友列表缓存. + * @since 2.4 + * @see BotConfiguration.enableFriendListCache + */ + public fun enableFriendListCache() { + friendListCache = FriendListCache() + } + + /** * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. * diff --git a/mirai-core-utils/src/commonMain/kotlin/IO.kt b/mirai-core-utils/src/commonMain/kotlin/IO.kt index 2969e81d0..0899301b2 100644 --- a/mirai-core-utils/src/commonMain/kotlin/IO.kt +++ b/mirai-core-utils/src/commonMain/kotlin/IO.kt @@ -16,6 +16,7 @@ package net.mamoe.mirai.utils import io.ktor.utils.io.charsets.* import kotlinx.io.core.* +import java.io.File import kotlin.text.Charsets @@ -123,4 +124,11 @@ public inline fun Input.readString(length: UShort, charset: Charset = Charsets.U String(this.readBytes(length.toInt()), charset = charset) public inline fun Input.readString(length: Byte, charset: Charset = Charsets.UTF_8): String = - String(this.readBytes(length.toInt()), charset = charset) \ No newline at end of file + String(this.readBytes(length.toInt()), charset = charset) + +public fun File.createFileIfNotExists() { + if (!this.exists()) { + this.parentFile.mkdirs() + this.createNewFile() + } +} \ No newline at end of file diff --git a/mirai-core-utils/src/commonMain/kotlin/Serialization.kt b/mirai-core-utils/src/commonMain/kotlin/Serialization.kt new file mode 100644 index 000000000..fc2c64f20 --- /dev/null +++ b/mirai-core-utils/src/commonMain/kotlin/Serialization.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +package net.mamoe.mirai.utils + +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.StringFormat +import java.io.File + +public fun File.loadAs( + serializer: DeserializationStrategy, + stringFormat: StringFormat, +): T? { + if (!this.exists() || this.length() == 0L) { + return null + } + return stringFormat.decodeFromString(serializer, this.readText()) +} diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 8dc5277fa..57d5eef1d 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -18,26 +18,25 @@ import net.mamoe.mirai.LowLevelApi import net.mamoe.mirai.Mirai import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* -import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.OtherClientImpl -import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.contact.checkIsGroupImpl +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl +import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.contact.uin import net.mamoe.mirai.internal.message.* -import net.mamoe.mirai.internal.network.Packet -import net.mamoe.mirai.internal.network.QQAndroidClient +import net.mamoe.mirai.internal.network.* import net.mamoe.mirai.internal.network.handler.QQAndroidBotNetworkHandler import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType import net.mamoe.mirai.internal.network.protocol.packet.chat.* import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc -import net.mamoe.mirai.internal.network.useNextServers +import net.mamoe.mirai.internal.utils.ScheduledJob import net.mamoe.mirai.message.data.* import net.mamoe.mirai.network.LoginFailedException import net.mamoe.mirai.utils.* import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext -import net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo as JceFriendInfo +import kotlin.time.milliseconds internal fun Bot.asQQAndroidBot(): QQAndroidBot { contract { @@ -59,7 +58,7 @@ internal class QQAndroidBot constructor( configuration: BotConfiguration ) : AbstractBot(configuration, account.id) { var client: QQAndroidClient = initClient() - private set + private set fun initClient(): QQAndroidClient { client = QQAndroidClient( @@ -78,6 +77,40 @@ internal class QQAndroidBot constructor( override val friends: ContactList = ContactList() + val friendListCache: FriendListCache? by lazy { + configuration.friendListCache?.cacheFile?.run { + val ret = loadAs(FriendListCache.serializer(), JsonForCache) ?: FriendListCache() + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + bot.eventChannel.parentScope(this@QQAndroidBot) + .subscribeAlways { + friendListSaver?.notice() + } + + ret + } + } + + private val friendListSaver by lazy { + configuration.friendListCache?.let { friendListCache: BotConfiguration.FriendListCache -> + + ScheduledJob(coroutineContext, friendListCache.saveIntervalMillis.milliseconds) { + runBIO { saveFriendCache() } + } + } + } + + fun saveFriendCache() { + val friendListCache = friendListCache + if (friendListCache != null) { + configuration.friendListCache?.cacheFile?.run { + createFileIfNotExists() + writeText(JsonForCache.encodeToString(FriendListCache.serializer(), friendListCache)) + bot.network.logger.info { "Saved ${friendListCache.list.size} friends to local cache." } + } + } + } + override lateinit var nick: String override val asFriend: Friend by lazy { @@ -100,7 +133,7 @@ internal class QQAndroidBot constructor( override suspend fun sendLogout() { network.run { - StatSvc.Register.offline(client). sendWithoutExpect() + StatSvc.Register.offline(client).sendWithoutExpect() } } diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt index 43e5a0144..2d50bdf06 100644 --- a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt +++ b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt @@ -17,13 +17,17 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import net.mamoe.mirai.Mirai +import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.FriendImpl import net.mamoe.mirai.internal.contact.GroupImpl +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.info.GroupInfoImpl import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.contact.toMiraiFriendInfo import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum +import net.mamoe.mirai.internal.network.protocol.data.jce.SvcRespRegister +import net.mamoe.mirai.internal.network.protocol.data.jce.isValid import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList import net.mamoe.mirai.internal.network.protocol.packet.list.StrangerList @@ -31,11 +35,8 @@ import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.retryCatching import net.mamoe.mirai.utils.verbose -internal interface ContactCache { -} - internal interface ContactUpdater { - suspend fun loadAll() + suspend fun loadAll(registerResp: SvcRespRegister) fun closeAllContacts(e: CancellationException) } @@ -44,9 +45,9 @@ internal class ContactUpdaterImpl( val bot: QQAndroidBot, ) : ContactUpdater { @Synchronized - override suspend fun loadAll() { + override suspend fun loadAll(registerResp: SvcRespRegister) { coroutineScope { - launch { reloadFriendList() } + launch { reloadFriendList(registerResp) } launch { reloadGroupList() } launch { reloadStrangerList() } } @@ -78,48 +79,80 @@ internal class ContactUpdaterImpl( /** * Don't use concurrently */ - private suspend fun reloadFriendList() = bot.network.run { + private suspend fun reloadFriendList(registerResp: SvcRespRegister) = bot.network.run { if (initFriendOk) { return } - logger.info { "Start loading friend list..." } - var currentFriendCount = 0 - var totalFriendCount: Short - while (true) { - val data = FriendList.GetFriendGroupList( - bot.client, currentFriendCount, 150, 0, 0 - ).sendAndExpect(timeoutMillis = 5000, retry = 2) + val friendListCache = bot.friendListCache - totalFriendCount = data.totalFriendCount - data.friendList.forEach { - // atomic - bot.friends.delegate.add( - FriendImpl(bot, bot.coroutineContext, it.toMiraiFriendInfo()) - ).also { currentFriendCount++ } + fun updateCacheSeq(list: List) { + bot.friendListCache?.apply { + friendListSeq = registerResp.iLargeSeq + timeStamp = registerResp.timeStamp + this.list = list + bot.saveFriendCache() } - logger.verbose { "Loading friend list: ${currentFriendCount}/${totalFriendCount}" } - if (currentFriendCount >= totalFriendCount) { - break - } - // delay(200) } - logger.info { "Successfully loaded friend list: $currentFriendCount in total" } + + suspend fun refreshFriendList(): List { + logger.info { "Start loading friend list..." } + val friendInfos = mutableListOf() + + var count = 0 + var total: Short + while (true) { + val data = FriendList.GetFriendGroupList( + bot.client, count, 150, 0, 0 + ).sendAndExpect(timeoutMillis = 5000, retry = 2) + + total = data.totalFriendCount + + for (jceInfo in data.friendList) { + friendInfos.add(jceInfo.toMiraiFriendInfo()) + } + + count += data.friendList.size + logger.verbose { "Loading friend list: ${count}/${total}" } + if (count >= total) break + } + logger.info { "Successfully loaded friend list: $count in total" } + return friendInfos + } + + val list = if (friendListCache?.isValid(registerResp) == true) { + val list = friendListCache.list + bot.network.logger.info { "Loaded ${list.size} friends from local cache." } + list + } else { + refreshFriendList().also { + updateCacheSeq(it) + } + } + + for (friendInfoImpl in list) { + addFriendToBot(friendInfoImpl) + } + + initFriendOk = true } - private suspend fun StTroopNum.reloadGroup() { + private fun addFriendToBot(it: FriendInfo) = + bot.friends.delegate.add(FriendImpl(bot, bot.coroutineContext, it)) + + private suspend fun addGroupToBot(stTroopNum: StTroopNum) { bot.groups.delegate.add( GroupImpl( bot = bot, coroutineContext = bot.coroutineContext, - id = groupCode, - groupInfo = GroupInfoImpl(this), + id = stTroopNum.groupCode, + groupInfo = GroupInfoImpl(stTroopNum), members = Mirai.getRawGroupMemberList( bot, - groupUin, - groupCode, - dwGroupOwnerUin + stTroopNum.groupUin, + stTroopNum.groupCode, + stTroopNum.dwGroupOwnerUin ) ) ) @@ -165,7 +198,7 @@ internal class ContactUpdaterImpl( troopListData.groups.forEach { group -> launch { semaphore.withPermit { - retryCatching(5) { group.reloadGroup() }.getOrThrow() + retryCatching(5) { addGroupToBot(group) }.getOrThrow() } } } diff --git a/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt b/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt new file mode 100644 index 000000000..b4786c15d --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2021 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.network + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl + +internal val JsonForCache = Json { + encodeDefaults = true + ignoreUnknownKeys = true + isLenient = true +} + +@Serializable +internal data class FriendListCache( + var friendListSeq: Long = 0, + /** + * 实际上是个序列号, 不是时间 + */ + var timeStamp: Long = 0, + var list: List = emptyList(), +) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt index aed759b6d..fee835efa 100644 --- a/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt @@ -265,13 +265,8 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") registerClientOnline() - startHeartbeatJobOrKill() - bot.otherClientsLock.withLock { - updateOtherClientsList() - } - launch { while (isActive) { bot.client.wLoginSigInfo.sKey.run { @@ -292,17 +287,17 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo WtLogin15(bot.client).sendAndExpect() } - private suspend fun registerClientOnline() { + private suspend fun registerClientOnline(): StatSvc.Register.Response { // object : OutgoingPacketFactory("push.proxyUnRegister") { // override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Packet? { // return null // } // }.buildOutgoingUniPacket(bot.client) {}.sendWithoutExpect() - kotlin.runCatching { - StatSvc.Register.offline(bot.client).sendAndExpect() - }.getOrElse { logger.warning(it) } + // kotlin.runCatching { + // StatSvc.Register.offline(bot.client).sendAndExpect() + // }.getOrElse { logger.warning(it) } - StatSvc.Register.online(bot.client).sendAndExpect() + return StatSvc.Register.online(bot.client).sendAndExpect() } private suspend fun updateOtherClientsList() { @@ -332,23 +327,34 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo check(bot.isActive) { "bot is dead therefore network can't init." } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init." } - contactUpdater.closeAllContacts(CancellationException("re-init")) + contactUpdater.closeAllContacts(CancellationException("re-init")) if (!pendingEnabled) { pendingIncomingPackets = ConcurrentLinkedQueue() _pendingEnabled.value = true } - contactUpdater.loadAll() + val registerResp = registerClientOnline() this@QQAndroidBotNetworkHandler.launch(CoroutineName("Awaiting ConfigPushSvc.PushReq"), block= ConfigPushSyncer()) - syncMessageSvc() + launch { + syncMessageSvc() + } + + launch { + bot.otherClientsLock.withLock { + updateOtherClientsList() + } + } + + contactUpdater.loadAll(registerResp.origin) bot.firstLoginSucceed = true postInitActions() } + @Suppress("FunctionName") private fun BotNetworkHandler.ConfigPushSyncer(): suspend CoroutineScope.() -> Unit = launch@{ logger.info { "Awaiting ConfigPushSvc.PushReq." } when (val resp: ConfigPushSvc.PushReq.PushReqResponse? = nextEventOrNull(20_000)) { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt index dd1c5aae6..9d1ff5990 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcReqRegister.kt @@ -15,41 +15,41 @@ import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId @Serializable internal class SvcReqRegister( - @TarsId(0) @JvmField val lUin: Long = 0L, - @TarsId(1) @JvmField val lBid: Long = 0L, - @TarsId(2) @JvmField val cConnType: Byte = 0, - @TarsId(3) @JvmField val sOther: String = "", - @TarsId(4) @JvmField val iStatus: Int = 11, - @TarsId(5) @JvmField val bOnlinePush: Byte = 0, - @TarsId(6) @JvmField val bIsOnline: Byte = 0, - @TarsId(7) @JvmField val bIsShowOnline: Byte = 0, - @TarsId(8) @JvmField val bKikPC: Byte = 0, - @TarsId(9) @JvmField val bKikWeak: Byte = 0, - @TarsId(10) @JvmField val timeStamp: Long = 0L, - @TarsId(11) @JvmField val iOSVersion: Long = 0L, - @TarsId(12) @JvmField val cNetType: Byte = 0, - @TarsId(13) @JvmField val sBuildVer: String? = "", - @TarsId(14) @JvmField val bRegType: Byte = 0, - @TarsId(15) @JvmField val vecDevParam: ByteArray? = null, - @TarsId(16) @JvmField val vecGuid: ByteArray? = null, - @TarsId(17) @JvmField val iLocaleID: Int = 2052, - @TarsId(18) @JvmField val bSlientPush: Byte = 0, - @TarsId(19) @JvmField val strDevName: String? = null, - @TarsId(20) @JvmField val strDevType: String? = null, - @TarsId(21) @JvmField val strOSVer: String? = null, - @TarsId(22) @JvmField val bOpenPush: Byte, - @TarsId(23) @JvmField val iLargeSeq: Long, - @TarsId(24) @JvmField val iLastWatchStartTime: Long = 0L, - @TarsId(26) @JvmField val uOldSSOIp: Long = 0L, - @TarsId(27) @JvmField val uNewSSOIp: Long = 0L, - @TarsId(28) @JvmField val sChannelNo: String? = null, - @TarsId(29) @JvmField val lCpId: Long = 0L, - @TarsId(30) @JvmField val strVendorName: String? = null, - @TarsId(31) @JvmField val strVendorOSName: String? = null, - @TarsId(32) @JvmField val strIOSIdfa: String? = null, - @TarsId(33) @JvmField val bytes_0x769_reqbody: ByteArray? = null, - @TarsId(34) @JvmField val bIsSetStatus: Byte = 0, - @TarsId(35) @JvmField val vecServerBuf: ByteArray? = null, - @TarsId(36) @JvmField val bSetMute: Byte = 0 + @TarsId(0) @JvmField var lUin: Long = 0L, + @TarsId(1) @JvmField var lBid: Long = 0L, + @TarsId(2) @JvmField var cConnType: Byte = 0, + @TarsId(3) @JvmField var sOther: String = "", + @TarsId(4) @JvmField var iStatus: Int = 11, + @TarsId(5) @JvmField var bOnlinePush: Byte = 0, + @TarsId(6) @JvmField var bIsOnline: Byte = 0, + @TarsId(7) @JvmField var bIsShowOnline: Byte = 0, + @TarsId(8) @JvmField var bKikPC: Byte = 0, + @TarsId(9) @JvmField var bKikWeak: Byte = 0, + @TarsId(10) @JvmField var timeStamp: Long = 0L, + @TarsId(11) @JvmField var iOSVersion: Long = 0L, + @TarsId(12) @JvmField var cNetType: Byte = 0, + @TarsId(13) @JvmField var sBuildVer: String? = "", + @TarsId(14) @JvmField var bRegType: Byte = 0, + @TarsId(15) @JvmField var vecDevParam: ByteArray? = null, + @TarsId(16) @JvmField var vecGuid: ByteArray? = null, + @TarsId(17) @JvmField var iLocaleID: Int = 2052, + @TarsId(18) @JvmField var bSlientPush: Byte = 0, + @TarsId(19) @JvmField var strDevName: String? = null, + @TarsId(20) @JvmField var strDevType: String? = null, + @TarsId(21) @JvmField var strOSVer: String? = null, + @TarsId(22) @JvmField var bOpenPush: Byte, + @TarsId(23) @JvmField var iLargeSeq: Long, + @TarsId(24) @JvmField var iLastWatchStartTime: Long = 0L, + @TarsId(26) @JvmField var uOldSSOIp: Long = 0L, + @TarsId(27) @JvmField var uNewSSOIp: Long = 0L, + @TarsId(28) @JvmField var sChannelNo: String? = null, + @TarsId(29) @JvmField var lCpId: Long = 0L, + @TarsId(30) @JvmField var strVendorName: String? = null, + @TarsId(31) @JvmField var strVendorOSName: String? = null, + @TarsId(32) @JvmField var strIOSIdfa: String? = null, + @TarsId(33) @JvmField var bytes_0x769_reqbody: ByteArray? = null, + @TarsId(34) @JvmField var bIsSetStatus: Byte = 0, + @TarsId(35) @JvmField var vecServerBuf: ByteArray? = null, + @TarsId(36) @JvmField var bSetMute: Byte = 0 // @SerialId(25) var vecBindUin: ArrayList<*>? = null // ?? 未知泛型 ) : JceStruct \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcRespRegister.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcRespRegister.kt index 0053f81ed..308d493c7 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcRespRegister.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/data/jce/SvcRespRegister.kt @@ -10,6 +10,7 @@ package net.mamoe.mirai.internal.network.protocol.data.jce import kotlinx.serialization.Serializable +import net.mamoe.mirai.internal.network.FriendListCache import net.mamoe.mirai.internal.utils.io.JceStruct import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId @@ -30,7 +31,15 @@ internal class SvcRespRegister( @JvmField @TarsId(11) val iClientPort: Int = 0, @JvmField @TarsId(12) val iHelloInterval: Int = 300, @JvmField @TarsId(13) val iLargeSeq: Long = 0L, + /** + * =1 好友列表更新 + */ @JvmField @TarsId(14) val largeSeqUpdate: Byte = 0, @JvmField @TarsId(15) val bytes_0x769_rspBody: ByteArray? = null, @JvmField @TarsId(16) val iStatus: Int? = 0 ) : JceStruct + +internal fun FriendListCache.isValid(svcRespRegister: SvcRespRegister): Boolean { + return svcRespRegister.iLargeSeq == friendListSeq && svcRespRegister.timeStamp == timeStamp +// return this.largeSeqUpdate != 0.toByte() +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt index da02eb756..c4706eca1 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt @@ -25,6 +25,7 @@ import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.appId import net.mamoe.mirai.internal.createOtherClient import net.mamoe.mirai.internal.message.contextualBugReportException +import net.mamoe.mirai.internal.network.FriendListCache import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.QQAndroidClient import net.mamoe.mirai.internal.network.getRandomByteArray @@ -94,29 +95,30 @@ internal class StatSvc { internal object Register : OutgoingPacketFactory("StatSvc.register") { - internal object Response : Packet { + internal class Response( + val origin: SvcRespRegister + ) : Packet { override fun toString(): String = "Response(StatSvc.register)" } override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { val packet = readUniPacket(SvcRespRegister.serializer()) - if (packet.updateFlag.toInt() == 1) { - //TODO 加载好友列表 - } - if (packet.largeSeqUpdate.toInt() == 1) { - //TODO 刷新好友列表 - } packet.iHelloInterval.let { bot.configuration.heartbeatPeriodMillis = it.times(1000).toLong() } - return Response + return Response(packet) } fun online( client: QQAndroidClient, regPushReason: RegPushReason = RegPushReason.appRegister - ) = impl(client, 1 or 2 or 4, client.onlineStatus, regPushReason) + ) = impl(client, 1 or 2 or 4, client.onlineStatus, regPushReason) { + client.bot.friendListCache?.let { friendListCache: FriendListCache -> + iLargeSeq = friendListCache.friendListSeq + // timeStamp = friendListCache.timeStamp + } + } fun offline( client: QQAndroidClient, @@ -127,7 +129,8 @@ internal class StatSvc { client: QQAndroidClient, bid: Long, status: OnlineStatus, - regPushReason: RegPushReason = RegPushReason.appRegister + regPushReason: RegPushReason = RegPushReason.appRegister, + applyAction: SvcReqRegister.() -> Unit = {} ) = buildLoginOutgoingPacket( client, bodyType = 1, @@ -198,7 +201,7 @@ internal class StatSvc { ) ), bSetMute = 0 - ) + ).apply(applyAction) ) ) ) diff --git a/mirai-core/src/commonMain/kotlin/utils/ScheduledJob.kt b/mirai-core/src/commonMain/kotlin/utils/ScheduledJob.kt new file mode 100644 index 000000000..4a5fa0d5b --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/utils/ScheduledJob.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2020 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.utils + +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.sample +import kotlin.coroutines.CoroutineContext +import kotlin.time.Duration + +@OptIn(FlowPreview::class) +internal class ScheduledJob( + coroutineContext: CoroutineContext, + val interval: Duration, + private val task: suspend () -> Unit +) : CoroutineScope by CoroutineScope(coroutineContext + SupervisorJob(coroutineContext[Job])) { + private val coroutineExceptionHandler = + coroutineContext[CoroutineExceptionHandler].also { + requireNotNull(it) { + "Could not init ScheduledJob, coroutineExceptionHandler == null" + } + } + + private val channel = Channel(Channel.CONFLATED) + + fun notice() { + if (interval == Duration.ZERO) { + launch { task() } + } else channel.offer(Unit) + } + + private suspend fun doTask() { + runCatching { + task() + }.onFailure { + coroutineExceptionHandler!!.handleException(currentCoroutineContext(), it) + } + } + + init { + if (interval != Duration.ZERO) { + launch { + channel.receiveAsFlow() + .runCatching { + sample(interval.toLongMilliseconds()) + } + .fold( + onSuccess = { flow -> + flow.collect { doTask() } + }, + onFailure = { + // binary change + while (isActive) { + delay(interval) + task() + } + } + ) + } + } + } +} \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt b/mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt new file mode 100644 index 000000000..d46c84aa3 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2019-2021 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/master/LICENSE + */ +package net.mamoe.mirai.internal.utils + +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Test +import java.util.concurrent.atomic.AtomicInteger +import kotlin.test.assertEquals +import kotlin.time.seconds + +internal class ScheduledJobTest { + @Test + fun testScheduledJob() { + runBlocking { + val scope = CoroutineScope(CoroutineExceptionHandler { _, throwable -> + throwable.printStackTrace() + }) + val invoked = AtomicInteger(0) + val job = ScheduledJob(scope.coroutineContext, 1.seconds) { + invoked.incrementAndGet() + } + delay(100) + assertEquals(0, invoked.get()) + job.notice() + job.notice() + job.notice() + } + } +} \ No newline at end of file From 78ae44d0e637feb5ae5b17263517861655a3ad5b Mon Sep 17 00:00:00 2001 From: gao_cai_sheng Date: Sun, 7 Feb 2021 13:02:39 +0800 Subject: [PATCH 05/11] Add gradlew executable permission (#972) --- gradlew | 0 gradlew.bat | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 From 7fac83702a259c3eb86561a367f494772080abd3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 12:49:12 +0800 Subject: [PATCH 06/11] Support group list cache, close #987 --- .../commonMain/kotlin/event/events/group.kt | 50 +++---- .../commonMain/kotlin/event/events/types.kt | 14 ++ .../kotlin/utils/BotConfiguration.kt | 33 +++++ mirai-core/src/commonMain/kotlin/MiraiImpl.kt | 1 + .../src/commonMain/kotlin/QQAndroidBot.kt | 14 +- .../kotlin/network/ContactListCache.kt | 126 ++++++++++++++++++ .../kotlin/network/ContactUpdater.kt | 41 ++++-- .../kotlin/network/FriendListCache.kt | 30 ----- .../protocol/packet/list/StrangerList.kt | 6 +- 9 files changed, 243 insertions(+), 72 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/ContactListCache.kt delete mode 100644 mirai-core/src/commonMain/kotlin/network/FriendListCache.kt diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt index 20b1c544c..7566e4d8c 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt @@ -9,7 +9,9 @@ @file:JvmMultifileClass @file:JvmName("BotEventsKt") -@file:Suppress("unused", "FunctionName", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "DEPRECATION_ERROR") +@file:Suppress("unused", "FunctionName", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "DEPRECATION_ERROR", + "MemberVisibilityCanBePrivate" +) package net.mamoe.mirai.event.events @@ -28,8 +30,8 @@ import java.util.concurrent.atomic.AtomicBoolean /** * 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群. */ -public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent() { - public abstract val group: Group +public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent { + public abstract override val group: Group /** * 机器人主动退出一个群. @@ -64,7 +66,7 @@ public data class BotGroupPermissionChangeEvent @MiraiInternalApi constructor( public override val group: Group, public val origin: MemberPermission, public val new: MemberPermission -) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent() +) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent /** * Bot 被禁言 @@ -75,7 +77,7 @@ public data class BotMuteEvent @MiraiInternalApi constructor( * 操作人. */ public val operator: NormalMember -) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent() { +) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent(), GroupMemberInfoChangeEvent { public override val group: Group get() = operator.group } @@ -88,7 +90,7 @@ public data class BotUnmuteEvent @MiraiInternalApi constructor( * 操作人. */ public val operator: NormalMember -) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent() { +) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent(), GroupMemberInfoChangeEvent { public override val group: Group get() = operator.group } @@ -96,7 +98,7 @@ public data class BotUnmuteEvent @MiraiInternalApi constructor( /** * Bot 成功加入了一个新群 */ -public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, AbstractEvent() { +public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent { public abstract override val group: Group /** @@ -164,7 +166,7 @@ public data class GroupNameChangeEvent @MiraiInternalApi constructor( * 操作人. 为 null 时则是机器人操作 */ public override val operator: NormalMember? -) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent /** * 入群公告改变. 此事件广播前修改就已经完成. @@ -177,7 +179,7 @@ public data class GroupEntranceAnnouncementChangeEvent @MiraiInternalApi constru * 操作人. 为 null 时则是机器人操作 */ public override val operator: NormalMember? -) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent /** @@ -191,7 +193,7 @@ public data class GroupMuteAllEvent @MiraiInternalApi constructor( * 操作人. 为 null 时则是机器人操作 */ public override val operator: NormalMember? -) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent /** @@ -205,7 +207,7 @@ public data class GroupAllowAnonymousChatEvent @MiraiInternalApi constructor( * 操作人. 为 null 时则是机器人操作 */ public override val operator: NormalMember? -) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent /** @@ -216,7 +218,7 @@ public data class GroupAllowConfessTalkEvent @MiraiInternalApi constructor( public override val new: Boolean, public override val group: Group, public val isByBot: Boolean // 无法获取操作人 -) : GroupSettingChangeEvent, Packet, AbstractEvent() +) : GroupSettingChangeEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent /** * 群 "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成. @@ -229,7 +231,7 @@ public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor( * 操作人. 为 null 时则是机器人操作 */ public override val operator: NormalMember? -) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupSettingChangeEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent // endregion @@ -245,7 +247,7 @@ public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor( public sealed class MemberJoinEvent( public override val member: NormalMember ) : GroupMemberEvent, BotPassiveEvent, Packet, - AbstractEvent() { + AbstractEvent(), GroupMemberInfoChangeEvent { /** * 被邀请加入群 */ @@ -282,7 +284,7 @@ public sealed class MemberJoinEvent( /** * 成员已经离开群的事件. 在事件广播前成员就已经从 [Group.members] 中删除 */ -public sealed class MemberLeaveEvent : GroupMemberEvent, AbstractEvent() { +public sealed class MemberLeaveEvent : GroupMemberEvent, AbstractEvent(), GroupMemberInfoChangeEvent { /** * 成员被踢出群. 成员不可能是机器人自己. */ @@ -320,13 +322,13 @@ public data class BotInvitedJoinGroupRequestEvent @MiraiInternalApi constructor( * 邀请入群的账号的 id */ public val invitorId: Long, - public val groupId: Long, + public override val groupId: Long, public val groupName: String, /** * 邀请人昵称 */ public val invitorNick: String -) : BotEvent, Packet, AbstractEvent() { +) : BotEvent, Packet, AbstractEvent(), BaseGroupMemberInfoChangeEvent { /** * 邀请人. 若在事件发生后邀请人已经被删除好友, [invitor] 为 `null`. */ @@ -360,7 +362,7 @@ public data class MemberJoinRequestEvent @MiraiInternalApi constructor( * 申请入群的账号的 id */ val fromId: Long, - val groupId: Long, + override val groupId: Long, val groupName: String, /** * 申请人昵称 @@ -370,7 +372,7 @@ public data class MemberJoinRequestEvent @MiraiInternalApi constructor( * 邀请人 id(如果是邀请入群) */ val invitorId: Long? = null -) : BotEvent, Packet, AbstractEvent() { +) : BotEvent, Packet, AbstractEvent(), BaseGroupMemberInfoChangeEvent { /** * 相关群. 若在事件发生后机器人退出这个群, [group] 为 `null`. */ @@ -471,7 +473,7 @@ public data class MemberCardChangeEvent @MiraiInternalApi constructor( public val new: String, public override val member: NormalMember -) : GroupMemberEvent, Packet, AbstractEvent() +) : GroupMemberEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent /** * 成员群头衔改动. 一定为群主操作 @@ -495,7 +497,7 @@ public data class MemberSpecialTitleChangeEvent @MiraiInternalApi constructor( * 为 null 时则是机器人操作. */ public override val operator: NormalMember? -) : GroupMemberEvent, GroupOperableEvent, AbstractEvent() +) : GroupMemberEvent, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent // endregion @@ -509,7 +511,7 @@ public data class MemberPermissionChangeEvent @MiraiInternalApi constructor( public override val member: NormalMember, public val origin: MemberPermission, public val new: MemberPermission -) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent() +) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent // endregion @@ -528,7 +530,7 @@ public data class MemberMuteEvent @MiraiInternalApi constructor( * 操作人. 为 null 则为机器人操作 */ public override val operator: Member? -) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent /** * 群成员被取消禁言事件. 被禁言的成员都不可能是机器人本人 @@ -541,7 +543,7 @@ public data class MemberUnmuteEvent @MiraiInternalApi constructor( * 操作人. 为 null 则为机器人操作 */ public override val operator: Member? -) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent() +) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent // endregion diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/types.kt b/mirai-core-api/src/commonMain/kotlin/event/events/types.kt index 9e90afb58..aa2b25f4b 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/types.kt +++ b/mirai-core-api/src/commonMain/kotlin/event/events/types.kt @@ -16,6 +16,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.Event import net.mamoe.mirai.internal.network.Packet +import net.mamoe.mirai.utils.MiraiInternalApi /** * 有关一个 [Bot] 的事件 @@ -110,6 +111,19 @@ public interface GroupMemberEvent : GroupEvent, UserEvent { override val user: Member get() = member } +/** + * 用于更新缓存, 请勿使用. + */ +@MiraiInternalApi +internal interface BaseGroupMemberInfoChangeEvent : BotEvent { + val groupId: Long +} // for cache + +@MiraiInternalApi +internal interface GroupMemberInfoChangeEvent : BotEvent, GroupEvent, BaseGroupMemberInfoChangeEvent { + override val groupId: Long get() = group.id +} // for cache + public interface OtherClientEvent : BotEvent, Packet { public val client: OtherClient override val bot: Bot get() = client.bot diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index 806fb727b..10a5d1cbf 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -347,6 +347,39 @@ public open class BotConfiguration { // open for Java } + /** + * 非 `null` 时启用群成员列表缓存, 加快初始化速度. 在启用后将会在下载群成员列表后保存到文件, 并在修改时自动保存. + * @since 2.4 + * @see enableGroupMemberListCache + */ + public var groupMemberListCache: GroupMemberListCache? = GroupMemberListCache() + + /** + * 群成员列表缓存设置. + * @since 2.4 + * @see groupMemberListCache + */ + public class GroupMemberListCache @JvmOverloads constructor( + /** + * 缓存文件位置, 相对于 [workingDir] 的路径. + */ + public val cacheDir: File = File("cache"), + /** + * 在有好友列表修改是 + */ + public val saveIntervalMillis: Long = 60_000, + ) + + /** + * 启用群成员列表缓存. + * @since 2.4 + * @see BotConfiguration.enableGroupMemberListCache + */ + public fun enableGroupMemberListCache() { + friendListCache = FriendListCache() + } + + /** * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. * diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index 71d91a3c0..6babe0880 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.withContext import kotlinx.io.core.discardExact import kotlinx.io.core.readBytes import kotlinx.serialization.json.* +import net.mamoe.kjbb.JvmBlockingBridge import net.mamoe.mirai.* import net.mamoe.mirai.contact.* import net.mamoe.mirai.data.* diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index 57d5eef1d..fd1ed3cee 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -78,19 +78,24 @@ internal class QQAndroidBot constructor( override val friends: ContactList = ContactList() val friendListCache: FriendListCache? by lazy { - configuration.friendListCache?.cacheFile?.run { - val ret = loadAs(FriendListCache.serializer(), JsonForCache) ?: FriendListCache() + configuration.friendListCache?.cacheFile?.let { cacheFile -> + val ret = configuration.workingDir.resolve(cacheFile).loadAs(FriendListCache.serializer(), JsonForCache) ?: FriendListCache() @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") bot.eventChannel.parentScope(this@QQAndroidBot) .subscribeAlways { friendListSaver?.notice() } - ret } } + val groupMemberListCaches: GroupMemberListCaches? by lazy { + if (configuration.groupMemberListCache!= null) { + GroupMemberListCaches(this) + } else null + } + private val friendListSaver by lazy { configuration.friendListCache?.let { friendListCache: BotConfiguration.FriendListCache -> @@ -99,11 +104,10 @@ internal class QQAndroidBot constructor( } } } - fun saveFriendCache() { val friendListCache = friendListCache if (friendListCache != null) { - configuration.friendListCache?.cacheFile?.run { + configuration.friendListCache?.cacheFile?.let { configuration.workingDir.resolve(it) }?.run { createFileIfNotExists() writeText(JsonForCache.encodeToString(FriendListCache.serializer(), friendListCache)) bot.network.logger.info { "Saved ${friendListCache.list.size} friends to local cache." } diff --git a/mirai-core/src/commonMain/kotlin/network/ContactListCache.kt b/mirai-core/src/commonMain/kotlin/network/ContactListCache.kt new file mode 100644 index 000000000..f5fde74c8 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/ContactListCache.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2019-2021 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/master/LICENSE + */ + +package net.mamoe.mirai.internal.network + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import net.mamoe.mirai.internal.QQAndroidBot +import net.mamoe.mirai.internal.contact.info.FriendInfoImpl +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl +import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum +import net.mamoe.mirai.internal.utils.ScheduledJob +import net.mamoe.mirai.utils.createFileIfNotExists +import net.mamoe.mirai.utils.info +import net.mamoe.mirai.utils.runBIO +import java.io.File +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentLinkedQueue +import kotlin.time.milliseconds + +internal val JsonForCache = Json { + encodeDefaults = true + ignoreUnknownKeys = true + isLenient = true +} + +@Serializable +internal data class FriendListCache( + var friendListSeq: Long = 0, + /** + * 实际上是个序列号, 不是时间 + */ + var timeStamp: Long = 0, + var list: List = emptyList(), +) + +@Serializable +internal data class GroupMemberListCache( + var troopMemberNumSeq: Long, + var list: List = emptyList(), +) + +internal fun GroupMemberListCache.isValid(stTroopNum: StTroopNum): Boolean { + return this.list.size == stTroopNum.dwMemberNum?.toInt() && this.troopMemberNumSeq == stTroopNum.dwMemberNumSeq +} + +internal class GroupMemberListCaches( + private val bot: QQAndroidBot, +) { + init { + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + bot.eventChannel.parentScope(bot) + .subscribeAlways { + groupListSaver.notice() + } + + } + + private val changedGroups: MutableCollection = ConcurrentLinkedQueue() + private val groupListSaver by lazy { + ScheduledJob(bot.coroutineContext, bot.configuration.groupMemberListCache!!.saveIntervalMillis.milliseconds) { + runBIO { saveGroupCaches() } + } + } + + fun reportChanged(groupCode: Long) { + changedGroups.add(groupCode) + groupListSaver.notice() + } + + private fun takeCurrentChangedGroups(): Map { + val ret = HashMap() + changedGroups.removeIf { + ret[it] = get(it) + true + } + return ret + } + + private val cacheDir by lazy { + bot.configuration.groupMemberListCache!!.cacheDir.let { bot.configuration.workingDir.resolve(it) } + } + + private fun resolveCacheFile(groupCode: Long): File { + cacheDir.mkdirs() + return cacheDir.resolve("$groupCode.json") + } + + fun saveGroupCaches() { + val currentChanged = takeCurrentChangedGroups() + if (currentChanged.isNotEmpty()) { + for ((id, cache) in currentChanged) { + val file = resolveCacheFile(id) + file.createFileIfNotExists() + file.writeText(JsonForCache.encodeToString(GroupMemberListCache.serializer(), cache)) + } + bot.network.logger.info { "Saved ${currentChanged.size} groups to local cache." } + } + } + + val map: MutableMap = ConcurrentHashMap() + + fun retainAll(list: Collection) { + this.map.keys.retainAll(list) + } + + operator fun get(id: Long): GroupMemberListCache { + return map.getOrPut(id) { + val file = resolveCacheFile(id) + if (file.exists() && file.isFile) { + val text = file.readText() + if (text.isNotBlank()) { + return JsonForCache.decodeFromString(GroupMemberListCache.serializer(), text) + } + } + + GroupMemberListCache(0, emptyList()) + } + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt index 2d50bdf06..e60e883e3 100644 --- a/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt +++ b/mirai-core/src/commonMain/kotlin/network/ContactUpdater.kt @@ -18,11 +18,13 @@ import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit import net.mamoe.mirai.Mirai import net.mamoe.mirai.data.FriendInfo +import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.contact.FriendImpl import net.mamoe.mirai.internal.contact.GroupImpl import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.info.GroupInfoImpl +import net.mamoe.mirai.internal.contact.info.MemberInfoImpl import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl import net.mamoe.mirai.internal.contact.toMiraiFriendInfo import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum @@ -141,19 +143,38 @@ internal class ContactUpdaterImpl( private fun addFriendToBot(it: FriendInfo) = bot.friends.delegate.add(FriendImpl(bot, bot.coroutineContext, it)) - private suspend fun addGroupToBot(stTroopNum: StTroopNum) { + private suspend fun addGroupToBot(stTroopNum: StTroopNum) = stTroopNum.run { + suspend fun refreshGroupMemberList(): Sequence { + return Mirai.getRawGroupMemberList( + bot, + groupUin, + groupCode, + dwGroupOwnerUin + ) + } + + val cache = bot.groupMemberListCaches?.get(groupCode) + val members = if (cache != null) { + if (cache.isValid(stTroopNum)) { + cache.list.asSequence().also { + bot.network.logger.info { "Loaded ${cache.list.size} members from local cache for group ${groupName} (${groupCode})" } + } + } else refreshGroupMemberList().also { sequence -> + cache.troopMemberNumSeq = dwMemberNumSeq ?: 0 + cache.list = sequence.mapTo(ArrayList()) { it as MemberInfoImpl } + bot.groupMemberListCaches!!.reportChanged(groupCode) + } + } else { + refreshGroupMemberList() + } + bot.groups.delegate.add( GroupImpl( bot = bot, coroutineContext = bot.coroutineContext, - id = stTroopNum.groupCode, + id = groupCode, groupInfo = GroupInfoImpl(stTroopNum), - members = Mirai.getRawGroupMemberList( - bot, - stTroopNum.groupUin, - stTroopNum.groupCode, - stTroopNum.dwGroupOwnerUin - ) + members = members ) ) } @@ -184,9 +205,7 @@ internal class ContactUpdaterImpl( if (initGroupOk) { return } - logger.info { "Start syncing group config..." } TroopManagement.GetTroopConfig(bot.client).sendAndExpect() - logger.info { "Successfully synced group config." } logger.info { "Start loading group list..." } val troopListData = FriendList.GetTroopListSimplify(bot.client) @@ -203,7 +222,9 @@ internal class ContactUpdaterImpl( } } } + logger.info { "Successfully loaded group list: ${troopListData.groups.size} in total." } + bot.groupMemberListCaches?.saveGroupCaches() initGroupOk = true } diff --git a/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt b/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt deleted file mode 100644 index b4786c15d..000000000 --- a/mirai-core/src/commonMain/kotlin/network/FriendListCache.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2019-2021 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/master/LICENSE - */ - -package net.mamoe.mirai.internal.network - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import net.mamoe.mirai.internal.contact.info.FriendInfoImpl - -internal val JsonForCache = Json { - encodeDefaults = true - ignoreUnknownKeys = true - isLenient = true -} - -@Serializable -internal data class FriendListCache( - var friendListSeq: Long = 0, - /** - * 实际上是个序列号, 不是时间 - */ - var timeStamp: Long = 0, - var list: List = emptyList(), -) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/StrangerList.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/StrangerList.kt index f1a0f6b95..44af3e529 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/StrangerList.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/list/StrangerList.kt @@ -30,7 +30,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf internal class StrangerList { object GetStrangerList : OutgoingPacketFactory("OidbSvc.0x5d2_0") { - class Response(val result: Int, val strangerList: List) : Packet { + class Response(val result: Int, val strangerList: List, val origin: Oidb0x5d2.RspGetList?) : Packet { override fun toString(): String { return "StrangerList.GetStrangerList.Response(result=$result)" } @@ -61,10 +61,10 @@ internal class StrangerList { if (pkg.result == 0) { pkg.bodybuffer.loadAs(Oidb0x5d2.RspBody.serializer()).rspGetList!!.let { bot.client.strangerSeq = it.seq - return Response(pkg.result, it.list) + return Response(pkg.result, it.list, it) } } - return Response(pkg.result, emptyList()) + return Response(pkg.result, emptyList(), null) } } From 4f3ced5407365a6f5cccda17a0c598c4b5abe7ca Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 12:53:46 +0800 Subject: [PATCH 07/11] apiDump --- .../api/binary-compatibility-validator.api | 78 ++++++++++++------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/binary-compatibility-validator/api/binary-compatibility-validator.api b/binary-compatibility-validator/api/binary-compatibility-validator.api index df9ae4ce0..8f681ffd5 100644 --- a/binary-compatibility-validator/api/binary-compatibility-validator.api +++ b/binary-compatibility-validator/api/binary-compatibility-validator.api @@ -1915,7 +1915,7 @@ public final class net/mamoe/mirai/event/events/BotEventsKt { public static final synthetic fun isSuccess (Lnet/mamoe/mirai/event/events/MessagePostSendEvent;)Z } -public final class net/mamoe/mirai/event/events/BotGroupPermissionChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/BotGroupPermissionChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/MemberPermission;Lnet/mamoe/mirai/contact/MemberPermission;)V public final fun component1 ()Lnet/mamoe/mirai/contact/Group; public final fun component2 ()Lnet/mamoe/mirai/contact/MemberPermission; @@ -1930,7 +1930,7 @@ public final class net/mamoe/mirai/event/events/BotGroupPermissionChangeEvent : public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/BotInvitedJoinGroupRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/BotInvitedJoinGroupRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BaseGroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/Bot;JJJLjava/lang/String;Ljava/lang/String;)V public final synthetic fun accept ()Lkotlin/Unit; public final fun accept ()V @@ -1946,7 +1946,7 @@ public final class net/mamoe/mirai/event/events/BotInvitedJoinGroupRequestEvent public fun equals (Ljava/lang/Object;)Z public fun getBot ()Lnet/mamoe/mirai/Bot; public final fun getEventId ()J - public final fun getGroupId ()J + public fun getGroupId ()J public final fun getGroupName ()Ljava/lang/String; public final fun getInvitor ()Lnet/mamoe/mirai/contact/Friend; public final fun getInvitorId ()J @@ -1958,7 +1958,7 @@ public final class net/mamoe/mirai/event/events/BotInvitedJoinGroupRequestEvent public fun toString ()Ljava/lang/String; } -public abstract class net/mamoe/mirai/event/events/BotJoinGroupEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/internal/network/Packet { +public abstract class net/mamoe/mirai/event/events/BotJoinGroupEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public abstract fun getGroup ()Lnet/mamoe/mirai/contact/Group; } @@ -1996,7 +1996,7 @@ public final class net/mamoe/mirai/event/events/BotJoinGroupEvent$Retrieve : net public fun toString ()Ljava/lang/String; } -public abstract class net/mamoe/mirai/event/events/BotLeaveEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { +public abstract class net/mamoe/mirai/event/events/BotLeaveEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun getBot ()Lnet/mamoe/mirai/Bot; public abstract fun getGroup ()Lnet/mamoe/mirai/contact/Group; } @@ -2026,7 +2026,7 @@ public final class net/mamoe/mirai/event/events/BotLeaveEvent$Kick : net/mamoe/m public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/BotMuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/BotMuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (ILnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()I public final fun component2 ()Lnet/mamoe/mirai/contact/NormalMember; @@ -2181,7 +2181,7 @@ public final class net/mamoe/mirai/event/events/BotReloginEvent : net/mamoe/mira public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/BotUnmuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/BotUnmuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Lnet/mamoe/mirai/contact/NormalMember; public final fun copy (Lnet/mamoe/mirai/contact/NormalMember;)Lnet/mamoe/mirai/event/events/BotUnmuteEvent; @@ -2200,7 +2200,7 @@ public final class net/mamoe/mirai/event/events/EventCancelledException : java/l public fun (Ljava/lang/Throwable;)V } -public final class net/mamoe/mirai/event/events/FriendAddEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/FriendAddEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/Friend;)V public final fun component1 ()Lnet/mamoe/mirai/contact/Friend; public final fun copy (Lnet/mamoe/mirai/contact/Friend;)Lnet/mamoe/mirai/event/events/FriendAddEvent; @@ -2221,7 +2221,7 @@ public final class net/mamoe/mirai/event/events/FriendAvatarChangedEvent : net/m public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/FriendDeleteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/FriendDeleteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public final fun component1 ()Lnet/mamoe/mirai/contact/Friend; public final fun copy (Lnet/mamoe/mirai/contact/Friend;)Lnet/mamoe/mirai/event/events/FriendDeleteEvent; public static synthetic fun copy$default (Lnet/mamoe/mirai/event/events/FriendDeleteEvent;Lnet/mamoe/mirai/contact/Friend;ILjava/lang/Object;)Lnet/mamoe/mirai/event/events/FriendDeleteEvent; @@ -2316,7 +2316,7 @@ public final class net/mamoe/mirai/event/events/FriendMessageSyncEvent : net/mam public fun getTime ()I } -public final class net/mamoe/mirai/event/events/FriendNickChangedEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/FriendNickChangedEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public final fun component1 ()Lnet/mamoe/mirai/contact/Friend; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; @@ -2330,7 +2330,7 @@ public final class net/mamoe/mirai/event/events/FriendNickChangedEvent : net/mam public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public final fun component1 ()Lnet/mamoe/mirai/contact/Friend; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/String; @@ -2344,7 +2344,7 @@ public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/ma public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/GroupAllowAnonymousChatEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupAllowAnonymousChatEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (ZZLnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Z public final fun component2 ()Z @@ -2364,7 +2364,7 @@ public final class net/mamoe/mirai/event/events/GroupAllowAnonymousChatEvent : n public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/GroupAllowConfessTalkEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupAllowConfessTalkEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (ZZLnet/mamoe/mirai/contact/Group;Z)V public final fun component1 ()Z public final fun component2 ()Z @@ -2383,7 +2383,7 @@ public final class net/mamoe/mirai/event/events/GroupAllowConfessTalkEvent : net public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/GroupAllowMemberInviteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupAllowMemberInviteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (ZZLnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Z public final fun component2 ()Z @@ -2407,7 +2407,7 @@ public abstract interface class net/mamoe/mirai/event/events/GroupAwareMessageEv public abstract fun getGroup ()Lnet/mamoe/mirai/contact/Group; } -public final class net/mamoe/mirai/event/events/GroupEntranceAnnouncementChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupEntranceAnnouncementChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; @@ -2505,7 +2505,7 @@ public final class net/mamoe/mirai/event/events/GroupMessageSyncEvent : net/mamo public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/GroupMuteAllEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupMuteAllEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (ZZLnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Z public final fun component2 ()Z @@ -2525,7 +2525,7 @@ public final class net/mamoe/mirai/event/events/GroupMuteAllEvent : net/mamoe/mi public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/GroupNameChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/GroupNameChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/event/events/GroupSettingChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; @@ -2678,7 +2678,7 @@ public final class net/mamoe/mirai/event/events/ImageUploadEvent$Succeed : net/m public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberCardChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/MemberCardChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; @@ -2727,7 +2727,7 @@ public final class net/mamoe/mirai/event/events/MemberHonorChangeEvent$Lose : ne public fun toString ()Ljava/lang/String; } -public abstract class net/mamoe/mirai/event/events/MemberJoinEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/internal/network/Packet { +public abstract class net/mamoe/mirai/event/events/MemberJoinEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public synthetic fun (Lnet/mamoe/mirai/contact/NormalMember;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun getMember ()Lnet/mamoe/mirai/contact/Member; public fun getMember ()Lnet/mamoe/mirai/contact/NormalMember; @@ -2771,7 +2771,7 @@ public final class net/mamoe/mirai/event/events/MemberJoinEvent$Retrieve : net/m public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberJoinRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/MemberJoinRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BaseGroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { public static final field Companion Lnet/mamoe/mirai/event/events/MemberJoinRequestEvent$Companion; public synthetic fun (Lnet/mamoe/mirai/Bot;JLjava/lang/String;JJLjava/lang/String;Ljava/lang/String;)V public fun (Lnet/mamoe/mirai/Bot;JLjava/lang/String;JJLjava/lang/String;Ljava/lang/String;Ljava/lang/Long;)V @@ -2797,7 +2797,7 @@ public final class net/mamoe/mirai/event/events/MemberJoinRequestEvent : net/mam public final fun getFromId ()J public final fun getFromNick ()Ljava/lang/String; public final fun getGroup ()Lnet/mamoe/mirai/contact/Group; - public final fun getGroupId ()J + public fun getGroupId ()J public final fun getGroupName ()Ljava/lang/String; public final fun getInvitor ()Lnet/mamoe/mirai/contact/NormalMember; public final fun getInvitorId ()Ljava/lang/Long; @@ -2820,7 +2820,7 @@ public final class net/mamoe/mirai/event/events/MemberJoinRequestEvent : net/mam public fun toString ()Ljava/lang/String; } -public abstract class net/mamoe/mirai/event/events/MemberLeaveEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent { +public abstract class net/mamoe/mirai/event/events/MemberLeaveEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent { } public final class net/mamoe/mirai/event/events/MemberLeaveEvent$Kick : net/mamoe/mirai/event/events/MemberLeaveEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/internal/network/Packet { @@ -2850,7 +2850,7 @@ public final class net/mamoe/mirai/event/events/MemberLeaveEvent$Quit : net/mamo public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberMuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/MemberMuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/Member;ILnet/mamoe/mirai/contact/Member;)V public final fun component1 ()Lnet/mamoe/mirai/contact/Member; public final fun component2 ()I @@ -2865,7 +2865,7 @@ public final class net/mamoe/mirai/event/events/MemberMuteEvent : net/mamoe/mira public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberPermissionChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/MemberPermissionChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotPassiveEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/NormalMember;Lnet/mamoe/mirai/contact/MemberPermission;Lnet/mamoe/mirai/contact/MemberPermission;)V public final fun component1 ()Lnet/mamoe/mirai/contact/NormalMember; public final fun component2 ()Lnet/mamoe/mirai/contact/MemberPermission; @@ -2881,7 +2881,7 @@ public final class net/mamoe/mirai/event/events/MemberPermissionChangeEvent : ne public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberSpecialTitleChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupOperableEvent { +public final class net/mamoe/mirai/event/events/MemberSpecialTitleChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent { public fun (Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/contact/NormalMember;Lnet/mamoe/mirai/contact/NormalMember;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; @@ -2900,7 +2900,7 @@ public final class net/mamoe/mirai/event/events/MemberSpecialTitleChangeEvent : public fun toString ()Ljava/lang/String; } -public final class net/mamoe/mirai/event/events/MemberUnmuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/MemberUnmuteEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/GroupMemberEvent, net/mamoe/mirai/event/events/GroupMemberInfoChangeEvent, net/mamoe/mirai/event/events/GroupOperableEvent, net/mamoe/mirai/internal/network/Packet { public fun (Lnet/mamoe/mirai/contact/Member;Lnet/mamoe/mirai/contact/Member;)V public final fun component1 ()Lnet/mamoe/mirai/contact/Member; public final fun component2 ()Lnet/mamoe/mirai/contact/Member; @@ -2999,7 +2999,7 @@ public final class net/mamoe/mirai/event/events/MessageRecallEvent$GroupRecall : public abstract interface class net/mamoe/mirai/event/events/MessageSyncEvent : net/mamoe/mirai/event/events/MessageEvent { } -public final class net/mamoe/mirai/event/events/NewFriendRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/internal/network/Packet { +public final class net/mamoe/mirai/event/events/NewFriendRequestEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/BotEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet { public final synthetic fun accept ()Lkotlin/Unit; public final fun accept ()V public final fun accept (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -5393,6 +5393,8 @@ public class net/mamoe/mirai/utils/BotConfiguration { public fun ()V public final fun autoReconnectOnForceOffline ()V public final fun copy ()Lnet/mamoe/mirai/utils/BotConfiguration; + public final fun enableFriendListCache ()V + public final fun enableGroupMemberListCache ()V public final fun fileBasedDeviceInfo ()V public final fun fileBasedDeviceInfo (Ljava/lang/String;)V public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V @@ -5401,6 +5403,8 @@ public class net/mamoe/mirai/utils/BotConfiguration { public static final fun getDefault ()Lnet/mamoe/mirai/utils/BotConfiguration; public final fun getDeviceInfo ()Lkotlin/jvm/functions/Function1; public final fun getFirstReconnectDelayMillis ()J + public final fun getFriendListCache ()Lnet/mamoe/mirai/utils/BotConfiguration$FriendListCache; + public final fun getGroupMemberListCache ()Lnet/mamoe/mirai/utils/BotConfiguration$GroupMemberListCache; public final fun getHeartbeatPeriodMillis ()J public final fun getHeartbeatTimeoutMillis ()J public final fun getHighwayUploadCoroutineCount ()I @@ -5439,6 +5443,8 @@ public class net/mamoe/mirai/utils/BotConfiguration { public final fun setBotLoggerSupplier (Lkotlin/jvm/functions/Function1;)V public final fun setDeviceInfo (Lkotlin/jvm/functions/Function1;)V public final fun setFirstReconnectDelayMillis (J)V + public final fun setFriendListCache (Lnet/mamoe/mirai/utils/BotConfiguration$FriendListCache;)V + public final fun setGroupMemberListCache (Lnet/mamoe/mirai/utils/BotConfiguration$GroupMemberListCache;)V public final fun setHeartbeatPeriodMillis (J)V public final fun setHeartbeatTimeoutMillis (J)V public final fun setHighwayUploadCoroutineCount (I)V @@ -5459,6 +5465,24 @@ public final class net/mamoe/mirai/utils/BotConfiguration$Companion { public abstract interface annotation class net/mamoe/mirai/utils/BotConfiguration$ConfigurationDsl : java/lang/annotation/Annotation { } +public final class net/mamoe/mirai/utils/BotConfiguration$FriendListCache { + public fun ()V + public fun (Ljava/io/File;)V + public fun (Ljava/io/File;J)V + public synthetic fun (Ljava/io/File;JILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getCacheFile ()Ljava/io/File; + public final fun getSaveIntervalMillis ()J +} + +public final class net/mamoe/mirai/utils/BotConfiguration$GroupMemberListCache { + public fun ()V + public fun (Ljava/io/File;)V + public fun (Ljava/io/File;J)V + public synthetic fun (Ljava/io/File;JILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getCacheDir ()Ljava/io/File; + public final fun getSaveIntervalMillis ()J +} + public final class net/mamoe/mirai/utils/BotConfiguration$MiraiProtocol : java/lang/Enum { public static final field ANDROID_PAD Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol; public static final field ANDROID_PHONE Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol; From 0a36170411ff95f314b2dc3c99181f00a9919a89 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 13:06:18 +0800 Subject: [PATCH 08/11] Fix docs --- .../src/commonMain/kotlin/utils/BotConfiguration.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index 10a5d1cbf..dffc84cba 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -332,7 +332,7 @@ public open class BotConfiguration { // open for Java */ public val cacheFile: File = File("cache/friendList.json"), /** - * 在有好友列表修改是 + * 在有好友列表修改时自动保存间隔 */ public val saveIntervalMillis: Long = 60_000, ) @@ -365,7 +365,7 @@ public open class BotConfiguration { // open for Java */ public val cacheDir: File = File("cache"), /** - * 在有好友列表修改是 + * 在有成员列表修改时自动保存间隔 */ public val saveIntervalMillis: Long = 60_000, ) From cbf151b24dd2e796634d2ef567f0f3a31b823d52 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 13:09:31 +0800 Subject: [PATCH 09/11] Rearrange BotConfiguration members --- .../kotlin/utils/BotConfiguration.kt | 271 ++++++++++-------- 1 file changed, 145 insertions(+), 126 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index dffc84cba..6cbd25d17 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -57,32 +57,87 @@ public open class BotConfiguration { // open for Java public var workingDir: File = File(".") /** - * 日志记录器 - * - * - 默认打印到标准输出, 通过 [MiraiLogger.create] - * - 忽略所有日志: [noBotLog] - * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` - * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` - * - * @see MiraiLogger + * Json 序列化器, 使用 'kotlinx.serialization' */ - public var botLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Bot ${it.id}") } + @MiraiExperimentalApi + public var json: Json = kotlin.runCatching { + Json { + isLenient = true + ignoreUnknownKeys = true + prettyPrint = true + } + }.getOrElse { Json {} } - /** - * 网络层日志构造器 - * - * - 默认打印到标准输出, 通过 [MiraiLogger.create] - * - 忽略所有日志: [noNetworkLog] - * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` - * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` - * - * @see MiraiLogger - */ - public var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Net ${it.id}") } + /////////////////////////////////////////////////////////////////////////// + // Coroutines + /////////////////////////////////////////////////////////////////////////// /** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */ public var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + /** + * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. + * + * Bot 将会使用一个 [SupervisorJob] 覆盖 [coroutineContext] 当前协程的 [Job], 并使用当前协程的 [Job] 作为父 [Job] + * + * 用例: + * ``` + * coroutineScope { + * val bot = Bot(...) { + * inheritCoroutineContext() + * } + * bot.login() + * } // coroutineScope 会等待 Bot 退出 + * ``` + * + * + * **注意**: `bot.cancel` 时将会让父 [Job] 也被 cancel. + * ``` + * coroutineScope { // this: CoroutineScope + * launch { + * while(isActive) { + * delay(500) + * println("I'm alive") + * } + * } + * + * val bot = Bot(...) { + * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job + * } + * bot.login() + * bot.cancel() // 取消了整个 `coroutineScope`, 因此上文不断打印 `"I'm alive"` 的协程也会被取消. + * } + * ``` + * + * 因此, 此函数尤为适合在 `suspend fun main()` 中使用, 它能阻止主线程退出: + * ``` + * suspend fun main() { + * val bot = Bot() { + * inheritCoroutineContext() + * } + * bot.subscribe { ... } + * + * // 主线程不会退出, 直到 Bot 离线. + * } + * ``` + * + * 简言之, + * - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext]. + * - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext] + * + * @see parentCoroutineContext + */ + @JvmSynthetic + @ConfigurationDsl + public suspend inline fun inheritCoroutineContext() { + parentCoroutineContext = coroutineContext + } + + + /////////////////////////////////////////////////////////////////////////// + // Connection + /////////////////////////////////////////////////////////////////////////// + /** 心跳周期. 过长会导致被服务器断开连接. */ public var heartbeatPeriodMillis: Long = 60.secondsToMillis @@ -125,6 +180,26 @@ public open class BotConfiguration { // open for Java /** 使用协议类型 */ public var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PHONE + public enum class MiraiProtocol { + /** + * Android 手机. 所有功能都支持. + */ + ANDROID_PHONE, + + /** + * Android 平板. + * + * 注意: 不支持戳一戳事件解析 + */ + ANDROID_PAD, + + /** + * Android 手表. + */ + ANDROID_WATCH, + + } + /** * Highway 通道上传图片, 语音, 文件等资源时的协程数量. * @@ -135,25 +210,6 @@ public open class BotConfiguration { // open for Java */ public var highwayUploadCoroutineCount: Int = Runtime.getRuntime().availableProcessors() - /** - * 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息. - * @see fileBasedDeviceInfo 使用指定文件存储设备信息 - * @see randomDeviceInfo 使用随机设备信息 - */ - public var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually. - - /** - * Json 序列化器, 使用 'kotlinx.serialization' - */ - @MiraiExperimentalApi - public var json: Json = kotlin.runCatching { - Json { - isLenient = true - ignoreUnknownKeys = true - prettyPrint = true - } - }.getOrElse { Json {} } - /** * 设置 [autoReconnectOnForceOffline] 为 `true`, 即在被挤下线时自动重连. * @since 2.1 @@ -163,6 +219,17 @@ public open class BotConfiguration { // open for Java autoReconnectOnForceOffline = true } + /////////////////////////////////////////////////////////////////////////// + // Device + /////////////////////////////////////////////////////////////////////////// + + /** + * 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息. + * @see fileBasedDeviceInfo 使用指定文件存储设备信息 + * @see randomDeviceInfo 使用随机设备信息 + */ + public var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually. + /** * 使用随机设备信息. * @@ -198,6 +265,34 @@ public open class BotConfiguration { // open for Java deviceInfo = getFileBasedDeviceInfoSupplier { workingDir.resolve(filepath) } } + /////////////////////////////////////////////////////////////////////////// + // Logging + /////////////////////////////////////////////////////////////////////////// + + /** + * 日志记录器 + * + * - 默认打印到标准输出, 通过 [MiraiLogger.create] + * - 忽略所有日志: [noBotLog] + * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` + * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` + * + * @see MiraiLogger + */ + public var botLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Bot ${it.id}") } + + /** + * 网络层日志构造器 + * + * - 默认打印到标准输出, 通过 [MiraiLogger.create] + * - 忽略所有日志: [noNetworkLog] + * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` + * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` + * + * @see MiraiLogger + */ + public var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Net ${it.id}") } + /** * 重定向 [网络日志][networkLoggerSupplier] 到指定目录. 若目录不存在将会自动创建 ([File.mkdirs]) @@ -265,33 +360,6 @@ public open class BotConfiguration { // open for Java botLoggerSupplier = { DirectoryLogger(identity(it), workingDir.resolve(dir), retain) } } - public enum class MiraiProtocol { - /** - * Android 手机. 所有功能都支持. - */ - ANDROID_PHONE, - - /** - * Android 平板. - * - * 注意: 不支持戳一戳事件解析 - */ - ANDROID_PAD, - - /** - * Android 手表. - */ - ANDROID_WATCH, - - } - - public companion object { - /** 默认的配置实例. 可以进行修改 */ - @JvmStatic - public val Default: BotConfiguration = BotConfiguration() - } - - /** * 不显示网络日志. 不推荐. * @see networkLoggerSupplier 更多日志处理方式 @@ -342,6 +410,7 @@ public open class BotConfiguration { // open for Java * @since 2.4 * @see BotConfiguration.enableFriendListCache */ + @ConfigurationDsl public fun enableFriendListCache() { friendListCache = FriendListCache() } @@ -375,69 +444,14 @@ public open class BotConfiguration { // open for Java * @since 2.4 * @see BotConfiguration.enableGroupMemberListCache */ + @ConfigurationDsl public fun enableGroupMemberListCache() { friendListCache = FriendListCache() } - - /** - * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. - * - * Bot 将会使用一个 [SupervisorJob] 覆盖 [coroutineContext] 当前协程的 [Job], 并使用当前协程的 [Job] 作为父 [Job] - * - * 用例: - * ``` - * coroutineScope { - * val bot = Bot(...) { - * inheritCoroutineContext() - * } - * bot.login() - * } // coroutineScope 会等待 Bot 退出 - * ``` - * - * - * **注意**: `bot.cancel` 时将会让父 [Job] 也被 cancel. - * ``` - * coroutineScope { // this: CoroutineScope - * launch { - * while(isActive) { - * delay(500) - * println("I'm alive") - * } - * } - * - * val bot = Bot(...) { - * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job - * } - * bot.login() - * bot.cancel() // 取消了整个 `coroutineScope`, 因此上文不断打印 `"I'm alive"` 的协程也会被取消. - * } - * ``` - * - * 因此, 此函数尤为适合在 `suspend fun main()` 中使用, 它能阻止主线程退出: - * ``` - * suspend fun main() { - * val bot = Bot() { - * inheritCoroutineContext() - * } - * bot.subscribe { ... } - * - * // 主线程不会退出, 直到 Bot 离线. - * } - * ``` - * - * 简言之, - * - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext]. - * - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext] - * - * @see parentCoroutineContext - */ - @JvmSynthetic - @ConfigurationDsl - public suspend inline fun inheritCoroutineContext() { - parentCoroutineContext = coroutineContext - } - + /////////////////////////////////////////////////////////////////////////// + // Misc + /////////////////////////////////////////////////////////////////////////// public fun copy(): BotConfiguration { return BotConfiguration().also { new -> @@ -455,11 +469,16 @@ public open class BotConfiguration { // open for Java } } - /** 标注一个配置 DSL 函数 */ @Target(AnnotationTarget.FUNCTION) @DslMarker public annotation class ConfigurationDsl + + public companion object { + /** 默认的配置实例. 可以进行修改 */ + @JvmStatic + public val Default: BotConfiguration = BotConfiguration() + } } /** From f27e42d225f8593529796b7ada2012e3460e8a43 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 13:12:40 +0800 Subject: [PATCH 10/11] Fix BotConfiguration.copy --- .../src/commonMain/kotlin/utils/BotConfiguration.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index 6cbd25d17..79346c6bc 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -455,17 +455,24 @@ public open class BotConfiguration { // open for Java public fun copy(): BotConfiguration { return BotConfiguration().also { new -> - new.botLoggerSupplier = botLoggerSupplier - new.networkLoggerSupplier = networkLoggerSupplier - new.deviceInfo = deviceInfo + // To structural order + new.workingDir = workingDir + new.json = json new.parentCoroutineContext = parentCoroutineContext new.heartbeatPeriodMillis = heartbeatPeriodMillis new.heartbeatTimeoutMillis = heartbeatTimeoutMillis new.firstReconnectDelayMillis = firstReconnectDelayMillis new.reconnectPeriodMillis = reconnectPeriodMillis new.reconnectionRetryTimes = reconnectionRetryTimes + new.autoReconnectOnForceOffline = autoReconnectOnForceOffline new.loginSolver = loginSolver new.protocol = protocol + new.highwayUploadCoroutineCount = highwayUploadCoroutineCount + new.deviceInfo = deviceInfo + new.botLoggerSupplier = botLoggerSupplier + new.networkLoggerSupplier = networkLoggerSupplier + new.friendListCache = friendListCache + new.groupMemberListCache = groupMemberListCache } } From 31839b76a32c8398e5e77590eeeeded209d0f6b4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 7 Feb 2021 13:14:41 +0800 Subject: [PATCH 11/11] Enable cache by default, change default cache dir, change enableXXXCache to disableXXXCache in BotConfiguration --- .../api/binary-compatibility-validator.api | 5 ++- .../kotlin/utils/BotConfiguration.kt | 39 ++++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/binary-compatibility-validator/api/binary-compatibility-validator.api b/binary-compatibility-validator/api/binary-compatibility-validator.api index 8f681ffd5..5611dc7b6 100644 --- a/binary-compatibility-validator/api/binary-compatibility-validator.api +++ b/binary-compatibility-validator/api/binary-compatibility-validator.api @@ -5393,8 +5393,9 @@ public class net/mamoe/mirai/utils/BotConfiguration { public fun ()V public final fun autoReconnectOnForceOffline ()V public final fun copy ()Lnet/mamoe/mirai/utils/BotConfiguration; - public final fun enableFriendListCache ()V - public final fun enableGroupMemberListCache ()V + public final fun disableContactCaches ()V + public final fun disableFriendListCache ()V + public final fun disableGroupMemberListCache ()V public final fun fileBasedDeviceInfo ()V public final fun fileBasedDeviceInfo (Ljava/lang/String;)V public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index 79346c6bc..f9eebb97b 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -385,7 +385,7 @@ public open class BotConfiguration { // open for Java /** * 非 `null` 时启用好友列表缓存, 加快初始化速度. 在启用后将会在下载好友列表后保存到文件, 并在修改时自动保存. * @since 2.4 - * @see enableFriendListCache + * @see disableFriendListCache */ public var friendListCache: FriendListCache? = FriendListCache() @@ -397,8 +397,10 @@ public open class BotConfiguration { // open for Java public class FriendListCache @JvmOverloads constructor( /** * 缓存文件位置, 相对于 [workingDir] 的路径. + * + * 注意: 保存的文件仅供内部使用, 将来可能会变化. */ - public val cacheFile: File = File("cache/friendList.json"), + public val cacheFile: File = File("cache/friends.json"), /** * 在有好友列表修改时自动保存间隔 */ @@ -406,20 +408,20 @@ public open class BotConfiguration { // open for Java ) /** - * 启用好友列表缓存. + * 禁用好友列表缓存. * @since 2.4 - * @see BotConfiguration.enableFriendListCache */ @ConfigurationDsl - public fun enableFriendListCache() { - friendListCache = FriendListCache() + public fun disableFriendListCache() { + friendListCache = null } + /** * 非 `null` 时启用群成员列表缓存, 加快初始化速度. 在启用后将会在下载群成员列表后保存到文件, 并在修改时自动保存. * @since 2.4 - * @see enableGroupMemberListCache + * @see disableGroupMemberListCache */ public var groupMemberListCache: GroupMemberListCache? = GroupMemberListCache() @@ -430,9 +432,11 @@ public open class BotConfiguration { // open for Java */ public class GroupMemberListCache @JvmOverloads constructor( /** - * 缓存文件位置, 相对于 [workingDir] 的路径. + * 缓存目录位置, 相对于 [workingDir] 的路径. + * + * 注意: 保存的文件仅供内部使用, 将来可能会变化. */ - public val cacheDir: File = File("cache"), + public val cacheDir: File = File("cache/groups"), /** * 在有成员列表修改时自动保存间隔 */ @@ -440,13 +444,22 @@ public open class BotConfiguration { // open for Java ) /** - * 启用群成员列表缓存. + * 禁用群成员列表缓存. * @since 2.4 - * @see BotConfiguration.enableGroupMemberListCache */ @ConfigurationDsl - public fun enableGroupMemberListCache() { - friendListCache = FriendListCache() + public fun disableGroupMemberListCache() { + groupMemberListCache = null + } + + /** + * 禁用好友列表, 群成员列表, 陌生人列表的缓存. + * @since 2.4 + */ + @ConfigurationDsl + public fun disableContactCaches() { + disableFriendListCache() + disableGroupMemberListCache() } ///////////////////////////////////////////////////////////////////////////