Support group list cache, close #987

This commit is contained in:
Him188 2021-02-07 12:49:12 +08:00
parent 90d4030fe6
commit 7fac83702a
9 changed files with 243 additions and 72 deletions

View File

@ -9,7 +9,9 @@
@file:JvmMultifileClass @file:JvmMultifileClass
@file:JvmName("BotEventsKt") @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 package net.mamoe.mirai.event.events
@ -28,8 +30,8 @@ import java.util.concurrent.atomic.AtomicBoolean
/** /**
* 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群. * 机器人被踢出群或在其他客户端主动退出一个群. 在事件广播前 [Bot.groups] 就已删除这个群.
*/ */
public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent() { public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent {
public abstract val group: Group public abstract override val group: Group
/** /**
* 机器人主动退出一个群. * 机器人主动退出一个群.
@ -64,7 +66,7 @@ public data class BotGroupPermissionChangeEvent @MiraiInternalApi constructor(
public override val group: Group, public override val group: Group,
public val origin: MemberPermission, public val origin: MemberPermission,
public val new: MemberPermission public val new: MemberPermission
) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent() ) : BotPassiveEvent, GroupEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
* Bot 被禁言 * Bot 被禁言
@ -75,7 +77,7 @@ public data class BotMuteEvent @MiraiInternalApi constructor(
* 操作人. * 操作人.
*/ */
public val operator: NormalMember public val operator: NormalMember
) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent() { ) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent(), GroupMemberInfoChangeEvent {
public override val group: Group public override val group: Group
get() = operator.group get() = operator.group
} }
@ -88,7 +90,7 @@ public data class BotUnmuteEvent @MiraiInternalApi constructor(
* 操作人. * 操作人.
*/ */
public val operator: NormalMember public val operator: NormalMember
) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent() { ) : GroupEvent, Packet, BotPassiveEvent, AbstractEvent(), GroupMemberInfoChangeEvent {
public override val group: Group public override val group: Group
get() = operator.group get() = operator.group
} }
@ -96,7 +98,7 @@ public data class BotUnmuteEvent @MiraiInternalApi constructor(
/** /**
* Bot 成功加入了一个新群 * Bot 成功加入了一个新群
*/ */
public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, AbstractEvent() { public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent {
public abstract override val group: Group public abstract override val group: Group
/** /**
@ -164,7 +166,7 @@ public data class GroupNameChangeEvent @MiraiInternalApi constructor(
* 操作人. null 时则是机器人操作 * 操作人. null 时则是机器人操作
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent() ) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
* 入群公告改变. 此事件广播前修改就已经完成. * 入群公告改变. 此事件广播前修改就已经完成.
@ -177,7 +179,7 @@ public data class GroupEntranceAnnouncementChangeEvent @MiraiInternalApi constru
* 操作人. null 时则是机器人操作 * 操作人. null 时则是机器人操作
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent() ) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
@ -191,7 +193,7 @@ public data class GroupMuteAllEvent @MiraiInternalApi constructor(
* 操作人. null 时则是机器人操作 * 操作人. null 时则是机器人操作
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent() ) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
@ -205,7 +207,7 @@ public data class GroupAllowAnonymousChatEvent @MiraiInternalApi constructor(
* 操作人. null 时则是机器人操作 * 操作人. null 时则是机器人操作
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent() ) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
@ -216,7 +218,7 @@ public data class GroupAllowConfessTalkEvent @MiraiInternalApi constructor(
public override val new: Boolean, public override val new: Boolean,
public override val group: Group, public override val group: Group,
public val isByBot: Boolean // 无法获取操作人 public val isByBot: Boolean // 无法获取操作人
) : GroupSettingChangeEvent<Boolean>, Packet, AbstractEvent() ) : GroupSettingChangeEvent<Boolean>, Packet, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
* "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成. * "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成.
@ -229,7 +231,7 @@ public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor(
* 操作人. null 时则是机器人操作 * 操作人. null 时则是机器人操作
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent() ) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
// endregion // endregion
@ -245,7 +247,7 @@ public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor(
public sealed class MemberJoinEvent( public sealed class MemberJoinEvent(
public override val member: NormalMember public override val member: NormalMember
) : GroupMemberEvent, BotPassiveEvent, Packet, ) : GroupMemberEvent, BotPassiveEvent, Packet,
AbstractEvent() { AbstractEvent(), GroupMemberInfoChangeEvent {
/** /**
* 被邀请加入群 * 被邀请加入群
*/ */
@ -282,7 +284,7 @@ public sealed class MemberJoinEvent(
/** /**
* 成员已经离开群的事件. 在事件广播前成员就已经从 [Group.members] 中删除 * 成员已经离开群的事件. 在事件广播前成员就已经从 [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 * 邀请入群的账号的 id
*/ */
public val invitorId: Long, public val invitorId: Long,
public val groupId: Long, public override val groupId: Long,
public val groupName: String, public val groupName: String,
/** /**
* 邀请人昵称 * 邀请人昵称
*/ */
public val invitorNick: String public val invitorNick: String
) : BotEvent, Packet, AbstractEvent() { ) : BotEvent, Packet, AbstractEvent(), BaseGroupMemberInfoChangeEvent {
/** /**
* 邀请人. 若在事件发生后邀请人已经被删除好友, [invitor] `null`. * 邀请人. 若在事件发生后邀请人已经被删除好友, [invitor] `null`.
*/ */
@ -360,7 +362,7 @@ public data class MemberJoinRequestEvent @MiraiInternalApi constructor(
* 申请入群的账号的 id * 申请入群的账号的 id
*/ */
val fromId: Long, val fromId: Long,
val groupId: Long, override val groupId: Long,
val groupName: String, val groupName: String,
/** /**
* 申请人昵称 * 申请人昵称
@ -370,7 +372,7 @@ public data class MemberJoinRequestEvent @MiraiInternalApi constructor(
* 邀请人 id如果是邀请入群 * 邀请人 id如果是邀请入群
*/ */
val invitorId: Long? = null val invitorId: Long? = null
) : BotEvent, Packet, AbstractEvent() { ) : BotEvent, Packet, AbstractEvent(), BaseGroupMemberInfoChangeEvent {
/** /**
* 相关群. 若在事件发生后机器人退出这个群, [group] `null`. * 相关群. 若在事件发生后机器人退出这个群, [group] `null`.
*/ */
@ -471,7 +473,7 @@ public data class MemberCardChangeEvent @MiraiInternalApi constructor(
public val new: String, public val new: String,
public override val member: NormalMember public override val member: NormalMember
) : GroupMemberEvent, Packet, AbstractEvent() ) : GroupMemberEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent
/** /**
* 成员群头衔改动. 一定为群主操作 * 成员群头衔改动. 一定为群主操作
@ -495,7 +497,7 @@ public data class MemberSpecialTitleChangeEvent @MiraiInternalApi constructor(
* null 时则是机器人操作. * null 时则是机器人操作.
*/ */
public override val operator: NormalMember? public override val operator: NormalMember?
) : GroupMemberEvent, GroupOperableEvent, AbstractEvent() ) : GroupMemberEvent, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
// endregion // endregion
@ -509,7 +511,7 @@ public data class MemberPermissionChangeEvent @MiraiInternalApi constructor(
public override val member: NormalMember, public override val member: NormalMember,
public val origin: MemberPermission, public val origin: MemberPermission,
public val new: MemberPermission public val new: MemberPermission
) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent() ) : GroupMemberEvent, BotPassiveEvent, Packet, AbstractEvent(), GroupMemberInfoChangeEvent
// endregion // endregion
@ -528,7 +530,7 @@ public data class MemberMuteEvent @MiraiInternalApi constructor(
* 操作人. null 则为机器人操作 * 操作人. null 则为机器人操作
*/ */
public override val operator: Member? 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 则为机器人操作 * 操作人. null 则为机器人操作
*/ */
public override val operator: Member? public override val operator: Member?
) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent() ) : GroupMemberEvent, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
// endregion // endregion

