[mock] Unified contacts data

This commit is contained in:
Karlatemp 2022-10-03 12:38:58 +08:00
parent 495542d2a2
commit cae7b1161c
No known key found for this signature in database
GPG Key ID: BA173CA2B9956C59
6 changed files with 137 additions and 86 deletions

View File

@ -23,7 +23,9 @@ import net.mamoe.mirai.contact.friendgroup.FriendGroups
import net.mamoe.mirai.event.EventChannel import net.mamoe.mirai.event.EventChannel
import net.mamoe.mirai.event.GlobalEventChannel import net.mamoe.mirai.event.GlobalEventChannel
import net.mamoe.mirai.event.broadcast 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.ComponentStorage
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
import net.mamoe.mirai.internal.network.components.EventDispatcher 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.components.MockEventDispatcherImpl
import net.mamoe.mirai.mock.internal.contact.* import net.mamoe.mirai.mock.internal.contact.*
import net.mamoe.mirai.mock.internal.contact.friendfroup.MockFriendGroups 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.internal.serverfs.TmpResourceServerImpl
import net.mamoe.mirai.mock.resserver.TmpResourceServer import net.mamoe.mirai.mock.resserver.TmpResourceServer
import net.mamoe.mirai.mock.userprofile.UserProfileService import net.mamoe.mirai.mock.userprofile.UserProfileService
import net.mamoe.mirai.mock.utils.NameGenerator 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.mock.utils.simpleMemberInfo
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import net.mamoe.mirai.internal.utils.subLoggerImpl as subLog import net.mamoe.mirai.internal.utils.subLoggerImpl as subLog
@ -58,22 +61,22 @@ internal class MockBotImpl(
override val msgDatabase: MessageDatabase, override val msgDatabase: MessageDatabase,
override val userProfileService: UserProfileService, override val userProfileService: UserProfileService,
) : MockBot, Bot, ContactOrBot { ) : MockBot, Bot, ContactOrBot {
@JvmField
internal val contactDatabase = ContactDatabase(this)
private val botccinfo = contactDatabase.acquireCI(id, nick)
private val loginBefore = AtomicBoolean(false) private val loginBefore = AtomicBoolean(false)
override var nickNoEvent: String = nick override var nickNoEvent: String by botccinfo::nick
override var nick: String override var nick: String
get() = nickNoEvent get() = botccinfo.nick
set(value) { set(value) {
val ov = nickNoEvent botccinfo.changeNick(value)
if (value == ov) return
nickNoEvent = value
BotNickChangedEvent(this, ov, value).broadcastBlocking()
} }
override var avatarUrl: String override var avatarUrl: String
get() = asFriend.avatarUrl get() = asFriend.avatarUrl
set(value) { set(value) {
asFriend.mockApi.avatarUrl = value asFriend.changeAvatarUrl(value)
BotAvatarChangedEvent(this).broadcastBlocking()
} }
override fun avatarUrl(spec: AvatarSpec): String { override fun avatarUrl(spec: AvatarSpec): String {
@ -187,3 +190,8 @@ internal class MockBotImpl(
return "MockBot($id)" return "MockBot($id)"
} }
} }
internal fun MockBot.impl(): MockBotImpl {
contract { returns() implies (this@impl is MockBotImpl) }
return cast()
}

View File

