Browse Source

[core] Support change friend remark (#2112)

* feat: support ChangeFriendName

* fix: register factory

[skip ci]

* rebase dev

* kdoc?

* api dump

* kdoc

* rebase dev

* remove unnecessary modification

* info::remark -> info.remark

* rebase dev

* api dump

* try to fix CI

* Add `@since` for `Friend.remark` setter

Co-authored-by: Him188 <[email protected]>
Eritque arcus 3 years ago
parent
commit
6b8c054948

+ 4 - 1
mirai-core-api/compatibility-validation/android/api/android.api

@@ -354,6 +354,7 @@ public abstract interface class net/mamoe/mirai/contact/FileSupported : net/mamo
 public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
 	public fun delete ()V
 	public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public abstract fun getRemark ()Ljava/lang/String;
 	public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
 	public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
 	public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/UserNudge;
@@ -362,6 +363,7 @@ public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/corouti
 	public fun sendMessage (Lnet/mamoe/mirai/message/data/Message;)Lnet/mamoe/mirai/message/MessageReceipt;
 	public abstract fun sendMessage (Lnet/mamoe/mirai/message/data/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static synthetic fun sendMessage$suspendImpl (Lnet/mamoe/mirai/contact/Friend;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public abstract fun setRemark (Ljava/lang/String;)V
 }
 
 public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/Contact, net/mamoe/mirai/contact/FileSupported {
@@ -2423,7 +2425,7 @@ public final class net/mamoe/mirai/event/events/FriendNickChangedEvent : net/mam
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet {
+public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/BroadcastControllable, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet {
 	public final fun component1 ()Lnet/mamoe/mirai/contact/Friend;
 	public final fun component2 ()Ljava/lang/String;
 	public final fun component3 ()Ljava/lang/String;
@@ -2433,6 +2435,7 @@ public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/ma
 	public fun getFriend ()Lnet/mamoe/mirai/contact/Friend;
 	public final fun getNewRemark ()Ljava/lang/String;
 	public final fun getOldRemark ()Ljava/lang/String;
+	public fun getShouldBroadcast ()Z
 	public fun hashCode ()I
 	public fun toString ()Ljava/lang/String;
 }

+ 4 - 1
mirai-core-api/compatibility-validation/jvm/api/jvm.api

@@ -354,6 +354,7 @@ public abstract interface class net/mamoe/mirai/contact/FileSupported : net/mamo
 public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/User, net/mamoe/mirai/contact/roaming/RoamingSupported {
 	public fun delete ()V
 	public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public abstract fun getRemark ()Ljava/lang/String;
 	public fun nudge ()Lnet/mamoe/mirai/message/action/FriendNudge;
 	public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
 	public synthetic fun nudge ()Lnet/mamoe/mirai/message/action/UserNudge;
@@ -362,6 +363,7 @@ public abstract interface class net/mamoe/mirai/contact/Friend : kotlinx/corouti
 	public fun sendMessage (Lnet/mamoe/mirai/message/data/Message;)Lnet/mamoe/mirai/message/MessageReceipt;
 	public abstract fun sendMessage (Lnet/mamoe/mirai/message/data/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public static synthetic fun sendMessage$suspendImpl (Lnet/mamoe/mirai/contact/Friend;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
+	public abstract fun setRemark (Ljava/lang/String;)V
 }
 
 public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/contact/AudioSupported, net/mamoe/mirai/contact/Contact, net/mamoe/mirai/contact/FileSupported {
@@ -2423,7 +2425,7 @@ public final class net/mamoe/mirai/event/events/FriendNickChangedEvent : net/mam
 	public fun toString ()Ljava/lang/String;
 }
 
-public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet {
+public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/event/BroadcastControllable, net/mamoe/mirai/event/events/FriendEvent, net/mamoe/mirai/event/events/FriendInfoChangeEvent, net/mamoe/mirai/internal/network/Packet {
 	public final fun component1 ()Lnet/mamoe/mirai/contact/Friend;
 	public final fun component2 ()Ljava/lang/String;
 	public final fun component3 ()Ljava/lang/String;
@@ -2433,6 +2435,7 @@ public final class net/mamoe/mirai/event/events/FriendRemarkChangeEvent : net/ma
 	public fun getFriend ()Lnet/mamoe/mirai/contact/Friend;
 	public final fun getNewRemark ()Ljava/lang/String;
 	public final fun getOldRemark ()Ljava/lang/String;
+	public fun getShouldBroadcast ()Z
 	public fun hashCode ()I
 	public fun toString ()Ljava/lang/String;
 }

+ 17 - 1
mirai-core-api/src/commonMain/kotlin/contact/Friend.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * 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.
@@ -34,8 +34,24 @@ import net.mamoe.mirai.utils.NotStableForInheritance
  *
  * @see FriendMessageEvent
  */
+@Suppress("RedundantSetter")
 @NotStableForInheritance
 public interface Friend : User, CoroutineScope, AudioSupported, RoamingSupported {
+
+    /**
+     * 备注信息
+     *
+     * 更改备注后会广播 [FriendRemarkChangeEvent]
+     *
+     * @see User.remarkOrNick
+     * @see FriendRemarkChangeEvent
+     */
+    override var remark: String
+        /**
+         * @since 2.13
+         */
+        set
+
     /**
      * 向这个对象发送消息.
      *

+ 5 - 1
mirai-core-api/src/commonMain/kotlin/event/events/friend.kt

@@ -22,6 +22,7 @@ import net.mamoe.mirai.contact.Friend
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.User
 import net.mamoe.mirai.event.AbstractEvent
+import net.mamoe.mirai.event.BroadcastControllable
 import net.mamoe.mirai.internal.event.VerboseEvent
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.utils.MiraiInternalApi
@@ -36,7 +37,10 @@ public data class FriendRemarkChangeEvent @MiraiInternalApi public constructor(
     public override val friend: Friend,
     public val oldRemark: String,
     public val newRemark: String,
-) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent
+) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent, BroadcastControllable {
+    override val shouldBroadcast: Boolean
+        get() = oldRemark != newRemark
+}
 
 /**
  * 成功添加了一个新好友的事件

+ 1 - 1
mirai-core/src/commonMain/kotlin/contact/AbstractMember.kt

@@ -25,7 +25,7 @@ internal sealed class AbstractMember(
     final override val info: MemberInfoImpl = memberInfo.cast()
 
     override var nick: String by info::nick
-    override var remark: String by info::remark
+    override val remark: String by info::remark
 
     override val nameCard: String get() = info.nameCard
     override val specialTitle: String get() = info.specialTitle

+ 16 - 1
mirai-core/src/commonMain/kotlin/contact/FriendImpl.kt

@@ -14,12 +14,16 @@
 
 package net.mamoe.mirai.internal.contact
 
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
 import io.ktor.utils.io.core.*
 import net.mamoe.mirai.LowLevelApi
 import net.mamoe.mirai.contact.Friend
 import net.mamoe.mirai.contact.roaming.RoamingMessages
+import net.mamoe.mirai.event.broadcast
 import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
 import net.mamoe.mirai.event.events.FriendMessagePreSendEvent
+import net.mamoe.mirai.event.events.FriendRemarkChangeEvent
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
 import net.mamoe.mirai.internal.contact.roaming.RoamingMessagesImplFriend
@@ -33,6 +37,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
 import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.audioCodec
 import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
+import net.mamoe.mirai.internal.network.protocol.packet.summarycard.ChangeFriendRemark
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
 import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
 import net.mamoe.mirai.message.MessageReceipt
@@ -66,7 +71,17 @@ internal class FriendImpl(
     override val info: FriendInfoImpl,
 ) : Friend, AbstractUser(bot, parentCoroutineContext, info) {
     override var nick: String by info::nick
-    override var remark: String by info::remark
+
+    override var remark: String
+        get() = info.remark
+        set(value) {
+            val old = info.remark
+            info.remark = value
+            launch {
+                bot.network.sendWithoutExpect(ChangeFriendRemark(bot.client, [email protected], value))
+                FriendRemarkChangeEvent(this@FriendImpl, old, value).broadcast()
+            }
+        }
 
     private val messageProtocolStrategy: MessageProtocolStrategy<FriendImpl> = FriendMessageProtocolStrategy(this)
 

+ 27 - 0
mirai-core/src/commonMain/kotlin/network/protocol/data/jce/ChangeFriendNameReq.kt

@@ -0,0 +1,27 @@
+/*
+ * 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.internal.network.protocol.data.jce
+
+import kotlinx.serialization.Serializable
+import net.mamoe.mirai.internal.utils.io.JceStruct
+import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
+import kotlin.jvm.JvmField
+
+
+@Serializable
+internal class ChangeFriendNameReq(
+    @JvmField @TarsId(0) val uFriendUin: Long = 0L,
+    @JvmField @TarsId(1) val cstrName: String = ""
+) : JceStruct
+
+@Serializable
+internal class ChangeFriendNameRes(
+    @JvmField @TarsId(0) val result: Byte = 0
+) : JceStruct

+ 2 - 0
mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt

@@ -26,6 +26,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.ConfigPushSvc
 import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat
 import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
 import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
+import net.mamoe.mirai.internal.network.protocol.packet.summarycard.ChangeFriendRemark
 import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard
 import net.mamoe.mirai.utils.DeprecatedSinceMirai
 import net.mamoe.mirai.utils.MiraiLoggerWithSwitch
@@ -170,6 +171,7 @@ internal object KnownPacketFactories {
         StrangerList.GetStrangerList,
         StrangerList.DelStranger,
         SummaryCard.ReqSummaryCard,
+        ChangeFriendRemark,
         MusicSharePacket,
         *FileManagement.factories
     )

+ 53 - 0
mirai-core/src/commonMain/kotlin/network/protocol/packet/summarycard/FriendRemark.kt

@@ -0,0 +1,53 @@
+/*
+ * 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.internal.network.protocol.packet.summarycard
+
+import io.ktor.utils.io.core.*
+import net.mamoe.mirai.internal.QQAndroidBot
+import net.mamoe.mirai.internal.network.Packet
+import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.protocol.data.jce.ChangeFriendNameReq
+import net.mamoe.mirai.internal.network.protocol.data.jce.ChangeFriendNameRes
+import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
+import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketWithRespType
+import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
+import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
+import net.mamoe.mirai.internal.utils.io.serialization.writeJceRequestPacket
+
+internal object ChangeFriendRemark :
+    OutgoingPacketFactory<ChangeFriendRemark.Response>("ProfileService.ChangeFriendName") {
+    class Response(val isSuccess: Boolean, val resultCode: Int) : Packet {
+        override fun toString(): String {
+            return "ProfileService.ChangeFriendName.Response(isSuccess=$isSuccess, resultCode=$resultCode)"
+        }
+    }
+
+    override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
+        val res = this.readUniPacket(ChangeFriendNameRes.serializer())
+        return Response(res.result == 0x0.toByte(), res.result.toInt())
+    }
+
+    operator fun invoke(
+        client: QQAndroidClient,
+        id: Long,
+        newRemark: String
+    ): OutgoingPacketWithRespType<Response> {
+        return buildOutgoingUniPacket(client) {
+            writeJceRequestPacket(
+                servantName = "KQQ.ProfileService.ProfileServantObj",
+                funcName = "ChangeFriendName",
+                name = "req",
+                serializer = ChangeFriendNameReq.serializer(),
+                body = ChangeFriendNameReq(id, newRemark)
+            )
+        }
+    }
+
+}