View File

@ -16,6 +16,7 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.Event
import net.mamoe.mirai.internal.network.Packet import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.utils.MiraiInternalApi
/** /**
* 有关一个 [Bot] 的事件 * 有关一个 [Bot] 的事件
@ -110,6 +111,19 @@ public interface GroupMemberEvent : GroupEvent, UserEvent {
override val user: Member get() = member 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 interface OtherClientEvent : BotEvent, Packet {
public val client: OtherClient public val client: OtherClient
override val bot: Bot get() = client.bot override val bot: Bot get() = client.bot

View File

@ -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]. * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext].
* *

View File

@ -20,6 +20,7 @@ import kotlinx.coroutines.withContext
import kotlinx.io.core.discardExact import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes import kotlinx.io.core.readBytes
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.* import net.mamoe.mirai.*
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.* import net.mamoe.mirai.data.*

View File

@ -78,19 +78,24 @@ internal class QQAndroidBot constructor(
override val friends: ContactList<Friend> = ContactList() override val friends: ContactList<Friend> = ContactList()
val friendListCache: FriendListCache? by lazy { val friendListCache: FriendListCache? by lazy {
configuration.friendListCache?.cacheFile?.run { configuration.friendListCache?.cacheFile?.let { cacheFile ->
val ret = loadAs(FriendListCache.serializer(), JsonForCache) ?: FriendListCache() val ret = configuration.workingDir.resolve(cacheFile).loadAs(FriendListCache.serializer(), JsonForCache) ?: FriendListCache()
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
bot.eventChannel.parentScope(this@QQAndroidBot) bot.eventChannel.parentScope(this@QQAndroidBot)
.subscribeAlways<net.mamoe.mirai.event.events.FriendInfoChangeEvent> { .subscribeAlways<net.mamoe.mirai.event.events.FriendInfoChangeEvent> {
friendListSaver?.notice() friendListSaver?.notice()
} }
ret ret
} }
} }
val groupMemberListCaches: GroupMemberListCaches? by lazy {
if (configuration.groupMemberListCache!= null) {
GroupMemberListCaches(this)
} else null
}
private val friendListSaver by lazy { private val friendListSaver by lazy {
configuration.friendListCache?.let { friendListCache: BotConfiguration.FriendListCache -> configuration.friendListCache?.let { friendListCache: BotConfiguration.FriendListCache ->
@ -99,11 +104,10 @@ internal class QQAndroidBot constructor(
} }
} }
} }
fun saveFriendCache() { fun saveFriendCache() {
val friendListCache = friendListCache val friendListCache = friendListCache
if (friendListCache != null) { if (friendListCache != null) {
configuration.friendListCache?.cacheFile?.run { configuration.friendListCache?.cacheFile?.let { configuration.workingDir.resolve(it) }?.run {
createFileIfNotExists() createFileIfNotExists()
writeText(JsonForCache.encodeToString(FriendListCache.serializer(), friendListCache)) writeText(JsonForCache.encodeToString(FriendListCache.serializer(), friendListCache))
bot.network.logger.info { "Saved ${friendListCache.list.size} friends to local cache." } bot.network.logger.info { "Saved ${friendListCache.list.size} friends to local cache." }

View File

@ -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<FriendInfoImpl> = emptyList(),
)
@Serializable
internal data class GroupMemberListCache(
var troopMemberNumSeq: Long,
var list: List<MemberInfoImpl> = 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<net.mamoe.mirai.event.events.BaseGroupMemberInfoChangeEvent> {
groupListSaver.notice()
}
}
private val changedGroups: MutableCollection<Long> = 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<Long, GroupMemberListCache> {
val ret = HashMap<Long, GroupMemberListCache>()
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<Long, GroupMemberListCache> = ConcurrentHashMap()
fun retainAll(list: Collection<Long>) {
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())
}
}
}

View File

@ -18,11 +18,13 @@ import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.data.FriendInfo
import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.FriendImpl import net.mamoe.mirai.internal.contact.FriendImpl
import net.mamoe.mirai.internal.contact.GroupImpl import net.mamoe.mirai.internal.contact.GroupImpl
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
import net.mamoe.mirai.internal.contact.info.GroupInfoImpl 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.info.StrangerInfoImpl
import net.mamoe.mirai.internal.contact.toMiraiFriendInfo 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.StTroopNum
@ -141,19 +143,38 @@ internal class ContactUpdaterImpl(
private fun addFriendToBot(it: FriendInfo) = private fun addFriendToBot(it: FriendInfo) =
bot.friends.delegate.add(FriendImpl(bot, bot.coroutineContext, it)) 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<MemberInfo> {
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( bot.groups.delegate.add(
GroupImpl( GroupImpl(
bot = bot, bot = bot,
coroutineContext = bot.coroutineContext, coroutineContext = bot.coroutineContext,
id = stTroopNum.groupCode, id = groupCode,
groupInfo = GroupInfoImpl(stTroopNum), groupInfo = GroupInfoImpl(stTroopNum),
members = Mirai.getRawGroupMemberList( members = members
bot,
stTroopNum.groupUin,
stTroopNum.groupCode,
stTroopNum.dwGroupOwnerUin
)
) )
) )
} }
@ -184,9 +205,7 @@ internal class ContactUpdaterImpl(
if (initGroupOk) { if (initGroupOk) {
return return
} }
logger.info { "Start syncing group config..." }
TroopManagement.GetTroopConfig(bot.client).sendAndExpect<TroopManagement.GetTroopConfig.Response>() TroopManagement.GetTroopConfig(bot.client).sendAndExpect<TroopManagement.GetTroopConfig.Response>()
logger.info { "Successfully synced group config." }
logger.info { "Start loading group list..." } logger.info { "Start loading group list..." }
val troopListData = FriendList.GetTroopListSimplify(bot.client) val troopListData = FriendList.GetTroopListSimplify(bot.client)
@ -203,7 +222,9 @@ internal class ContactUpdaterImpl(
} }
} }
} }
logger.info { "Successfully loaded group list: ${troopListData.groups.size} in total." } logger.info { "Successfully loaded group list: ${troopListData.groups.size} in total." }
bot.groupMemberListCaches?.saveGroupCaches()
initGroupOk = true initGroupOk = true
} }

View File

@ -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<FriendInfoImpl> = emptyList(),
)

View File

@ -30,7 +30,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
internal class StrangerList { internal class StrangerList {
object GetStrangerList : OutgoingPacketFactory<GetStrangerList.Response>("OidbSvc.0x5d2_0") { object GetStrangerList : OutgoingPacketFactory<GetStrangerList.Response>("OidbSvc.0x5d2_0") {
class Response(val result: Int, val strangerList: List<Oidb0x5d2.FriendEntry>) : Packet { class Response(val result: Int, val strangerList: List<Oidb0x5d2.FriendEntry>, val origin: Oidb0x5d2.RspGetList?) : Packet {
override fun toString(): String { override fun toString(): String {
return "StrangerList.GetStrangerList.Response(result=$result)" return "StrangerList.GetStrangerList.Response(result=$result)"
} }
@ -61,10 +61,10 @@ internal class StrangerList {
if (pkg.result == 0) { if (pkg.result == 0) {
pkg.bodybuffer.loadAs(Oidb0x5d2.RspBody.serializer()).rspGetList!!.let { pkg.bodybuffer.loadAs(Oidb0x5d2.RspBody.serializer()).rspGetList!!.let {
bot.client.strangerSeq = it.seq 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)
} }
} }