@ -12,7 +12,6 @@
package net.mamoe.mirai.mock.internal.contact package net.mamoe.mirai.mock.internal.contact
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.contact.AvatarSpec import net.mamoe.mirai.contact.AvatarSpec
import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.friendgroup.FriendGroup 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.contact.MockFriend
import net.mamoe.mirai.mock.internal.contact.friendfroup.MockFriendGroups import net.mamoe.mirai.mock.internal.contact.friendfroup.MockFriendGroups
import net.mamoe.mirai.mock.internal.contact.roaming.MockRoamingMessages 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.OnlineMsgSrcFromFriend
import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToFriend import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToFriend
import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc
import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.mock.utils.broadcastBlocking
import net.mamoe.mirai.utils.ExternalResource import net.mamoe.mirai.utils.ExternalResource
import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.lateinitMutableProperty
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -48,33 +47,15 @@ internal class MockFriendImpl(
parentCoroutineContext, parentCoroutineContext,
bot, id bot, id
), MockFriend { ), MockFriend {
private val ccinfo = bot.impl().contactDatabase.acquireCI(id, nick)
override val mockApi: MockFriend.MockApi = object : MockFriend.MockApi { override val mockApi: MockFriend.MockApi = object : MockFriend.MockApi {
override val contact: MockFriend get() = this@MockFriendImpl override val contact: MockFriend get() = this@MockFriendImpl
override var nick: String = nick
override var remark: String = remark override var remark: String = remark
override var avatarUrl: String
get() = this@MockFriendImpl._avatarUrl override var nick: String by ccinfo::nick
set(value) { override var avatarUrl: String by ccinfo::avatarUrl
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<MockNormalMemberImpl>().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<MockStrangerImpl>().avatarUrl = value }
}
override var friendGroupId: Int = 0 override var friendGroupId: Int = 0
} }
@ -82,15 +63,13 @@ internal class MockFriendImpl(
override val friendGroup: FriendGroup override val friendGroup: FriendGroup
get() = bot.friendGroups.cast<MockFriendGroups>().findOrDefault(mockApi.friendGroupId) get() = bot.friendGroups.cast<MockFriendGroups>().findOrDefault(mockApi.friendGroupId)
private var _avatarUrl: String by lateinitMutableProperty { runBlocking { MockImage.random(bot).getUrl(bot) } } override val avatarUrl: String get() = ccinfo.avatarUrl
override val avatarUrl: String get() = _avatarUrl
internal fun initAvatarUrl(v: String) { internal fun initAvatarUrl(v: String) {
_avatarUrl = v ccinfo.avatarUrl = v
} }
override fun changeAvatarUrl(newAvatar: String) { override fun changeAvatarUrl(newAvatar: String) {
mockApi.avatarUrl = newAvatar ccinfo.changeAvatarUrl(newAvatar)
FriendAvatarChangedEvent(this).broadcastBlocking()
} }
override fun avatarUrl(spec: AvatarSpec): String { override fun avatarUrl(spec: AvatarSpec): String {
@ -98,12 +77,9 @@ internal class MockFriendImpl(
} }
override var nick: String override var nick: String
get() = mockApi.nick get() = ccinfo.nick
set(value) { set(value) {
val ov = mockApi.nick ccinfo.changeNick(value)
if (ov == value) return
mockApi.nick = value
FriendNickChangedEvent(this, ov, value).broadcastBlocking()
} }
override var remark: String override var remark: String

View File

@ -10,7 +10,6 @@
package net.mamoe.mirai.mock.internal.contact package net.mamoe.mirai.mock.internal.contact
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.* 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.MockNormalMember
import net.mamoe.mirai.mock.contact.active.MockMemberActive import net.mamoe.mirai.mock.contact.active.MockMemberActive
import net.mamoe.mirai.mock.internal.contact.active.MockMemberActiveImpl 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.OnlineMsgSrcFromGroup
import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToTemp import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToTemp
import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc
import net.mamoe.mirai.mock.utils.broadcastBlocking import net.mamoe.mirai.mock.utils.broadcastBlocking
import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.lateinitMutableProperty
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.cancellation.CancellationException import kotlin.coroutines.cancellation.CancellationException
import kotlin.math.max import kotlin.math.max
@ -52,18 +51,19 @@ internal class MockNormalMemberImpl(
parentCoroutineContext, bot, parentCoroutineContext, bot,
id id
), MockNormalMember { ), MockNormalMember {
override var avatarUrl: String by lateinitMutableProperty { private val ccinfo = bot.impl().contactDatabase.let {
bot.getFriend(id)?.let { return@lateinitMutableProperty it.avatarUrl } if (nick.isEmpty()) it.acquireCI(id)
runBlocking { MockImage.random(bot).getUrl(bot) } else it.acquireCI(id, nick)
} }
override val avatarUrl: String get() = ccinfo.avatarUrl
override fun avatarUrl(spec: AvatarSpec): String { override fun avatarUrl(spec: AvatarSpec): String {
return avatarUrl return avatarUrl
} }
override fun changeAvatarUrl(newAvatar: String) { override fun changeAvatarUrl(newAvatar: String) {
bot.getFriend(id)?.let { return it.changeAvatarUrl(newAvatar) } ccinfo.changeAvatarUrl(newAvatar)
this.avatarUrl = newAvatar
} }
private inline fun <T> crossFriendAccess( private inline fun <T> crossFriendAccess(
@ -80,11 +80,7 @@ internal class MockNormalMemberImpl(
override var joinTimestamp: Int = joinTimestamp override var joinTimestamp: Int = joinTimestamp
override var muteTimeEndTimestamp: Long = currentTimeSeconds() + muteTimeRemaining override var muteTimeEndTimestamp: Long = currentTimeSeconds() + muteTimeRemaining
override var nick: String = nick override var nick: String by ccinfo::nick
get() = crossFriendAccess(ifExists = { it.nick }, ifNotExists = { field })
set(value) {
crossFriendAccess(ifExists = { it.mockApi.nick = value }, ifNotExists = { field = value })
}
override var remark: String = remark override var remark: String = remark
get() = crossFriendAccess(ifExists = { it.remark }, ifNotExists = { field }) get() = crossFriendAccess(ifExists = { it.remark }, ifNotExists = { field })
@ -95,15 +91,7 @@ internal class MockNormalMemberImpl(
override var permission: MemberPermission = permission override var permission: MemberPermission = permission
override var nameCard: String = nameCard override var nameCard: String = nameCard
override var specialTitle: String = specialTitle override var specialTitle: String = specialTitle
override var avatarUrl: String override var avatarUrl: String by ccinfo::avatarUrl
get() = this@MockNormalMemberImpl.avatarUrl
set(value) {
this@MockNormalMemberImpl.avatarUrl = value
bot.getFriend(this@MockNormalMemberImpl.id)?.let { f ->
f.mockApi.avatarUrl = value
}
}
} }
override val permission: MemberPermission override val permission: MemberPermission

View File

@ -10,7 +10,6 @@
package net.mamoe.mirai.mock.internal.contact package net.mamoe.mirai.mock.internal.contact
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.contact.AvatarSpec import net.mamoe.mirai.contact.AvatarSpec
import net.mamoe.mirai.contact.Stranger import net.mamoe.mirai.contact.Stranger
import net.mamoe.mirai.event.broadcast 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.message.data.OnlineMessageSource
import net.mamoe.mirai.mock.MockBot import net.mamoe.mirai.mock.MockBot
import net.mamoe.mirai.mock.contact.MockStranger 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.OnlineMsgSrcFromStranger
import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToStranger import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToStranger
import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc
import net.mamoe.mirai.utils.cast import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.lateinitMutableProperty
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -37,34 +36,23 @@ internal class MockStrangerImpl(
remark: String, remark: String,
nick: String nick: String
) : AbstractMockContact(parentCoroutineContext, bot, id), MockStranger { ) : AbstractMockContact(parentCoroutineContext, bot, id), MockStranger {
private val ccinfo = bot.impl().contactDatabase.acquireCI(id, nick)
override val mockApi: MockStranger.MockApi = object : MockStranger.MockApi { override val mockApi: MockStranger.MockApi = object : MockStranger.MockApi {
override val contact: MockStranger get() = this@MockStrangerImpl 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 remark: String = remark
override var avatarUrl: String override var avatarUrl: String by ccinfo::avatarUrl
get() = this@MockStrangerImpl.avatarUrl }
set(value) {
this@MockStrangerImpl.avatarUrl = value
bot.getFriend(this@MockStrangerImpl.id)?.let { f -> override val avatarUrl: String get() = ccinfo.avatarUrl
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 fun avatarUrl(spec: AvatarSpec): String { override fun avatarUrl(spec: AvatarSpec): String {
return avatarUrl return avatarUrl
} }
override fun changeAvatarUrl(newAvatar: String) { override fun changeAvatarUrl(newAvatar: String) {
this.avatarUrl = newAvatar ccinfo.changeAvatarUrl(newAvatar)
bot.getFriend(id)?.let { return it.changeAvatarUrl(newAvatar) }
} }
override val nick: String override val nick: String

View File

@ -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<Long, ContactInfo>()
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)
}
}
}

View File

@ -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()
}
}