diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt index c54e2e62b..a2ef510a9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt @@ -38,8 +38,8 @@ import net.mamoe.mirai.event.events.NewFriendRequestEvent import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.* import net.mamoe.mirai.network.LoginFailedException +import net.mamoe.mirai.qqandroid.contact.FriendImpl import net.mamoe.mirai.qqandroid.contact.MemberInfoImpl -import net.mamoe.mirai.qqandroid.contact.QQImpl import net.mamoe.mirai.qqandroid.contact.checkIsGroupImpl import net.mamoe.mirai.qqandroid.message.* import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler @@ -89,7 +89,7 @@ internal class QQAndroidBot constructor( event, accept = true ).sendWithoutExpect() - bot.friends.delegate.addLast(bot._lowLevelNewQQ(object : FriendInfo { + bot.friends.delegate.addLast(bot._lowLevelNewFriend(object : FriendInfo { override val uin: Long get() = event.fromId override val nick: String get() = event.fromNick })) @@ -150,7 +150,6 @@ internal class QQAndroidBot constructor( } override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) { - check(event.responded.compareAndSet(false, true)) { "the request $this has already been responded" } @@ -188,15 +187,15 @@ internal abstract class QQAndroidBotBase constructor( val json = Json(JsonConfiguration(ignoreUnknownKeys = true, encodeDefaults = true)) } - override val friends: ContactList<QQ> = ContactList(LockFreeLinkedList()) + override val friends: ContactList<Friend> = ContactList(LockFreeLinkedList()) override val nick: String get() = selfInfo.nick internal lateinit var selfInfo: JceFriendInfo - override val selfQQ: QQ by lazy { + override val selfQQ: Friend by lazy { @OptIn(LowLevelAPI::class) - _lowLevelNewQQ(object : FriendInfo { + _lowLevelNewFriend(object : FriendInfo { override val uin: Long get() = this@QQAndroidBotBase.id override val nick: String get() = this@QQAndroidBotBase.nick }) @@ -214,10 +213,10 @@ internal abstract class QQAndroidBotBase constructor( } @LowLevelAPI - override fun _lowLevelNewQQ(friendInfo: FriendInfo): QQ { - return QQImpl( + override fun _lowLevelNewFriend(friendInfo: FriendInfo): Friend { + return FriendImpl( this as QQAndroidBot, - coroutineContext + CoroutineName("QQ(${friendInfo.uin}"), + coroutineContext + CoroutineName("Friend(${friendInfo.uin}"), friendInfo.uin, friendInfo ) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt similarity index 77% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt index 13dae8893..46efcef23 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt @@ -8,7 +8,7 @@ */ @file:OptIn(MiraiInternalAPI::class, LowLevelAPI::class) -@file:Suppress("EXPERIMENTAL_API_USAGE", "DEPRECATION_ERROR") +@file:Suppress("EXPERIMENTAL_API_USAGE", "DEPRECATION_ERROR", "NOTHING_TO_INLINE") package net.mamoe.mirai.qqandroid.contact @@ -16,12 +16,8 @@ import kotlinx.atomicfu.AtomicInt import kotlinx.atomicfu.atomic import kotlinx.io.core.Closeable import net.mamoe.mirai.LowLevelAPI -import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.data.FriendInfo -import net.mamoe.mirai.data.FriendNameRemark -import net.mamoe.mirai.data.PreviousNameList -import net.mamoe.mirai.data.Profile import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.EventCancelledException @@ -35,7 +31,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352 import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn import net.mamoe.mirai.qqandroid.utils.MiraiPlatformUtils import net.mamoe.mirai.qqandroid.utils.toUHexString -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.ExternalImage +import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.getValue +import net.mamoe.mirai.utils.unsafeWeakRef import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext @@ -49,20 +48,20 @@ internal inline class FriendInfoImpl( } @OptIn(ExperimentalContracts::class) -internal fun QQ.checkIsQQImpl(): QQImpl { +internal inline fun Friend.checkIsFriendImpl(): FriendImpl { contract { - returns() implies (this@checkIsQQImpl is QQImpl) + returns() implies (this@checkIsFriendImpl is FriendImpl) } - check(this is QQImpl) { "A QQ instance is not instance of QQImpl. Don't interlace two protocol implementations together!" } + check(this is FriendImpl) { "A Friend instance is not instance of FriendImpl. Don't interlace two protocol implementations together!" } return this } -internal class QQImpl( +internal class FriendImpl( bot: QQAndroidBot, override val coroutineContext: CoroutineContext, override val id: Long, private val friendInfo: FriendInfo -) : QQ() { +) : Friend() { @Suppress("unused") // bug val lastMessageSequence: AtomicInt = atomic(-1) @@ -72,7 +71,7 @@ internal class QQImpl( @JvmSynthetic @Suppress("DuplicatedCode") - override suspend fun sendMessage(message: Message): MessageReceipt<QQ> { + override suspend fun sendMessage(message: Message): MessageReceipt<Friend> { return sendMessageImpl(message).also { logMessageSent(message) } @@ -110,7 +109,7 @@ internal class QQImpl( width = response.imageInfo.fileWidth, resourceId = response.resourceId ).also { - ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast() + ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() } is LongConn.OffPicUp.Response.RequireUpload -> { MiraiPlatformUtils.Http.postImage( @@ -141,11 +140,11 @@ internal class QQImpl( width = image.width, resourceId = response.resourceId ).also { - ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast() + ImageUploadEvent.Succeed(this@FriendImpl, image, it).broadcast() } } is LongConn.OffPicUp.Response.Failed -> { - ImageUploadEvent.Failed(this@QQImpl, image, -1, response.message).broadcast() + ImageUploadEvent.Failed(this@FriendImpl, image, -1, response.message).broadcast() error(response.message) } } @@ -153,35 +152,4 @@ internal class QQImpl( } finally { (image.input as? Closeable)?.close() } - - override fun hashCode(): Int { - var result = bot.hashCode() - result = 31 * result + id.hashCode() - return result - } - - override fun equals(other: Any?): Boolean { - @Suppress("DuplicatedCode") - if (this === other) return true - if (other !is Contact) return false - if (this::class != other::class) return false - return this.id == other.id && this.bot == other.bot - } - - @MiraiExperimentalAPI - override suspend fun queryProfile(): Profile { - TODO("not implemented") - } - - @MiraiExperimentalAPI - override suspend fun queryPreviousNameList(): PreviousNameList { - TODO("not implemented") - } - - @MiraiExperimentalAPI - override suspend fun queryRemark(): FriendNameRemark { - TODO("not implemented") - } - - override fun toString(): String = "QQ($id)" } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt index 8c86774da..faf25a19b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt @@ -250,7 +250,7 @@ internal class GroupImpl( override fun newMember(memberInfo: MemberInfo): Member { return MemberImpl( @OptIn(LowLevelAPI::class) - bot._lowLevelNewQQ(memberInfo) as QQImpl, + bot._lowLevelNewFriend(memberInfo) as FriendImpl, this, this.coroutineContext, memberInfo @@ -476,23 +476,5 @@ internal class GroupImpl( (image.input as? Closeable)?.close() } - override fun toString(): String { - return "Group($id)" - } - - override fun hashCode(): Int { - var result = bot.hashCode() - result = 31 * result + id.hashCode() - return result - } - - override fun equals(other: Any?): Boolean { - @Suppress("DuplicatedCode", "DuplicatedCode") - if (this === other) return true - if (other !is Contact) return false - if (this::class != other::class) return false - return this.id == other.id && this.bot == other.bot - } - - + override fun toString(): String = "Group($id)" } \ No newline at end of file diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt index b6062d7df..4fc9335f4 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt @@ -16,10 +16,7 @@ import kotlinx.atomicfu.atomic import kotlinx.coroutines.launch import net.mamoe.mirai.LowLevelAPI import net.mamoe.mirai.contact.* -import net.mamoe.mirai.data.FriendNameRemark import net.mamoe.mirai.data.MemberInfo -import net.mamoe.mirai.data.PreviousNameList -import net.mamoe.mirai.data.Profile import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.MemberCardChangeEvent import net.mamoe.mirai.event.events.MemberLeaveEvent @@ -42,7 +39,7 @@ import kotlin.jvm.JvmSynthetic @OptIn(LowLevelAPI::class) @Suppress("MemberVisibilityCanBePrivate") internal class MemberImpl constructor( - val qq: QQImpl, // 不要 WeakRef + val qq: FriendImpl, // 不要 WeakRef group: GroupImpl, override val coroutineContext: CoroutineContext, memberInfo: MemberInfo @@ -52,22 +49,10 @@ internal class MemberImpl constructor( @Suppress("unused") // false positive val lastMessageSequence: AtomicInt = atomic(-1) - // region QQ delegate override val id: Long = qq.id override val nick: String = qq.nick - @MiraiExperimentalAPI - override suspend fun queryProfile(): Profile = qq.queryProfile() - - @MiraiExperimentalAPI - override suspend fun queryPreviousNameList(): PreviousNameList = qq.queryPreviousNameList() - - @MiraiExperimentalAPI - override suspend fun queryRemark(): FriendNameRemark = qq.queryRemark() - - @OptIn(MiraiInternalAPI::class) @JvmSynthetic - @Suppress("DuplicatedCode", "UNCHECKED_CAST") override suspend fun sendMessage(message: Message): MessageReceipt<Member> { return sendMessageImpl(message).also { logMessageSent(message) @@ -92,7 +77,6 @@ internal class MemberImpl constructor( @JvmSynthetic override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = qq.uploadImage(image) - // endregion override var permission: MemberPermission = memberInfo.permission @@ -217,23 +201,6 @@ internal class MemberImpl constructor( MemberLeaveEvent.Kick(this@MemberImpl, null).broadcast() } } - - override fun hashCode(): Int { - var result = bot.hashCode() - result = 31 * result + id.hashCode() - return result - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is Contact) return false - if (this::class != other::class) return false - return this.id == other.id && this.bot == other.bot - } - - override fun toString(): String { - return "Member($id)" - } } @OptIn(ExperimentalContracts::class) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/util.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/util.kt index 2fc27621f..cf68a81de 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/util.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/util.kt @@ -10,7 +10,7 @@ package net.mamoe.mirai.qqandroid.contact import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.EventCancelledException import net.mamoe.mirai.event.events.MessageSendEvent @@ -31,7 +31,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.verbose @OptIn(MiraiInternalAPI::class) -internal suspend fun QQ.sendMessageImpl(message: Message): MessageReceipt<QQ> { +internal suspend fun Friend.sendMessageImpl(message: Message): MessageReceipt<Friend> { val event = MessageSendEvent.FriendMessageSendEvent(this, message.asMessageChain()).broadcast() if (event.isCancelled) { throw EventCancelledException("cancelled by FriendMessageSendEvent") diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt index b8507ffcb..3ee4741b6 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/incomingSourceImpl.kt @@ -12,8 +12,8 @@ package net.mamoe.mirai.qqandroid.message import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource @@ -57,7 +57,7 @@ internal class MessageSourceFromFriendImpl( override val random: Int get() = msg.msgBody.richText.attr!!.random override val time: Int get() = msg.msgHead.msgTime override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, 0, false) } - override val sender: QQ get() = bot.getFriend(msg.msgHead.fromUin) + override val sender: Friend get() = bot.getFriend(msg.msgHead.fromUin) private val jceData by lazy { msg.toJceDataFriendOrTemp(random) } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt index 13b0939e7..832ec4eff 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/outgoingSourceImpl.kt @@ -14,9 +14,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.ExperimentalCoroutinesApi import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.asyncFromEventOrNull import net.mamoe.mirai.event.internal.MiraiAtomicBoolean import net.mamoe.mirai.message.data.MessageChain @@ -74,7 +74,7 @@ internal class MessageSourceToFriendImpl( override val time: Int, override val originalMessage: MessageChain, override val sender: Bot, - override val target: QQ + override val target: Friend ) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal { override val bot: Bot get() = sender diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 92af20e90..40c03b08d 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -227,7 +227,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler data.friendList.forEach { // atomic bot.friends.delegate.addLast( - QQImpl(bot, bot.coroutineContext, it.friendUin, FriendInfoImpl(it)) + FriendImpl(bot, bot.coroutineContext, it.friendUin, FriendInfoImpl(it)) ).also { currentFriendCount++ } } logger.verbose { "正在加载好友列表 ${currentFriendCount}/${totalFriendCount}" } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 95f228532..9a4562364 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -18,10 +18,10 @@ import kotlinx.coroutines.flow.* import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.discardExact import net.mamoe.mirai.LowLevelAPI +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission -import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.events.BotJoinGroupEvent @@ -33,8 +33,8 @@ import net.mamoe.mirai.message.TempMessage import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.contact.GroupImpl +import net.mamoe.mirai.qqandroid.contact.checkIsFriendImpl import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl -import net.mamoe.mirai.qqandroid.contact.checkIsQQImpl import net.mamoe.mirai.qqandroid.message.* import net.mamoe.mirai.qqandroid.network.MultiPacketByIterable import net.mamoe.mirai.qqandroid.network.Packet @@ -53,10 +53,8 @@ import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf import net.mamoe.mirai.qqandroid.utils.io.serialization.readUniPacket import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf -import net.mamoe.mirai.utils.MiraiExperimentalAPI -import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.currentTimeSeconds -import net.mamoe.mirai.utils.debug +import net.mamoe.mirai.utils.* +import kotlin.collections.firstOrNull import kotlin.math.absoluteValue import kotlin.random.Random @@ -191,7 +189,7 @@ internal class MessageSvc { if (resp.result != 0) { bot.network.logger - .warning("MessageSvc.PushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}") + .warning { "MessageSvc.PushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" } return EmptyResponse } @@ -231,7 +229,7 @@ internal class MessageSvc { } 166 -> { val friend = bot.getFriendOrNull(msg.msgHead.fromUin) ?: return@mapNotNull null - friend.checkIsQQImpl() + friend.checkIsFriendImpl() if (msg.msgHead.fromUin == bot.id || !bot.firstLoginSucceed) { return@mapNotNull null @@ -365,7 +363,7 @@ internal class MessageSvc { inline fun createToFriend( client: QQAndroidClient, - qq: QQ, + qq: Friend, message: MessageChain, crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit ): OutgoingPacket { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 6fd4a28a9..f2265008b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -409,7 +409,7 @@ internal class OnlinePush { 0xB3L to lambda528 { bot -> // 08 01 12 52 08 A2 FF 8C F0 03 10 00 1D 15 3D 90 5E 22 2E E6 88 91 E4 BB AC E5 B7 B2 E7 BB 8F E6 98 AF E5 A5 BD E5 8F 8B E5 95 A6 EF BC 8C E4 B8 80 E8 B5 B7 E6 9D A5 E8 81 8A E5 A4 A9 E5 90 A7 21 2A 09 48 69 6D 31 38 38 6D 6F 65 30 07 38 03 48 DD F1 92 B7 07 val body = vProtobuf.loadAs(Submsgtype0xb3.SubMsgType0xb3.MsgBody.serializer()) - val new = bot._lowLevelNewQQ(object : FriendInfo { + val new = bot._lowLevelNewFriend(object : FriendInfo { override val uin: Long get() = body.msgAddFrdNotify.fuin override val nick: String get() = body.msgAddFrdNotify.fuinNick }) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt index 093040808..63db3304f 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt @@ -28,8 +28,6 @@ import net.mamoe.mirai.utils.OverFileSizeMaxException * * A QQ instance helps you to receive event from or sendPacket event to. * Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same. - * - * @author Him188moe */ @Suppress("INAPPLICABLE_JVM_NAME") actual abstract class QQ : Contact(), CoroutineScope { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index d00de4f3a..a244fcf24 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -109,20 +109,21 @@ abstract class Bot : CoroutineScope, LowLevelBotAPIAccessor, BotJavaFriendlyAPI( // region contacts /** - * [QQ.id] 与 [Bot.uin] 相同的 [_lowLevelNewQQ] 实例 + * [QQ.id] 与 [Bot.uin] 相同的 [_lowLevelNewFriend] 实例 */ - abstract val selfQQ: QQ + abstract val selfQQ: Friend + /** * 机器人的好友列表. 与服务器同步更新 */ - abstract val friends: ContactList<QQ> + abstract val friends: ContactList<Friend> /** * 获取一个好友对象. * @throws [NoSuchElementException] 当不存在这个好友时抛出 */ - fun getFriend(id: Long): QQ = friends.firstOrNull { it.id == id } ?: throw NoSuchElementException("friend $id") + fun getFriend(id: Long): Friend = friends.firstOrNull { it.id == id } ?: throw NoSuchElementException("friend $id") /** * 机器人加入的群列表. 与服务器同步更新 @@ -273,9 +274,17 @@ abstract class Bot : CoroutineScope, LowLevelBotAPIAccessor, BotJavaFriendlyAPI( @MiraiInternalAPI abstract val network: BotNetworkHandler - @PlannedRemoval("1.0.0") - @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) - suspend inline fun Bot.join() = this.coroutineContext[Job]!!.join() + @PlannedRemoval("1.0.0.") + @get:JvmName("getSelfQQ") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) + val selfQQDeprecated: QQ + get() = selfQQ + + @JvmName("getFriend") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) + fun getFriendDeprecated(id: Long): QQ = this.getFriend(id) } /** @@ -351,7 +360,7 @@ inline fun Bot.containsFriend(id: Long): Boolean = this.friends.contains(id) inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id) @JvmSynthetic -inline fun Bot.getFriendOrNull(id: Long): QQ? = this.friends.getOrNull(id) +inline fun Bot.getFriendOrNull(id: Long): Friend? = this.friends.getOrNull(id) @JvmSynthetic inline fun Bot.getGroupOrNull(id: Long): Group? = this.groups.getOrNull(id) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index b4c98884f..e407ce616 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -32,9 +32,7 @@ import kotlin.jvm.JvmSynthetic /** - * 联系人. 虽然叫做联系人, 但他的子类有 [QQ], [群成员][Member] 和 [群][Group]. - * - * @author Him188moe + * 联系人. 虽然叫做联系人, 但他的子类有 [人][User], 和 [群][Group]. */ abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI(), ContactOrBot { /** @@ -85,23 +83,11 @@ abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI(), ContactOrBot @JvmSynthetic abstract suspend fun uploadImage(image: ExternalImage): OfflineImage - /** - * 判断 `this` 和 [other] 是否是相同的类型, 并且 [id] 相同. - * - * 注: - * [id] 相同的 [Member] 和 [QQ], 他们并不 [equals]. - * 因为, [Member] 含义为群员, 必属于一个群. - * 而 [QQ] 含义为一个独立的人, 可以是好友, 也可以是陌生人. - */ - abstract override fun equals(other: Any?): Boolean + final override fun equals(other: Any?): Boolean = super.equals(other) + final override fun hashCode(): Int = super.hashCode() /** - * @return `bot.hashCode() * 31 + id.hashCode()` - */ - abstract override fun hashCode(): Int - - /** - * @return "QQ($id)" or "Group($id)" or "Member($id)" + * @return "Friend($id)" or "Group($id)" or "Member($id)" */ abstract override fun toString(): String } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt index c9ce94d7e..cf6b570c2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/ContactOrBot.kt @@ -15,12 +15,11 @@ import net.mamoe.mirai.utils.SinceMirai /** * 拥有 [id] 的对象. * 此为 [Contact] 与 [Bot] 的唯一公共接口. - * **注意:** 此接口为实验性接口, 将来可能会发生不兼容的更名. * * @see Contact * @see Bot */ -@SinceMirai("0.37.2") +@SinceMirai("0.39.0") interface ContactOrBot { /** * QQ 号或群号. diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Friend.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Friend.kt new file mode 100644 index 000000000..8a616fb57 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Friend.kt @@ -0,0 +1,80 @@ +/* + * 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 + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused") + +package net.mamoe.mirai.contact + +import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.events.EventCancelledException +import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent +import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent +import net.mamoe.mirai.message.MessageReceipt +import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.toMessage +import kotlin.jvm.JvmSynthetic + +/** + * 好友 对象. + * 注意: 一个 [Friend] 实例并不是独立的, 它属于一个 [Bot]. + * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. + * + * 对于同一个 [Bot] 任何一个人的 [Friend] 实例都是单一的. + * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. + */ +@Suppress("DEPRECATION_ERROR") +abstract class Friend : QQ(), CoroutineScope { + /** + * 请求头像下载链接 + */ + // @MiraiExperimentalAPI + //suspend fun queryAvatar(): AvatarLink + /** + * QQ 号码 + */ + abstract override val id: Long + + /** + * 昵称 + */ + abstract override val nick: String + + /** + * 头像下载链接 + */ + override val avatarUrl: String + get() = "http://q1.qlogo.cn/g?b=qq&nk=$id&s=640" + + /** + * 向这个对象发送消息. + * + * 单条消息最大可发送 4500 字符或 50 张图片. + * + * @see FriendMessageSendEvent 发送好友信息事件, cancellable + * @see GroupMessageSendEvent 发送群消息事件. cancellable + * + * @throws EventCancelledException 当发送消息事件被取消时抛出 + * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 + * @throws MessageTooLargeException 当消息过长时抛出 + * + * @return 消息回执. 可进行撤回 ([MessageReceipt.recall]) + */ + @JvmSynthetic + abstract override suspend fun sendMessage(message: Message): MessageReceipt<Friend> + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE") + @kotlin.internal.InlineOnly // purely virtual + @JvmSynthetic + suspend inline fun sendMessage(message: String): MessageReceipt<Friend> { + return sendMessage(message.toMessage()) + } + + final override fun toString(): String = "Friend($id)" +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index b2a583839..3f876a254 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -21,23 +21,25 @@ import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.OfflineGroupImage +import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.OverFileSizeMaxException import net.mamoe.mirai.utils.SinceMirai +import kotlin.jvm.JvmStatic import kotlin.jvm.JvmSynthetic /** - * 群. 在 QQ Android 中叫做 "Troop" + * 群. */ -expect abstract class Group() : Contact, CoroutineScope { +abstract class Group : Contact(), CoroutineScope { /** * 群名称. * - * 在修改时将会异步上传至服务器. + * 在修改时将会异步上传至服务器, 也会广播事件 [GroupNameChangeEvent]. * 频繁修改可能会被服务器拒绝. * - * @see MemberPermissionChangeEvent + * @see GroupNameChangeEvent 群名片修改事件 * @throws PermissionDeniedException 无权限修改时将会抛出异常 */ abstract var name: String @@ -88,6 +90,7 @@ expect abstract class Group() : Contact, CoroutineScope { * 群头像下载链接. */ val avatarUrl: String + get() = "https://p.qlogo.cn/gh/$id/${id}_1/640" /** * 群成员列表, 不含机器人自己, 含群主. @@ -148,6 +151,16 @@ expect abstract class Group() : Contact, CoroutineScope { @JvmSynthetic abstract override suspend fun sendMessage(message: Message): MessageReceipt<Group> + /** + * @see sendMessage + */ + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE") + @kotlin.internal.InlineOnly // purely virtual + @JvmSynthetic + suspend inline fun sendMessage(message: String): MessageReceipt<Group> { + return sendMessage(message.toMessage()) + } + /** * 上传一个图片以备发送. * @@ -161,14 +174,20 @@ expect abstract class Group() : Contact, CoroutineScope { abstract override suspend fun uploadImage(image: ExternalImage): OfflineGroupImage companion object { - // don't @JvmStatic: JDK 1.8 required - fun calculateGroupUinByGroupCode(groupCode: Long): Long + /** + * @suppress internal api + */ + @JvmStatic + fun calculateGroupUinByGroupCode(groupCode: Long): Long = + CommonGroupCalculations.calculateGroupUinByGroupCode(groupCode) - fun calculateGroupCodeByGroupUin(groupUin: Long): Long + /** + * @suppress internal api + */ + @JvmStatic + fun calculateGroupCodeByGroupUin(groupUin: Long): Long = + CommonGroupCalculations.calculateGroupCodeByGroupUin(groupUin) } - - @MiraiExperimentalAPI - fun toFullString(): String } /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index a6e5ada81..fb1c5d94d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -14,8 +14,10 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Bot import net.mamoe.mirai.JavaFriendlyAPI import net.mamoe.mirai.event.events.* +import net.mamoe.mirai.getFriendOrNull import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.WeakRefProperty import kotlin.jvm.JvmSynthetic @@ -24,10 +26,13 @@ import kotlin.time.ExperimentalTime /** * 群成员. - */ // 不要删除多平台结构, kotlin bug + * + * 群成员可能也是好友, 但他们在对象类型上不同. + * 群成员可以通过 [asFriend] 得到相关好友对象. + */ @Suppress("INAPPLICABLE_JVM_NAME") @OptIn(MiraiInternalAPI::class, JavaFriendlyAPI::class) -expect abstract class Member() : MemberJavaFriendlyAPI { +abstract class Member : MemberJavaFriendlyAPI() { /** * 所在的群. */ @@ -119,16 +124,6 @@ expect abstract class Member() : MemberJavaFriendlyAPI { @JvmSynthetic abstract suspend fun kick(message: String = "") - /** - * 当且仅当 `[other] is [Member] && [other].id == this.id && [other].group == this.group` 时为 true - */ - abstract override fun equals(other: Any?): Boolean - - /** - * @return `bot.hashCode() * 31 + id.hashCode()` - */ - abstract override fun hashCode(): Int - /** * 向这个对象发送消息. * @@ -145,6 +140,43 @@ expect abstract class Member() : MemberJavaFriendlyAPI { */ @JvmSynthetic abstract override suspend fun sendMessage(message: Message): MessageReceipt<Member> + + /** + * @see sendMessage + */ + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE") + @kotlin.internal.InlineOnly // purely virtual + @JvmSynthetic + suspend inline fun sendMessage(message: String): MessageReceipt<Member> { + return sendMessage(message.toMessage()) + } + + final override fun toString(): String = "Member($id)" +} + +/** + * 得到此成员作为好友的对象. + */ +inline val Member.asFriend: Friend + get() = this.bot.getFriendOrNull(this.id) ?: error("$this is not a friend") + +/** + * 得到此成员作为好友的对象. + */ +inline val Member.asFriendOrNull: Friend? + get() = this.bot.getFriendOrNull(this.id) + +/** + * 判断此成员是否为好友 + */ +inline val Member.isFriend: Boolean + get() = this.bot.friends.contains(this.id) + +/** + * 如果此成员是好友, 则执行 [block] 并返回其返回值. 否则返回 `null` + */ +inline fun <R> Member.takeIfFriend(block: (Friend) -> R): R? { + return this.asFriendOrNull?.let(block) } /** @@ -161,6 +193,9 @@ fun Member.isMuted(): Boolean { return muteTimeRemaining != 0 && muteTimeRemaining != 0xFFFFFFFF.toInt() } +/** + * @see Member.mute + */ @ExperimentalTime suspend inline fun Member.mute(duration: Duration) { require(duration.inDays <= 30) { "duration must be at most 1 month" } @@ -168,4 +203,7 @@ suspend inline fun Member.mute(duration: Duration) { this.mute(duration.inSeconds.toInt()) } +/** + * @see Member.mute + */ suspend inline fun Member.mute(durationSeconds: Long) = this.mute(durationSeconds.toInt()) \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/MemberPermission.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/MemberPermission.kt index 4bb688768..80b4d3527 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/MemberPermission.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/MemberPermission.kt @@ -12,10 +12,8 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Bot -import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.SinceMirai - /** * 群成员的权限. * @@ -37,39 +35,42 @@ enum class MemberPermission : Comparable<MemberPermission> { */ OWNER; // ordinal = 2 + /** + * 权限等级. [OWNER] 为 2, [ADMINISTRATOR] 为 1, [MEMBER] 为 0 + */ @SinceMirai("0.32.0") val level: Int get() = ordinal } /** - * 是群主 + * 判断权限是否为群主 */ inline fun MemberPermission.isOwner(): Boolean = this == MemberPermission.OWNER /** - * 是管理员 + * 判断权限是否为管理员 */ inline fun MemberPermission.isAdministrator(): Boolean = this == MemberPermission.ADMINISTRATOR /** - * 是管理员或群主 + * 判断权限是否为管理员或群主 */ inline fun MemberPermission.isOperator(): Boolean = isAdministrator() || isOwner() /** - * 是群主 + * 判断权限是否为群主 */ inline fun Member.isOwner(): Boolean = this.permission.isOwner() /** - * 是管理员 + * 判断权限是否为管理员 */ inline fun Member.isAdministrator(): Boolean = this.permission.isAdministrator() /** - * 是管理员或群主 + * 判断权限是否为管理员或群主 */ inline fun Member.isOperator(): Boolean = this.permission.isOperator() @@ -77,9 +78,10 @@ inline fun Member.isOperator(): Boolean = this.permission.isOperator() /** * 权限不足 */ -expect class PermissionDeniedException : IllegalStateException { - constructor() - constructor(message: String?) +@Suppress("unused") +class PermissionDeniedException : IllegalStateException { + constructor() : super("Permission denied") + constructor(message: String?) : super(message) } /** @@ -87,10 +89,9 @@ expect class PermissionDeniedException : IllegalStateException { * * @throws PermissionDeniedException */ -@OptIn(MiraiExperimentalAPI::class) inline fun Group.checkBotPermission( required: MemberPermission, - lazyMessage: () -> String = { + crossinline lazyMessage: () -> String = { "Permission denied: required $required, got actual $botPermission for $bot in group $id" } ) { @@ -104,9 +105,8 @@ inline fun Group.checkBotPermission( * * @throws PermissionDeniedException */ -@OptIn(MiraiExperimentalAPI::class) inline fun Group.checkBotPermissionOperator( - lazyMessage: () -> String = { + crossinline lazyMessage: () -> String = { "Permission denied: required ${MemberPermission.ADMINISTRATOR} or ${MemberPermission.OWNER}, got actual $botPermission for $bot in group $id" } ) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt index c54ad63fb..a5055deb8 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt @@ -13,76 +13,47 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot -import net.mamoe.mirai.data.FriendNameRemark -import net.mamoe.mirai.data.PreviousNameList -import net.mamoe.mirai.data.Profile -import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.EventCancelledException -import net.mamoe.mirai.event.events.ImageUploadEvent import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineFriendImage -import net.mamoe.mirai.utils.ExternalImage -import net.mamoe.mirai.utils.MiraiExperimentalAPI -import net.mamoe.mirai.utils.OverFileSizeMaxException +import net.mamoe.mirai.utils.PlannedRemoval import kotlin.jvm.JvmSynthetic /** * QQ 对象. - * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot]. - * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. * - * 对于同一个 [Bot] 任何一个人的 [QQ] 实例都是单一的. + * 自 0.39.0 起 mirai 引入 [User] 作为 [Friend] 和 [Member] 的父类, + * 以备将来支持仅 [Friend] 可用的 API, 如设置备注. * - * A QQ instance helps you to receive event from or sendPacket event to. - * Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same. + * 所有 API 均有二进制兼容. * - * @author Him188moe + * 请根据实际情况, 使用 [Friend] 或 [User] 替代. */ -@Suppress("INAPPLICABLE_JVM_NAME") -expect abstract class QQ() : Contact, CoroutineScope { - /** - * 请求头像下载链接 - */ - // @MiraiExperimentalAPI - //suspend fun queryAvatar(): AvatarLink +@PlannedRemoval("1.0.0") +@Deprecated( + "use Friend or Person instead", + replaceWith = ReplaceWith("Friend", "net.mamoe.mirai.contact.Friend"), + level = DeprecationLevel.ERROR +) +@Suppress("DEPRECATION_ERROR") +abstract class QQ : User(), CoroutineScope { /** * QQ 号码 */ abstract override val id: Long + /** * 昵称 */ - abstract val nick: String - - /** - * 查询用户资料 - */ - @MiraiExperimentalAPI("还未支持") - abstract suspend fun queryProfile(): Profile + abstract override val nick: String /** * 头像下载链接 */ - val avatarUrl: String - - /** - * 查询曾用名. - * - * 曾用名可能是: - * - 昵称 - * - 共同群内的群名片 - */ - @MiraiExperimentalAPI("还未支持") - abstract suspend fun queryPreviousNameList(): PreviousNameList - - /** - * 查询机器人账号给这个人设置的备注 - */ - @MiraiExperimentalAPI("还未支持") - abstract suspend fun queryRemark(): FriendNameRemark + override val avatarUrl: String + get() = "http://q1.qlogo.cn/g?b=qq&nk=$id&s=640" /** * 向这个对象发送消息. @@ -100,16 +71,4 @@ expect abstract class QQ() : Contact, CoroutineScope { */ @JvmSynthetic abstract override suspend fun sendMessage(message: Message): MessageReceipt<QQ> - - /** - * 上传一个图片以备发送. - * - * @see BeforeImageUploadEvent 图片发送前事件, cancellable - * @see ImageUploadEvent 图片发送完成事件 - * - * @throws EventCancelledException 当发送消息事件被取消 - * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 20 MB) - */ - @JvmSynthetic - abstract override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage } \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt similarity index 52% rename from mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt index 093040808..fd8456a7b 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/User.kt @@ -1,12 +1,18 @@ -@file:Suppress("unused") +/* + * 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 + */ + +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused") package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot -import net.mamoe.mirai.data.FriendNameRemark -import net.mamoe.mirai.data.PreviousNameList -import net.mamoe.mirai.data.Profile import net.mamoe.mirai.event.events.BeforeImageUploadEvent import net.mamoe.mirai.event.events.EventCancelledException import net.mamoe.mirai.event.events.ImageUploadEvent @@ -15,66 +21,38 @@ import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.OfflineFriendImage +import net.mamoe.mirai.message.data.toMessage import net.mamoe.mirai.utils.ExternalImage -import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.OverFileSizeMaxException +import kotlin.jvm.JvmSynthetic /** - * QQ 对象. - * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot]. - * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. + * 代表一个 **用户**. * - * 对于同一个 [Bot] 任何一个人的 [QQ] 实例都是单一的. + * 其子类有 [群成员][Member] 和 [好友][Friend]. + * 虽然群成员也可能是好友, 但他们仍是不同的两个类型. * - * A QQ instance helps you to receive event from or sendPacket event to. - * Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same. + * 注意: 一个 [User] 实例并不是独立的, 它属于一个 [Bot]. * - * @author Him188moe + * 对于同一个 [Bot] 任何一个人的 [User] 实例都是单一的. */ -@Suppress("INAPPLICABLE_JVM_NAME") -actual abstract class QQ : Contact(), CoroutineScope { - /** - * 请求头像下载链接 - */ - // @MiraiExperimentalAPI - //suspend fun queryAvatar(): AvatarLink +abstract class User : Contact(), CoroutineScope { /** * QQ 号码 */ - actual abstract override val id: Long + abstract override val id: Long + /** * 昵称 */ - actual abstract val nick: String - - /** - * 查询用户资料 - */ - @MiraiExperimentalAPI("还未支持") - actual abstract suspend fun queryProfile(): Profile + abstract val nick: String /** * 头像下载链接 */ - actual val avatarUrl: String + open val avatarUrl: String get() = "http://q1.qlogo.cn/g?b=qq&nk=$id&s=640" - /** - * 查询曾用名. - * - * 曾用名可能是: - * - 昵称 - * - 共同群内的群名片 - */ - @MiraiExperimentalAPI("还未支持") - actual abstract suspend fun queryPreviousNameList(): PreviousNameList - - /** - * 查询机器人账号给这个人设置的备注 - */ - @MiraiExperimentalAPI("还未支持") - actual abstract suspend fun queryRemark(): FriendNameRemark - /** * 向这个对象发送消息. * @@ -90,7 +68,17 @@ actual abstract class QQ : Contact(), CoroutineScope { * @return 消息回执. 可进行撤回 ([MessageReceipt.recall]) */ @JvmSynthetic - actual abstract override suspend fun sendMessage(message: Message): MessageReceipt<QQ> + abstract override suspend fun sendMessage(message: Message): MessageReceipt<User> + + /** + * @see sendMessage + */ + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "VIRTUAL_MEMBER_HIDDEN", "OVERRIDE_BY_INLINE") + @kotlin.internal.InlineOnly // purely virtual + @JvmSynthetic + suspend inline fun sendMessage(message: String): MessageReceipt<User> { + return sendMessage(message.toMessage()) + } /** * 上传一个图片以备发送. @@ -102,5 +90,7 @@ actual abstract class QQ : Contact(), CoroutineScope { * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 20 MB) */ @JvmSynthetic - actual abstract override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage + abstract override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage + + abstract override fun toString(): String } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/javaFriendly.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/javaFriendly.kt index b20b7f897..49bfeaf45 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/javaFriendly.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/javaFriendly.kt @@ -13,15 +13,18 @@ import net.mamoe.mirai.JavaFriendlyAPI import net.mamoe.mirai.utils.MiraiInternalAPI /** - * [Contact] 中为了让 `Java` 更容易调用的 API + * [Contact] 中为了让 `Java` 更容易调用的 API. + * 不要用它作为一个类型, 只应使用其中的方法 */ @MiraiInternalAPI @JavaFriendlyAPI -expect abstract class ContactJavaFriendlyAPI() +expect abstract class ContactJavaFriendlyAPI internal constructor() /** * [Member] 中为了让 `Java` 更容易调用的 API + * 不要用它作为一个类型, 只应使用其中的方法 */ +@Suppress("DEPRECATION_ERROR") @MiraiInternalAPI @JavaFriendlyAPI -expect abstract class MemberJavaFriendlyAPI : QQ \ No newline at end of file +expect abstract class MemberJavaFriendlyAPI internal constructor() : QQ // 将来会改为 User \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt index 9a7e750dd..560cf5c68 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribersBuilder.kt @@ -241,7 +241,7 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>( /** 如果是这个人发的消息. 消息可以是好友消息也可以是群消息 */ @MessageDsl - fun sentBy(friend: QQ): ListeningFilter = content { sender.id == friend.id } + fun sentBy(friend: User): ListeningFilter = content { sender.id == friend.id } /** 如果是这个人发的消息. 消息可以是好友消息也可以是群消息 */ @MessageDsl @@ -294,7 +294,7 @@ open class MessageSubscribersBuilder<M : ContactMessage, out Ret, R : RR, RR>( /** [消息内容][Message.contentToString]包含目标为 [target] 的 [At] */ @MessageDsl - fun at(target: QQ): ListeningFilter = content { message.firstIsInstanceOrNull<At>()?.target == target.id } + fun at(target: User): ListeningFilter = content { message.firstIsInstanceOrNull<At>()?.target == target.id } /** [消息内容][Message.contentToString]包含目标为 [Bot] 的 [At], 就执行 [onEvent] */ @MessageDsl diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 6d1587c61..1a2ae792f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -102,7 +102,7 @@ sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractCancellableEve ) : MessageSendEvent(), CancellableEvent data class FriendMessageSendEvent( - override val target: QQ, + override val target: Friend, var message: MessageChain ) : MessageSendEvent(), CancellableEvent } @@ -539,9 +539,17 @@ data class MemberUnmuteEvent( @SinceMirai("0.36.0") data class FriendRemarkChangeEvent( override val bot: Bot, - val friend: QQ, + val friend: Friend, val newName: String -) : BotEvent, Packet +) : BotEvent, Packet { + + @Deprecated("", level = DeprecationLevel.HIDDEN) + @get:JvmSynthetic + @get:JvmName("getFriend") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + val friendDeprecated: QQ + get() = friend +} /** * 成功添加了一个新好友的事件 @@ -551,9 +559,16 @@ data class FriendAddEvent( /** * 新好友. 已经添加到 [Bot.friends] */ - val friend: QQ + val friend: Friend ) : BotEvent, Packet { override val bot: Bot get() = friend.bot + + @Deprecated("", level = DeprecationLevel.HIDDEN) + @get:JvmSynthetic + @get:JvmName("getFriend") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + val friendDeprecated: QQ + get() = friend } /** @@ -561,9 +576,16 @@ data class FriendAddEvent( */ @SinceMirai("0.36.0") data class FriendDeleteEvent( - val friend: QQ + val friend: Friend ) : BotEvent, Packet { override val bot: Bot get() = friend.bot + + @Deprecated("", level = DeprecationLevel.HIDDEN) + @get:JvmSynthetic + @get:JvmName("getFriend") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + val friendDeprecated: QQ + get() = friend } /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt index ac811712b..1019a6f1a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/types.kt @@ -10,11 +10,13 @@ package net.mamoe.mirai.event.events import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.Event import net.mamoe.mirai.utils.MiraiExperimentalAPI +import kotlin.jvm.JvmName +import kotlin.jvm.JvmSynthetic /** * 有关一个 [Bot] 的事件 @@ -85,7 +87,14 @@ val GroupOperableEvent.operatorOrBot: Member * 有关好友的事件 */ interface FriendEvent : BotEvent { - val friend: QQ + val friend: Friend override val bot: Bot get() = friend.bot + + @Deprecated("", level = DeprecationLevel.HIDDEN) + @get:JvmSynthetic + @get:JvmName("getFriend") + @Suppress("INAPPLICABLE_JVM_NAME", "DEPRECATION_ERROR") + val friendDeprecated: net.mamoe.mirai.contact.QQ + get() = friend } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt index daff84a10..b0b3daa5e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt @@ -10,8 +10,8 @@ package net.mamoe.mirai import kotlinx.coroutines.Job +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.data.* import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.SinceMirai @@ -37,13 +37,13 @@ annotation class LowLevelAPI @LowLevelAPI interface LowLevelBotAPIAccessor { /** - * 构造一个 [_lowLevelNewQQ] 对象. 它持有对 [Bot] 的弱引用([WeakRef]). + * 构造一个 [Friend] 对象. 它持有对 [Bot] 的弱引用([WeakRef]). * * [Bot] 无法管理这个对象, 但这个对象会以 [Bot] 的 [Job] 作为父 Job. * 因此, 当 [Bot] 被关闭后, 这个对象也会被关闭. */ @LowLevelAPI - fun _lowLevelNewQQ(friendInfo: FriendInfo): QQ + fun _lowLevelNewFriend(friendInfo: FriendInfo): Friend /** * 向服务器查询群列表. 返回值高 32 bits 为 uin, 低 32 bits 为 groupCode diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/ContactMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/ContactMessage.kt index ee84de497..df229c4d1 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/ContactMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/ContactMessage.kt @@ -23,10 +23,7 @@ import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.async import kotlinx.coroutines.io.ByteReadChannel import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.* import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.selectMessages import net.mamoe.mirai.event.syncFromEvent @@ -52,7 +49,7 @@ import kotlin.jvm.JvmSynthetic */ @Suppress("DEPRECATION") @SinceMirai("0.32.0") -abstract class ContactMessage : MessagePacket<QQ, Contact>(), BotEvent +abstract class ContactMessage : MessagePacket<User, Contact>(), BotEvent /** * 一条从服务器接收到的消息事件. @@ -63,7 +60,7 @@ abstract class ContactMessage : MessagePacket<QQ, Contact>(), BotEvent message = "use ContactMessage", replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage") ) -expect abstract class MessagePacket<TSender : QQ, TSubject : Contact> constructor() : +expect abstract class MessagePacket<TSender : User, TSubject : Contact> constructor() : MessagePacketBase<TSender, TSubject> /** @@ -74,7 +71,7 @@ expect abstract class MessagePacket<TSender : QQ, TSubject : Contact> constructo replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage") ) @Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST") -abstract class MessagePacketBase<out TSender : QQ, out TSubject : Contact> : Packet, BotEvent { +abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent { /** * 接受到这条消息的 */ @@ -105,6 +102,10 @@ abstract class MessagePacketBase<out TSender : QQ, out TSubject : Contact> : Pac */ abstract val message: MessageChain + /** + * 消息源 + */ + open val source: OnlineMessageSource.Incoming get() = message.source as OnlineMessageSource.Incoming // region 发送 Message @@ -118,18 +119,11 @@ abstract class MessagePacketBase<out TSender : QQ, out TSubject : Contact> : Pac suspend inline fun reply(plain: String): MessageReceipt<TSubject> = subject.sendMessage(plain.toMessage().asMessageChain()) as MessageReceipt<TSubject> - // endregion - // region 撤回 - - // endregion - - // region 上传图片 + // region 图片 suspend inline fun ExternalImage.upload(): Image = this.upload(subject) - // endregion - // region 发送图片 suspend inline fun ExternalImage.send(): MessageReceipt<TSubject> = this.sendTo(subject) suspend inline fun Image.send(): MessageReceipt<TSubject> = this.sendTo(subject) @@ -159,22 +153,12 @@ abstract class MessagePacketBase<out TSender : QQ, out TSubject : Contact> : Pac @JvmName("reply2") suspend inline fun MessageChain.quoteReply(): MessageReceipt<TSubject> = quoteReply(this) - open val source: OnlineMessageSource.Incoming get() = message.source as OnlineMessageSource.Incoming - // endregion - operator fun <M : Message> get(at: Message.Key<M>): M { + inline operator fun <M : Message> get(at: Message.Key<M>): M { return this.message[at] } - /** - * 创建 @ 这个账号的消息. 当且仅当消息为群消息时可用. 否则将会抛出 [IllegalArgumentException] - */ - fun QQ.at(): At = At(this as? Member ?: error("`QQ.at` can only be used in GroupMessage")) - - fun At.member(): Member = (this@MessagePacketBase as? GroupMessage)?.group?.get(this.target) - ?: error("`At.member` can only be used in GroupMessage") - inline fun At.isBot(): Boolean = target == bot.id // endregion @@ -202,13 +186,40 @@ abstract class MessagePacketBase<out TSender : QQ, out TSubject : Contact> : Pac // endregion - @Deprecated("use reply(String) for clear semantics", ReplaceWith("reply(this)")) + @PlannedRemoval("1.0.0") + @Deprecated("use reply(String) for clear semantics", ReplaceWith("reply(this)"), + DeprecationLevel.ERROR) @JvmName("reply1") suspend inline fun String.reply(): MessageReceipt<TSubject> = reply(this) - @Deprecated("use reply(String) for clear semantics", ReplaceWith("reply(this)")) + @PlannedRemoval("1.0.0") + @Deprecated("use reply(String) for clear semantics", ReplaceWith("reply(this)"), + level = DeprecationLevel.ERROR) @JvmName("reply1") suspend inline fun Message.reply(): MessageReceipt<TSubject> = reply(this) + + @Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN) + @get:JvmSynthetic + @get:JvmName("getSender") + @Suppress("DEPRECATION_ERROR", "INAPPLICABLE_JVM_NAME") + val senderDeprecated: QQ + get() = sender as QQ + + @Suppress("DEPRECATION_ERROR") + @PlannedRemoval("1.0.0") + @Deprecated("removed", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("At(this as? Member ?: error(\"`QQ.at` can only be used in GroupMessage\"))", + "net.mamoe.mirai.message.data.At", + "net.mamoe.mirai.contact.Member")) + fun QQ.at(): At = At(this as? Member ?: error("`QQ.at` can only be used in GroupMessage")) + + @PlannedRemoval("1.0.0") + @Deprecated("removed", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("(this@MessagePacketBase as? GroupMessage)?.group?.get(this.target) ?: error(\"`At.member` can only be used in GroupMessage\")")) + fun At.member(): Member = (this@MessagePacketBase as? GroupMessage)?.group?.get(this.target) + ?: error("`At.member` can only be used in GroupMessage") } /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt index e0075ddd5..8930500e0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt @@ -7,15 +7,19 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress("DEPRECATION_ERROR") + package net.mamoe.mirai.message import net.mamoe.mirai.Bot +import net.mamoe.mirai.contact.Friend import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.BroadcastControllable import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.OnlineMessageSource import net.mamoe.mirai.message.data.source +import net.mamoe.mirai.utils.PlannedRemoval import net.mamoe.mirai.utils.getValue import net.mamoe.mirai.utils.unsafeWeakRef @@ -23,17 +27,21 @@ import net.mamoe.mirai.utils.unsafeWeakRef * 好友消息 */ class FriendMessage( - sender: QQ, + sender: Friend, override val message: MessageChain ) : ContactMessage(), BroadcastControllable { + @PlannedRemoval("1.0.0") + @Deprecated("", level = DeprecationLevel.HIDDEN) + constructor(sender: QQ, message: MessageChain) : this(sender as Friend, message) + init { val source = message.getOrNull(MessageSource) ?: error("Cannot find MessageSource from message") check(source is OnlineMessageSource.Incoming.FromFriend) { "source provided to a FriendMessage must be an instance of OnlineMessageSource.Incoming.FromFriend" } } - override val sender: QQ by sender.unsafeWeakRef() + override val sender: Friend by sender.unsafeWeakRef() override val bot: Bot get() = sender.bot - override val subject: QQ get() = sender + override val subject: Friend get() = sender override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend override fun toString(): String = "FriendMessage(sender=${sender.id}, message=$message)" diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt index fc961d633..c457c9517 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt @@ -14,10 +14,7 @@ import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.event.Event -import net.mamoe.mirai.message.data.MessageChain -import net.mamoe.mirai.message.data.MessageSource -import net.mamoe.mirai.message.data.OnlineMessageSource -import net.mamoe.mirai.message.data.source +import net.mamoe.mirai.message.data.* import net.mamoe.mirai.utils.getValue import net.mamoe.mirai.utils.unsafeWeakRef @@ -44,7 +41,7 @@ class GroupMessage( override val source: OnlineMessageSource.Incoming.FromGroup get() = message.source as OnlineMessageSource.Incoming.FromGroup - inline fun Long.member(): Member = group[this] + inline fun At.asMember(): Member = group[this.target] override fun toString(): String = "GroupMessage(group=${group.id}, senderName=$senderName, sender=${sender.id}, permission=${permission.name}, message=$message)" diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt index 291ca89c6..0e7806620 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -116,14 +116,12 @@ sealed class OnlineMessageSource : MessageSource() { * 消息发送人. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群员][Member]. * 即类型必定为 [Bot], [QQ] 或 [Member] */ - @ExperimentalIdentification abstract val sender: ContactOrBot /** * 消息发送目标. 可能为 [机器人][Bot] 或 [好友][QQ] 或 [群][Group]. * 即类型必定为 [Bot], [QQ] 或 [Group] */ - @ExperimentalIdentification abstract val target: ContactOrBot /** @@ -135,7 +133,6 @@ sealed class OnlineMessageSource : MessageSource() { /** * 由 [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource] */ - @OptIn(ExperimentalIdentification::class) sealed class Outgoing : OnlineMessageSource() { companion object Key : Message.Key<Outgoing> { override val typeName: String get() = "OnlineMessageSource.Outgoing" @@ -152,8 +149,8 @@ sealed class OnlineMessageSource : MessageSource() { override val typeName: String get() = "OnlineMessageSource.Outgoing.ToFriend" } - abstract override val target: QQ - final override val subject: QQ get() = target + abstract override val target: Friend + final override val subject: Friend get() = target // final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})" } @@ -181,13 +178,12 @@ sealed class OnlineMessageSource : MessageSource() { /** * 接收到的一条消息的 [MessageSource] */ - @OptIn(ExperimentalIdentification::class) sealed class Incoming : OnlineMessageSource() { companion object Key : Message.Key<Incoming> { override val typeName: String get() = "OnlineMessageSource.Incoming" } - abstract override val sender: QQ // out QQ + abstract override val sender: User final override val fromId: Long get() = sender.id final override val targetId: Long get() = target.id @@ -197,8 +193,8 @@ sealed class OnlineMessageSource : MessageSource() { override val typeName: String get() = "OnlineMessageSource.Incoming.FromFriend" } - abstract override val sender: QQ - final override val subject: QQ get() = sender + abstract override val sender: Friend + final override val subject: Friend get() = sender final override val target: Bot get() = sender.bot // final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})" } @@ -243,7 +239,6 @@ sealed class OnlineMessageSource : MessageSource() { @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) @get:JvmName("target") @get:JvmSynthetic - @OptIn(ExperimentalIdentification::class) open val target2: Any get() = target @@ -251,7 +246,6 @@ sealed class OnlineMessageSource : MessageSource() { @Deprecated("for binary compatibility until 1.0.0", level = DeprecationLevel.HIDDEN) @get:JvmName("sender") @get:JvmSynthetic - @OptIn(ExperimentalIdentification::class) open val sender2: Any get() = sender } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt index d0dbdd67c..7ef989a4d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("EXPERIMENTAL_API_USAGE") +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused") package net.mamoe.mirai.utils @@ -18,7 +18,7 @@ import kotlinx.io.core.Input import kotlinx.serialization.InternalSerializationApi import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.User import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.OfflineImage @@ -153,7 +153,7 @@ class ExternalImage private constructor( @JvmSynthetic suspend fun <C : Contact> ExternalImage.sendTo(contact: C): MessageReceipt<C> = when (contact) { is Group -> contact.uploadImage(this).sendTo(contact) - is QQ -> contact.uploadImage(this).sendTo(contact) + is User -> contact.uploadImage(this).sendTo(contact) else -> error("unreachable") } @@ -166,7 +166,7 @@ suspend fun <C : Contact> ExternalImage.sendTo(contact: C): MessageReceipt<C> = @JvmSynthetic suspend fun ExternalImage.upload(contact: Contact): OfflineImage = when (contact) { is Group -> contact.uploadImage(this) - is QQ -> contact.uploadImage(this) + is User -> contact.uploadImage(this) else -> error("unreachable") } diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt index 7c6f8b5db..ef3295b71 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt @@ -1,7 +1,6 @@ package net.mamoe.mirai import kotlinx.coroutines.* -import net.mamoe.mirai.contact.PermissionDeniedException import net.mamoe.mirai.contact.recall import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.message.MessageReceipt diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt index 8a79554dd..6e0b96bcf 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt @@ -205,7 +205,7 @@ actual abstract class ContactJavaFriendlyAPI { } } -@Suppress("INAPPLICABLE_JVM_NAME", "FunctionName", "unused", "unused") +@Suppress("INAPPLICABLE_JVM_NAME", "FunctionName", "unused", "unused", "DEPRECATION_ERROR") @MiraiInternalAPI @JavaFriendlyAPI actual abstract class MemberJavaFriendlyAPI : QQ() { diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt deleted file mode 100644 index 7f49e77f8..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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.contact - -import kotlinx.coroutines.CoroutineScope -import net.mamoe.mirai.Bot -import net.mamoe.mirai.LowLevelAPI -import net.mamoe.mirai.data.MemberInfo -import net.mamoe.mirai.event.events.* -import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent -import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent -import net.mamoe.mirai.message.MessageReceipt -import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.message.data.OfflineGroupImage -import net.mamoe.mirai.utils.ExternalImage -import net.mamoe.mirai.utils.MiraiExperimentalAPI -import net.mamoe.mirai.utils.OverFileSizeMaxException -import net.mamoe.mirai.utils.SinceMirai - -/** - * 群. 在 QQ Android 中叫做 "Troop" - */ -@Suppress("INAPPLICABLE_JVM_NAME") -actual abstract class Group : Contact(), CoroutineScope { - /** - * 群名称. - * - * 在修改时将会异步上传至服务器. - * 频繁修改可能会被服务器拒绝. - * - * @see MemberPermissionChangeEvent - * @throws PermissionDeniedException 无权限修改时将会抛出异常 - */ - actual abstract var name: String - - /** - * 群设置 - */ - @SinceMirai("0.30.0") - actual abstract val settings: GroupSettings - - /** - * 同为 groupCode, 用户看到的群号码. - */ - actual abstract override val id: Long - - /** - * 群主. - * - * @return 若机器人是群主, 返回 [botAsMember]. 否则返回相应的成员 - */ - actual abstract val owner: Member - - /** - * [Bot] 在群内的 [newMember] 实例 - */ - @MiraiExperimentalAPI - actual abstract val botAsMember: Member - - /** - * 机器人被禁言还剩余多少秒 - * - * @see BotMuteEvent 机器人被禁言事件 - * @see isBotMuted 判断机器人是否正在被禁言 - */ - actual abstract val botMuteRemaining: Int - - /** - * 机器人在这个群里的权限 - * - * @see Group.checkBotPermission 检查 [Bot] 在这个群里的权限 - * @see Group.checkBotPermissionOperator 要求 [Bot] 在这个群里的权限为 [管理员或群主][MemberPermission.isOperator] - * - * @see BotGroupPermissionChangeEvent 机器人群员修改 - */ - actual abstract val botPermission: MemberPermission - - /** - * 群头像下载链接. - */ - actual val avatarUrl: String - get() = "https://p.qlogo.cn/gh/$id/${id}_1/640" - - /** - * 群成员列表, 不含机器人自己, 含群主. - * 在 [Group] 实例创建的时候查询一次. 并与事件同步事件更新 - */ - actual abstract val members: ContactList<Member> - - /** - * 获取群成员实例. 不存在时抛出 [kotlin.NoSuchElementException] - * 当 [id] 为 [Bot.id] 时返回 [botAsMember] - */ - actual abstract operator fun get(id: Long): Member - - /** - * 获取群成员实例, 不存在则 null - * 当 [id] 为 [Bot.id] 时返回 [botAsMember] - */ - actual abstract fun getOrNull(id: Long): Member? - - - /** - * 检查此 id 的群成员是否存在 - * 当 [id] 为 [Bot.id] 时返回 `true` - */ - actual abstract operator fun contains(id: Long): Boolean - - /** - * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 - */ - @SinceMirai("0.37.0") - actual abstract suspend fun quit(): Boolean - - /** - * 构造一个 [Member]. - * 非特殊情况请不要使用这个函数. 优先使用 [get]. - */ - @LowLevelAPI - @MiraiExperimentalAPI("dangerous") - actual abstract fun newMember(memberInfo: MemberInfo): Member - - /** - * 向这个对象发送消息. - * - * 单条消息最大可发送 4500 字符或 50 张图片. - * - * @see FriendMessageSendEvent 发送好友信息事件, cancellable - * @see GroupMessageSendEvent 发送群消息事件. cancellable - * - * @throws EventCancelledException 当发送消息事件被取消时抛出 - * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 - * @throws MessageTooLargeException 当消息过长时抛出 - * - * @return 消息回执. 可进行撤回 ([MessageReceipt.recall]) - */ - @JvmSynthetic - actual abstract override suspend fun sendMessage(message: Message): MessageReceipt<Group> - - /** - * 上传一个图片以备发送. - * - * @see BeforeImageUploadEvent 图片上传前事件, cancellable - * @see ImageUploadEvent 图片上传完成事件 - * - * @throws EventCancelledException 当发送消息事件被取消 - * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 20 MB) - */ - @JvmSynthetic - actual abstract override suspend fun uploadImage(image: ExternalImage): OfflineGroupImage - - actual companion object { - actual fun calculateGroupUinByGroupCode(groupCode: Long): Long = - CommonGroupCalculations.calculateGroupUinByGroupCode(groupCode) - - actual fun calculateGroupCodeByGroupUin(groupUin: Long): Long = - CommonGroupCalculations.calculateGroupCodeByGroupUin(groupUin) - } - - @MiraiExperimentalAPI - actual fun toFullString(): String { - return "Group(id=${this.id}, name=$name, owner=${owner.id}, members=${members.idContentString})" - } -} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt deleted file mode 100644 index 8afbf1231..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 - */ - -@file:Suppress("unused") - -package net.mamoe.mirai.contact - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.JavaFriendlyAPI -import net.mamoe.mirai.event.events.* -import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent -import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent -import net.mamoe.mirai.message.MessageReceipt -import net.mamoe.mirai.message.data.Message -import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.WeakRefProperty - -/** - * 群成员. - */ -@OptIn(MiraiInternalAPI::class, JavaFriendlyAPI::class) -@Suppress("INAPPLICABLE_JVM_NAME") -actual abstract class Member : MemberJavaFriendlyAPI() { - /** - * 所在的群. - */ - @WeakRefProperty - actual abstract val group: Group - - /** - * 成员的权限, 动态更新. - * - * @see MemberPermissionChangeEvent 权限变更事件. 由群主或机器人的操作触发. - */ - actual abstract val permission: MemberPermission - /** - * 群名片. 可能为空. - * - * 管理员和群主都可修改任何人(包括群主)的群名片. - * - * 在修改时将会异步上传至服务器. - * - * @see [nameCardOrNick] 获取非空群名片或昵称 - * - * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. - * @throws PermissionDeniedException 无权限修改时 - */ - actual abstract var nameCard: String - /** - * 群头衔. - * - * 仅群主可以修改群头衔. - * - * 在修改时将会异步上传至服务器. - * - * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. - * @throws PermissionDeniedException 无权限修改时 - */ - actual abstract var specialTitle: String - /** - * 被禁言剩余时长. 单位为秒. - * - * @see isMuted 判断改成员是否处于禁言状态 - * @see mute 设置禁言 - * @see unmute 取消禁言 - */ - actual abstract val muteTimeRemaining: Int - - /** - * 禁言. - * - * QQ 中最小操作和显示的时间都是一分钟. - * 机器人可以实现精确到秒, 会被客户端显示为 1 分钟但不影响实际禁言时间. - * - * 管理员可禁言成员, 群主可禁言管理员和群员. - * - * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常. - * @return 机器人无权限时返回 `false` - * - * @see Int.minutesToSeconds - * @see Int.hoursToSeconds - * @see Int.daysToSeconds - * - * @see MemberMuteEvent 成员被禁言事件 - * @throws PermissionDeniedException 无权限修改时 - */ - @JvmSynthetic - actual abstract suspend fun mute(durationSeconds: Int) - - /** - * 解除禁言. - * - * 管理员可解除成员的禁言, 群主可解除管理员和群员的禁言. - * - * @see MemberUnmuteEvent 成员被取消禁言事件. - * @throws PermissionDeniedException 无权限修改时 - */ - @JvmSynthetic - actual abstract suspend fun unmute() - - /** - * 踢出该成员. - * - * 管理员可踢出成员, 群主可踢出管理员和群员. - * - * @see MemberLeaveEvent.Kick 成员被踢出事件. - * @throws PermissionDeniedException 无权限修改时 - */ - @JvmSynthetic - actual abstract suspend fun kick(message: String) - - /** - * 向这个对象发送消息. - * - * 单条消息最大可发送 4500 字符或 50 张图片. - * - * @see FriendMessageSendEvent 发送好友信息事件, cancellable - * @see GroupMessageSendEvent 发送群消息事件. cancellable - * - * @throws EventCancelledException 当发送消息事件被取消时抛出 - * @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出 - * @throws MessageTooLargeException 当消息过长时抛出 - * - * @return 消息回执. 可进行撤回 ([MessageReceipt.recall]) - */ - @JvmSynthetic - actual abstract override suspend fun sendMessage(message: Message): MessageReceipt<Member> - - /** - * 当且仅当 `[other] is [Member] && [other].id == this.id && [other].group == this.group` 时为 true - */ - actual abstract override fun equals(other: Any?): Boolean - - /** - * @return `bot.hashCode() * 31 + id.hashCode()` - */ - actual abstract override fun hashCode(): Int - -} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/PermissionDeniedException.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/PermissionDeniedException.kt deleted file mode 100644 index 01ff0cef3..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/PermissionDeniedException.kt +++ /dev/null @@ -1,9 +0,0 @@ -package net.mamoe.mirai.contact - -/** - * 权限不足 - */ // 不要删除多平台结构 -actual class PermissionDeniedException : IllegalStateException { - actual constructor() : super("Permission denied") - actual constructor(message: String?) : super(message) -} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt index 249cec608..ff0df3075 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessagePacket.kt @@ -16,7 +16,8 @@ import kotlinx.io.core.Input import kotlinx.io.core.Output import kotlinx.io.core.use import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.Friend +import net.mamoe.mirai.contact.User import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiInternalAPI @@ -38,7 +39,7 @@ import java.net.URL replaceWith = ReplaceWith("ContactMessage", "net.mamoe.mirai.message.ContactMessage") ) @OptIn(MiraiInternalAPI::class, MiraiExperimentalAPI::class) -actual abstract class MessagePacket<TSender : QQ, TSubject : Contact> actual constructor() : +actual abstract class MessagePacket<TSender : User, TSubject : Contact> actual constructor() : MessagePacketBase<TSender, TSubject>() { // region 上传图片 @JvmSynthetic