From cae7b1161c462f82e38b319e7e600c7f33d2e513 Mon Sep 17 00:00:00 2001 From: Karlatemp Date: Mon, 3 Oct 2022 12:38:58 +0800 Subject: [PATCH] [mock] Unified contacts data --- mirai-core-mock/src/internal/MockBotImpl.kt | 30 ++++++---- .../src/internal/contact/MockFriendImpl.kt | 46 ++++----------- .../internal/contact/MockNormalMemberImpl.kt | 30 +++------- .../src/internal/contact/MockStrangerImpl.kt | 26 +++------ .../internal/contactbase/ContactDatabase.kt | 33 +++++++++++ .../src/internal/contactbase/ContactInfo.kt | 58 +++++++++++++++++++ 6 files changed, 137 insertions(+), 86 deletions(-) create mode 100644 mirai-core-mock/src/internal/contactbase/ContactDatabase.kt create mode 100644 mirai-core-mock/src/internal/contactbase/ContactInfo.kt diff --git a/mirai-core-mock/src/internal/MockBotImpl.kt b/mirai-core-mock/src/internal/MockBotImpl.kt index d431dfa8f..e665a0327 100644 --- a/mirai-core-mock/src/internal/MockBotImpl.kt +++ b/mirai-core-mock/src/internal/MockBotImpl.kt @@ -23,7 +23,9 @@ import net.mamoe.mirai.contact.friendgroup.FriendGroups import net.mamoe.mirai.event.EventChannel import net.mamoe.mirai.event.GlobalEventChannel import net.mamoe.mirai.event.broadcast -import net.mamoe.mirai.event.events.* +import net.mamoe.mirai.event.events.BotEvent +import net.mamoe.mirai.event.events.BotOnlineEvent +import net.mamoe.mirai.event.events.BotReloginEvent import net.mamoe.mirai.internal.network.component.ComponentStorage import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage import net.mamoe.mirai.internal.network.components.EventDispatcher @@ -37,15 +39,16 @@ import net.mamoe.mirai.mock.database.MessageDatabase import net.mamoe.mirai.mock.internal.components.MockEventDispatcherImpl import net.mamoe.mirai.mock.internal.contact.* import net.mamoe.mirai.mock.internal.contact.friendfroup.MockFriendGroups +import net.mamoe.mirai.mock.internal.contactbase.ContactDatabase import net.mamoe.mirai.mock.internal.serverfs.TmpResourceServerImpl import net.mamoe.mirai.mock.resserver.TmpResourceServer import net.mamoe.mirai.mock.userprofile.UserProfileService import net.mamoe.mirai.mock.utils.NameGenerator -import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.mock.utils.simpleMemberInfo import net.mamoe.mirai.utils.* import java.util.concurrent.CancellationException import java.util.concurrent.atomic.AtomicBoolean +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import net.mamoe.mirai.internal.utils.subLoggerImpl as subLog @@ -58,22 +61,22 @@ internal class MockBotImpl( override val msgDatabase: MessageDatabase, override val userProfileService: UserProfileService, ) : MockBot, Bot, ContactOrBot { + @JvmField + internal val contactDatabase = ContactDatabase(this) + private val botccinfo = contactDatabase.acquireCI(id, nick) + private val loginBefore = AtomicBoolean(false) - override var nickNoEvent: String = nick + override var nickNoEvent: String by botccinfo::nick override var nick: String - get() = nickNoEvent + get() = botccinfo.nick set(value) { - val ov = nickNoEvent - if (value == ov) return - nickNoEvent = value - BotNickChangedEvent(this, ov, value).broadcastBlocking() + botccinfo.changeNick(value) } override var avatarUrl: String get() = asFriend.avatarUrl set(value) { - asFriend.mockApi.avatarUrl = value - BotAvatarChangedEvent(this).broadcastBlocking() + asFriend.changeAvatarUrl(value) } override fun avatarUrl(spec: AvatarSpec): String { @@ -186,4 +189,9 @@ internal class MockBotImpl( override fun toString(): String { return "MockBot($id)" } -} \ No newline at end of file +} + +internal fun MockBot.impl(): MockBotImpl { + contract { returns() implies (this@impl is MockBotImpl) } + return cast() +} diff --git a/mirai-core-mock/src/internal/contact/MockFriendImpl.kt b/mirai-core-mock/src/internal/contact/MockFriendImpl.kt index 2958c018d..643cd9e4e 100644 --- a/mirai-core-mock/src/internal/contact/MockFriendImpl.kt +++ b/mirai-core-mock/src/internal/contact/MockFriendImpl.kt @@ -12,7 +12,6 @@ package net.mamoe.mirai.mock.internal.contact import kotlinx.coroutines.cancel -import kotlinx.coroutines.runBlocking import net.mamoe.mirai.contact.AvatarSpec import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.friendgroup.FriendGroup @@ -28,13 +27,13 @@ import net.mamoe.mirai.mock.MockBot import net.mamoe.mirai.mock.contact.MockFriend import net.mamoe.mirai.mock.internal.contact.friendfroup.MockFriendGroups import net.mamoe.mirai.mock.internal.contact.roaming.MockRoamingMessages +import net.mamoe.mirai.mock.internal.impl import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcFromFriend import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToFriend import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.utils.ExternalResource import net.mamoe.mirai.utils.cast -import net.mamoe.mirai.utils.lateinitMutableProperty import java.util.concurrent.CancellationException import kotlin.coroutines.CoroutineContext @@ -48,33 +47,15 @@ internal class MockFriendImpl( parentCoroutineContext, bot, id ), MockFriend { + private val ccinfo = bot.impl().contactDatabase.acquireCI(id, nick) + override val mockApi: MockFriend.MockApi = object : MockFriend.MockApi { override val contact: MockFriend get() = this@MockFriendImpl - override var nick: String = nick override var remark: String = remark - override var avatarUrl: String - get() = this@MockFriendImpl._avatarUrl - set(value) { - this@MockFriendImpl._avatarUrl = value - bot.groups.forEach { g -> - val mems = if (this@MockFriendImpl.id == bot.id) { - sequenceOf(g.botAsMember) - } else g.members.asSequence().filter { - it.id == this@MockFriendImpl.id - } - mems.forEach { m -> - m.cast().avatarUrl = value - } - } - if (this@MockFriendImpl.id == bot.id) { - sequenceOf(bot.asStranger) - } else { - bot.strangers.asSequence().filter { s -> - s.id == this@MockFriendImpl.id - } - }.forEach { it.cast().avatarUrl = value } - } + + override var nick: String by ccinfo::nick + override var avatarUrl: String by ccinfo::avatarUrl override var friendGroupId: Int = 0 } @@ -82,15 +63,13 @@ internal class MockFriendImpl( override val friendGroup: FriendGroup get() = bot.friendGroups.cast().findOrDefault(mockApi.friendGroupId) - private var _avatarUrl: String by lateinitMutableProperty { runBlocking { MockImage.random(bot).getUrl(bot) } } - override val avatarUrl: String get() = _avatarUrl + override val avatarUrl: String get() = ccinfo.avatarUrl internal fun initAvatarUrl(v: String) { - _avatarUrl = v + ccinfo.avatarUrl = v } override fun changeAvatarUrl(newAvatar: String) { - mockApi.avatarUrl = newAvatar - FriendAvatarChangedEvent(this).broadcastBlocking() + ccinfo.changeAvatarUrl(newAvatar) } override fun avatarUrl(spec: AvatarSpec): String { @@ -98,12 +77,9 @@ internal class MockFriendImpl( } override var nick: String - get() = mockApi.nick + get() = ccinfo.nick set(value) { - val ov = mockApi.nick - if (ov == value) return - mockApi.nick = value - FriendNickChangedEvent(this, ov, value).broadcastBlocking() + ccinfo.changeNick(value) } override var remark: String diff --git a/mirai-core-mock/src/internal/contact/MockNormalMemberImpl.kt b/mirai-core-mock/src/internal/contact/MockNormalMemberImpl.kt index 665db270e..7d505df5a 100644 --- a/mirai-core-mock/src/internal/contact/MockNormalMemberImpl.kt +++ b/mirai-core-mock/src/internal/contact/MockNormalMemberImpl.kt @@ -10,7 +10,6 @@ package net.mamoe.mirai.mock.internal.contact import kotlinx.coroutines.cancel -import kotlinx.coroutines.runBlocking import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* @@ -24,13 +23,13 @@ import net.mamoe.mirai.mock.contact.MockGroup import net.mamoe.mirai.mock.contact.MockNormalMember import net.mamoe.mirai.mock.contact.active.MockMemberActive import net.mamoe.mirai.mock.internal.contact.active.MockMemberActiveImpl +import net.mamoe.mirai.mock.internal.impl import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcFromGroup import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToTemp import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.currentTimeSeconds -import net.mamoe.mirai.utils.lateinitMutableProperty import kotlin.coroutines.CoroutineContext import kotlin.coroutines.cancellation.CancellationException import kotlin.math.max @@ -52,18 +51,19 @@ internal class MockNormalMemberImpl( parentCoroutineContext, bot, id ), MockNormalMember { - override var avatarUrl: String by lateinitMutableProperty { - bot.getFriend(id)?.let { return@lateinitMutableProperty it.avatarUrl } - runBlocking { MockImage.random(bot).getUrl(bot) } + private val ccinfo = bot.impl().contactDatabase.let { + if (nick.isEmpty()) it.acquireCI(id) + else it.acquireCI(id, nick) } + override val avatarUrl: String get() = ccinfo.avatarUrl + override fun avatarUrl(spec: AvatarSpec): String { return avatarUrl } override fun changeAvatarUrl(newAvatar: String) { - bot.getFriend(id)?.let { return it.changeAvatarUrl(newAvatar) } - this.avatarUrl = newAvatar + ccinfo.changeAvatarUrl(newAvatar) } private inline fun crossFriendAccess( @@ -80,11 +80,7 @@ internal class MockNormalMemberImpl( override var joinTimestamp: Int = joinTimestamp override var muteTimeEndTimestamp: Long = currentTimeSeconds() + muteTimeRemaining - override var nick: String = nick - get() = crossFriendAccess(ifExists = { it.nick }, ifNotExists = { field }) - set(value) { - crossFriendAccess(ifExists = { it.mockApi.nick = value }, ifNotExists = { field = value }) - } + override var nick: String by ccinfo::nick override var remark: String = remark get() = crossFriendAccess(ifExists = { it.remark }, ifNotExists = { field }) @@ -95,15 +91,7 @@ internal class MockNormalMemberImpl( override var permission: MemberPermission = permission override var nameCard: String = nameCard override var specialTitle: String = specialTitle - override var avatarUrl: String - get() = this@MockNormalMemberImpl.avatarUrl - set(value) { - this@MockNormalMemberImpl.avatarUrl = value - - bot.getFriend(this@MockNormalMemberImpl.id)?.let { f -> - f.mockApi.avatarUrl = value - } - } + override var avatarUrl: String by ccinfo::avatarUrl } override val permission: MemberPermission diff --git a/mirai-core-mock/src/internal/contact/MockStrangerImpl.kt b/mirai-core-mock/src/internal/contact/MockStrangerImpl.kt index ebe06d78c..77e4d496c 100644 --- a/mirai-core-mock/src/internal/contact/MockStrangerImpl.kt +++ b/mirai-core-mock/src/internal/contact/MockStrangerImpl.kt @@ -10,7 +10,6 @@ package net.mamoe.mirai.mock.internal.contact import kotlinx.coroutines.cancel -import kotlinx.coroutines.runBlocking import net.mamoe.mirai.contact.AvatarSpec import net.mamoe.mirai.contact.Stranger import net.mamoe.mirai.event.broadcast @@ -21,11 +20,11 @@ import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.OnlineMessageSource import net.mamoe.mirai.mock.MockBot import net.mamoe.mirai.mock.contact.MockStranger +import net.mamoe.mirai.mock.internal.impl import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcFromStranger import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToStranger import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.utils.cast -import net.mamoe.mirai.utils.lateinitMutableProperty import java.util.concurrent.CancellationException import kotlin.coroutines.CoroutineContext @@ -37,34 +36,23 @@ internal class MockStrangerImpl( remark: String, nick: String ) : AbstractMockContact(parentCoroutineContext, bot, id), MockStranger { + private val ccinfo = bot.impl().contactDatabase.acquireCI(id, nick) override val mockApi: MockStranger.MockApi = object : MockStranger.MockApi { override val contact: MockStranger get() = this@MockStrangerImpl - override var nick: String = nick + override var nick: String by ccinfo::nick override var remark: String = remark - override var avatarUrl: String - get() = this@MockStrangerImpl.avatarUrl - set(value) { - this@MockStrangerImpl.avatarUrl = value + override var avatarUrl: String by ccinfo::avatarUrl + } - bot.getFriend(this@MockStrangerImpl.id)?.let { f -> - f.mockApi.avatarUrl = value - return - } - } - } - override var avatarUrl: String by lateinitMutableProperty { - bot.getFriend(id)?.let { return@lateinitMutableProperty it.avatarUrl } - runBlocking { MockImage.random(bot).getUrl(bot) } - } + override val avatarUrl: String get() = ccinfo.avatarUrl override fun avatarUrl(spec: AvatarSpec): String { return avatarUrl } override fun changeAvatarUrl(newAvatar: String) { - this.avatarUrl = newAvatar - bot.getFriend(id)?.let { return it.changeAvatarUrl(newAvatar) } + ccinfo.changeAvatarUrl(newAvatar) } override val nick: String diff --git a/mirai-core-mock/src/internal/contactbase/ContactDatabase.kt b/mirai-core-mock/src/internal/contactbase/ContactDatabase.kt new file mode 100644 index 000000000..5ba84e40f --- /dev/null +++ b/mirai-core-mock/src/internal/contactbase/ContactDatabase.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.mock.internal.contactbase + +import net.mamoe.mirai.mock.internal.MockBotImpl +import net.mamoe.mirai.utils.ConcurrentHashMap + +internal class ContactDatabase( + private val bot: MockBotImpl, +) { + val contacts = ConcurrentHashMap() + + fun acquireCI(id: Long): ContactInfo { + return contacts.computeIfAbsent(id) { + ContactInfo(bot, id, bot.nameGenerator.nextFriendName()) + } + } + + fun acquireCI(id: Long, name: String): ContactInfo { + return contacts.computeIfAbsent(id) { + ContactInfo(bot, id, name) + }.also { rsp -> + if (rsp.nick != name) rsp.changeNick(name) + } + } +} diff --git a/mirai-core-mock/src/internal/contactbase/ContactInfo.kt b/mirai-core-mock/src/internal/contactbase/ContactInfo.kt new file mode 100644 index 000000000..385ca8450 --- /dev/null +++ b/mirai-core-mock/src/internal/contactbase/ContactInfo.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2019-2022 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/dev/LICENSE + */ + +package net.mamoe.mirai.mock.internal.contactbase + +import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.event.events.BotAvatarChangedEvent +import net.mamoe.mirai.event.events.BotNickChangedEvent +import net.mamoe.mirai.event.events.FriendAvatarChangedEvent +import net.mamoe.mirai.event.events.FriendNickChangedEvent +import net.mamoe.mirai.mock.internal.MockBotImpl +import net.mamoe.mirai.mock.internal.contact.MockImage +import net.mamoe.mirai.mock.utils.broadcastBlocking +import net.mamoe.mirai.utils.lateinitMutableProperty + +internal class ContactInfo( + private val declaredBot: MockBotImpl, + @JvmField val id: Long, + @JvmField var nick: String, +) { + var avatarUrl: String by lateinitMutableProperty { + runBlocking { MockImage.random(declaredBot).getUrl(declaredBot) } + } + + fun changeAvatarUrl(newAvatar: String) { + avatarUrl = newAvatar + if (declaredBot.id == id) { + BotAvatarChangedEvent(declaredBot).broadcastBlocking() + return + } + declaredBot.getFriend(id)?.let { + FriendAvatarChangedEvent(it).broadcastBlocking() + } + } + + fun changeNick(newNick: String) { + if (id == declaredBot.id) { + val o = nick + nick = newNick + BotNickChangedEvent(declaredBot, o, newNick).broadcastBlocking() + return + } + val friend = declaredBot.getFriend(id) + if (friend == null) { + nick = newNick + return + } + val o = nick + nick = newNick + FriendNickChangedEvent(friend, o, newNick).broadcastBlocking() + } +}