mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-10 18:35:06 +08:00
Support group list cache, close #987
This commit is contained in:
parent
90d4030fe6
commit
7fac83702a
@ -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<String>, Packet, GroupOperableEvent, AbstractEvent()
|
||||
) : GroupSettingChangeEvent<String>, Packet, GroupOperableEvent, AbstractEvent(), GroupMemberInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 入群公告改变. 此事件广播前修改就已经完成.
|
||||
@ -177,7 +179,7 @@ public data class GroupEntranceAnnouncementChangeEvent @MiraiInternalApi constru
|
||||
* 操作人. 为 null 时则是机器人操作
|
||||
*/
|
||||
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 时则是机器人操作
|
||||
*/
|
||||
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 时则是机器人操作
|
||||
*/
|
||||
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 group: Group,
|
||||
public val isByBot: Boolean // 无法获取操作人
|
||||
) : GroupSettingChangeEvent<Boolean>, Packet, AbstractEvent()
|
||||
) : GroupSettingChangeEvent<Boolean>, Packet, AbstractEvent(), GroupMemberInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 群 "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成.
|
||||
@ -229,7 +231,7 @@ public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor(
|
||||
* 操作人. 为 null 时则是机器人操作
|
||||
*/
|
||||
public override val operator: NormalMember?
|
||||
) : GroupSettingChangeEvent<Boolean>, Packet, GroupOperableEvent, AbstractEvent()
|
||||
) : GroupSettingChangeEvent<Boolean>, 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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].
|
||||
*
|
||||
|
@ -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.*
|
||||
|
@ -78,19 +78,24 @@ internal class QQAndroidBot constructor(
|
||||
override val friends: ContactList<Friend> = 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<net.mamoe.mirai.event.events.FriendInfoChangeEvent> {
|
||||
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." }
|
||||
|
126
mirai-core/src/commonMain/kotlin/network/ContactListCache.kt
Normal file
126
mirai-core/src/commonMain/kotlin/network/ContactListCache.kt
Normal 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())
|
||||
}
|
||||
}
|
||||
}
|
@ -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<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(
|
||||
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<TroopManagement.GetTroopConfig.Response>()
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
)
|
@ -30,7 +30,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
internal class StrangerList {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user