mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-03 03:54:45 +08:00
[core] Support friend group (#2113)
* feat: support friend group * remove unnecessary modifications * toByteArray2 * support friendGroup, with api dump * support rename, with api dump * modify as required * modify as required * reverse * doc * FriendGroups * api dump * modify as required * fix CI * FriendGroup sync notice * api dump * modify as required * immutable * add friends: ContactList in FriendGroup * more sync notice * modify log content * Change `FriendGroup.friends` to `Collection<Friend>` * Fix `FriendGroup.friends.isEmpty()` * modified as require, untested * del count and online count in info * change import * fix missing import * set @since 2.13 and modified as required * modified as required * modified as required * doc * change friendGroupId type to Int? * api dumped * change friendGroupId type to Int? * introduce null to friendGroupId * modified as required * chore * api dump * chore: remark * change int? to int * api dump * Update mirai-core-api/src/commonMain/kotlin/data/FriendGroups.kt Co-authored-by: Him188 <Him188@mamoe.net> * Move FriendGroup and FriendGroups to contact.friendgroup * Make `Friend.friendGroup` not null * add FriendGroups.default for default group * Redesign FriendGroup interface Co-authored-by: Karlatemp <kar@kasukusakura.com> Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
parent
eb892da093
commit
fea1d28488
@ -15,6 +15,7 @@ public abstract interface class net/mamoe/mirai/Bot : kotlinx/coroutines/Corouti
|
||||
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
||||
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
||||
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
||||
public abstract fun getFriendGroups ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroups;
|
||||
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
||||
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
||||
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
||||
@ -354,6 +355,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 getFriendGroup ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
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;
|
||||
@ -908,6 +910,27 @@ public abstract interface class net/mamoe/mirai/contact/file/RemoteFiles {
|
||||
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroup {
|
||||
public fun delete ()Z
|
||||
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun getCount ()I
|
||||
public abstract fun getFriends ()Ljava/util/Collection;
|
||||
public abstract fun getId ()I
|
||||
public abstract fun getName ()Ljava/lang/String;
|
||||
public fun moveIn (Lnet/mamoe/mirai/contact/Friend;)Z
|
||||
public abstract fun moveIn (Lnet/mamoe/mirai/contact/Friend;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun renameTo (Ljava/lang/String;)Z
|
||||
public abstract fun renameTo (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroups {
|
||||
public abstract fun asCollection ()Ljava/util/Collection;
|
||||
public fun create (Ljava/lang/String;)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
public abstract fun create (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun get (I)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
public fun getDefault ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
||||
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
||||
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
||||
@ -962,6 +985,7 @@ public abstract interface class net/mamoe/mirai/contact/roaming/RoamingSupported
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
||||
public abstract fun getFriendGroupId ()I
|
||||
public abstract fun getNick ()Ljava/lang/String;
|
||||
public abstract fun getRemark ()Ljava/lang/String;
|
||||
public abstract fun getUin ()J
|
||||
@ -970,9 +994,11 @@ public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mira
|
||||
|
||||
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
||||
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
||||
public fun getFriendGroupId ()I
|
||||
public fun getNick ()Ljava/lang/String;
|
||||
public fun getRemark ()Ljava/lang/String;
|
||||
public fun getUin ()J
|
||||
public fun setFriendGroupId (I)V
|
||||
public fun setNick (Ljava/lang/String;)V
|
||||
public fun setRemark (Ljava/lang/String;)V
|
||||
}
|
||||
@ -1688,6 +1714,7 @@ public abstract interface class net/mamoe/mirai/data/UserInfo {
|
||||
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
||||
public abstract fun getAge ()I
|
||||
public abstract fun getEmail ()Ljava/lang/String;
|
||||
public abstract fun getFriendGroupId ()I
|
||||
public abstract fun getNickname ()Ljava/lang/String;
|
||||
public abstract fun getQLevel ()I
|
||||
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
||||
|
@ -15,6 +15,7 @@ public abstract interface class net/mamoe/mirai/Bot : kotlinx/coroutines/Corouti
|
||||
public abstract fun getConfiguration ()Lnet/mamoe/mirai/utils/BotConfiguration;
|
||||
public abstract fun getEventChannel ()Lnet/mamoe/mirai/event/EventChannel;
|
||||
public fun getFriend (J)Lnet/mamoe/mirai/contact/Friend;
|
||||
public abstract fun getFriendGroups ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroups;
|
||||
public fun getFriendOrFail (J)Lnet/mamoe/mirai/contact/Friend;
|
||||
public abstract fun getFriends ()Lnet/mamoe/mirai/contact/ContactList;
|
||||
public fun getGroup (J)Lnet/mamoe/mirai/contact/Group;
|
||||
@ -354,6 +355,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 getFriendGroup ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
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;
|
||||
@ -908,6 +910,27 @@ public abstract interface class net/mamoe/mirai/contact/file/RemoteFiles {
|
||||
public static synthetic fun uploadNewFile$suspendImpl (Lnet/mamoe/mirai/contact/file/RemoteFiles;Ljava/lang/String;Lnet/mamoe/mirai/utils/ExternalResource;Lnet/mamoe/mirai/utils/ProgressionCallback;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroup {
|
||||
public fun delete ()Z
|
||||
public abstract fun delete (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun getCount ()I
|
||||
public abstract fun getFriends ()Ljava/util/Collection;
|
||||
public abstract fun getId ()I
|
||||
public abstract fun getName ()Ljava/lang/String;
|
||||
public fun moveIn (Lnet/mamoe/mirai/contact/Friend;)Z
|
||||
public abstract fun moveIn (Lnet/mamoe/mirai/contact/Friend;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public fun renameTo (Ljava/lang/String;)Z
|
||||
public abstract fun renameTo (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/friendgroup/FriendGroups {
|
||||
public abstract fun asCollection ()Ljava/util/Collection;
|
||||
public fun create (Ljava/lang/String;)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
public abstract fun create (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||
public abstract fun get (I)Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
public fun getDefault ()Lnet/mamoe/mirai/contact/friendgroup/FriendGroup;
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/contact/roaming/RoamingMessage {
|
||||
public fun getBot ()Lnet/mamoe/mirai/Bot;
|
||||
public abstract fun getContact ()Lnet/mamoe/mirai/contact/Contact;
|
||||
@ -962,6 +985,7 @@ public abstract interface class net/mamoe/mirai/contact/roaming/RoamingSupported
|
||||
}
|
||||
|
||||
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
|
||||
public abstract fun getFriendGroupId ()I
|
||||
public abstract fun getNick ()Ljava/lang/String;
|
||||
public abstract fun getRemark ()Ljava/lang/String;
|
||||
public abstract fun getUin ()J
|
||||
@ -970,9 +994,11 @@ public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mira
|
||||
|
||||
public class net/mamoe/mirai/data/FriendInfoImpl : net/mamoe/mirai/data/FriendInfo {
|
||||
public fun <init> (JLjava/lang/String;Ljava/lang/String;)V
|
||||
public fun getFriendGroupId ()I
|
||||
public fun getNick ()Ljava/lang/String;
|
||||
public fun getRemark ()Ljava/lang/String;
|
||||
public fun getUin ()J
|
||||
public fun setFriendGroupId (I)V
|
||||
public fun setNick (Ljava/lang/String;)V
|
||||
public fun setRemark (Ljava/lang/String;)V
|
||||
}
|
||||
@ -1688,6 +1714,7 @@ public abstract interface class net/mamoe/mirai/data/UserInfo {
|
||||
public abstract interface class net/mamoe/mirai/data/UserProfile {
|
||||
public abstract fun getAge ()I
|
||||
public abstract fun getEmail ()Ljava/lang/String;
|
||||
public abstract fun getFriendGroupId ()I
|
||||
public abstract fun getNickname ()Ljava/lang/String;
|
||||
public abstract fun getQLevel ()I
|
||||
public abstract fun getSex ()Lnet/mamoe/mirai/data/UserProfile$Sex;
|
||||
|
@ -15,6 +15,7 @@ package net.mamoe.mirai
|
||||
import kotlinx.coroutines.*
|
||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroups
|
||||
import net.mamoe.mirai.event.EventChannel
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.message.action.BotNudge
|
||||
@ -112,6 +113,13 @@ public interface Bot : CoroutineScope, ContactOrBot, UserOrBot {
|
||||
*/
|
||||
public val friends: ContactList<Friend>
|
||||
|
||||
/**
|
||||
* 全部的好友分组
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public val friendGroups: FriendGroups
|
||||
|
||||
|
||||
/**
|
||||
* 以 [对方 QQ 号码][id] 获取一个好友对象, 在获取失败时返回 `null`.
|
||||
|
@ -15,6 +15,7 @@ package net.mamoe.mirai.contact
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||
import net.mamoe.mirai.contact.roaming.RoamingSupported
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
@ -38,6 +39,14 @@ import net.mamoe.mirai.utils.NotStableForInheritance
|
||||
@NotStableForInheritance
|
||||
public interface Friend : User, CoroutineScope, AudioSupported, RoamingSupported {
|
||||
|
||||
/**
|
||||
* 该好友所在的好友分组
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public val friendGroup: FriendGroup
|
||||
|
||||
|
||||
/**
|
||||
* 备注信息
|
||||
*
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.contact.friendgroup
|
||||
|
||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.utils.NotStableForInheritance
|
||||
|
||||
/**
|
||||
* 一个好友分组.
|
||||
* 可能同时存在多个相同[名称][name]的分组, 但是每个分组的 [id] 都是唯一的.
|
||||
*
|
||||
*
|
||||
* 要获取一个分组, 可使用 [get] 根据 [ID][FriendGroup.id] 获取, 或者使用 [asCollection] 获取全部分组列表.
|
||||
* 也可以通过 [Friend.friendGroup] 获取一个好友所在的分组.
|
||||
*
|
||||
* 在每次登录会话中, [FriendGroup] 的实例是依据 [id] 唯一的. 存在于同一个分组中的多个好友的 [Friend.friendGroup] 会返回相同的 [FriendGroup] 实例.
|
||||
* 但当 bot 重新登录后, 实例可能变化.
|
||||
*
|
||||
* @see FriendGroups
|
||||
* @since 2.13
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
@NotStableForInheritance
|
||||
public interface FriendGroup {
|
||||
/**
|
||||
* 好友分组 ID
|
||||
*/
|
||||
public val id: Int
|
||||
|
||||
/**
|
||||
* 好友分组名
|
||||
*/
|
||||
public val name: String
|
||||
|
||||
/**
|
||||
* 好友分组内好友数量
|
||||
*/
|
||||
public val count: Int
|
||||
|
||||
/**
|
||||
* 属于本分组的好友集合
|
||||
*/
|
||||
public val friends: Collection<Friend>
|
||||
|
||||
/**
|
||||
* 更改好友分组名称.
|
||||
*
|
||||
* 允许存在同名分组.
|
||||
* 当操作成时返回 `true`; 当分组不存在时返回 `false`; 如果因为其他原因造成的改名失败时会抛出 [IllegalStateException]
|
||||
*/
|
||||
public suspend fun renameTo(newName: String): Boolean
|
||||
|
||||
/**
|
||||
* 把一名好友移动至本分组内.
|
||||
*
|
||||
* 当远程分组不存在时会自动移动该好友到 ID 为 0 的默认好友分组.
|
||||
* 当操作成功时返回 `true`; 当分组不存在 (如已经在远程被删除) 时返回 `false`; 因为其他原因移动不成功时抛出 [IllegalStateException].
|
||||
*/
|
||||
public suspend fun moveIn(friend: Friend): Boolean
|
||||
|
||||
/**
|
||||
* 删除本分组.
|
||||
*
|
||||
* 删除后组内全部好友移动至 ID 为 0 的默认好友分组, 本分组的好友列表会被清空.
|
||||
* 当操作成功时返回 `true`; 当分组不存在或试图删除 ID 为 0 的默认好友分组时返回 `false`;
|
||||
* 因为其他原因删除不成功时抛出 [IllegalStateException].
|
||||
*/
|
||||
public suspend fun delete(): Boolean
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.contact.friendgroup
|
||||
|
||||
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
|
||||
import net.mamoe.mirai.utils.NotStableForInheritance
|
||||
|
||||
/**
|
||||
* 好友分组列表 (管理器).
|
||||
* 允许存在重复名称的分组, 因此依赖于 name 判断不可靠, 需要依赖 ID 判断.
|
||||
*
|
||||
* @see FriendGroup
|
||||
* @since 2.13
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
@NotStableForInheritance
|
||||
public interface FriendGroups {
|
||||
/**
|
||||
* 获取 [ID][FriendGroup.id] 为 `0` 的默认分组 ("我的好友").
|
||||
*/
|
||||
public val default: FriendGroup get() = get(0) ?: error("Internal error: could not find FriendGroup with id = 0.")
|
||||
|
||||
/**
|
||||
* 新建一个好友分组.
|
||||
*
|
||||
* 允许名称重复, 当新建一个已存在名称的分组时, 服务器会返回一个拥有重复名字的新分组;
|
||||
* 当因为其他原因创建不成功时抛出 [IllegalStateException].
|
||||
*
|
||||
* 提示: 要删除一个好友分组, 使用 [FriendGroup.delete].
|
||||
*/
|
||||
public suspend fun create(name: String): FriendGroup
|
||||
|
||||
/**
|
||||
* 获取指定 ID 的好友分组, 不存在时返回 `null`
|
||||
*/
|
||||
public operator fun get(id: Int): FriendGroup?
|
||||
|
||||
/**
|
||||
* 获取包含全部 [FriendGroup] 的 [Collection]. 返回的 [Collection] 只可读取.
|
||||
*
|
||||
* 此方法快速返回, 不会在调用时实例化新的 [Collection] 对象.
|
||||
* 返回的 [Collection] 是对缓存的引用, 会随着服务器通知和机器人操作 (如 [create]) 变化.
|
||||
*/
|
||||
public fun asCollection(): Collection<FriendGroup>
|
||||
}
|
@ -18,6 +18,8 @@ public interface FriendInfo : UserInfo {
|
||||
public override val nick: String
|
||||
|
||||
public override var remark: String
|
||||
|
||||
public val friendGroupId: Int
|
||||
}
|
||||
|
||||
|
||||
@ -32,4 +34,6 @@ public open class FriendInfoImpl(
|
||||
override val uin: Long,
|
||||
override var nick: String,
|
||||
override var remark: String,
|
||||
) : FriendInfo
|
||||
) : FriendInfo {
|
||||
override var friendGroupId: Int = 0
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* 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.
|
||||
* 此源代码的使用受 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
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.data
|
||||
@ -27,6 +27,13 @@ public interface UserProfile {
|
||||
public val qLevel: Int
|
||||
public val sex: Sex
|
||||
|
||||
/**
|
||||
* 好友分组 ID, 在非好友情况下或者位于默认分组情况下为 `0`
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public val friendGroupId: Int
|
||||
|
||||
/**
|
||||
* 个性签名
|
||||
*/
|
||||
|
@ -100,7 +100,7 @@ internal abstract class AbstractBot constructor(
|
||||
final override val strangers: ContactList<StrangerImpl> = ContactList()
|
||||
|
||||
final override val asFriend: FriendImpl by lazy {
|
||||
Mirai.newFriend(this, FriendInfoImpl(uin, "", "")).cast()
|
||||
Mirai.newFriend(this, FriendInfoImpl(uin, "", "", 0)).cast()
|
||||
} // nick is initialized later on login
|
||||
final override val asStranger: StrangerImpl by lazy {
|
||||
Mirai.newStranger(this, StrangerInfoImpl(bot.id, bot.nick)).cast()
|
||||
|
@ -599,7 +599,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
if (!accept) return
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
bot.friends.delegate.add(newFriend(bot, FriendInfoImpl(fromId, fromNick, "")))
|
||||
bot.friends.delegate.add(newFriend(bot, FriendInfoImpl(fromId, fromNick, "", 0)))
|
||||
}
|
||||
|
||||
override suspend fun solveBotInvitedJoinGroupRequestEvent(
|
||||
|
@ -16,6 +16,7 @@ import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.event.events.BotOnlineEvent
|
||||
import net.mamoe.mirai.event.events.BotReloginEvent
|
||||
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupsImpl
|
||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||
import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate
|
||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||
@ -44,6 +45,7 @@ import net.mamoe.mirai.internal.network.notice.group.GroupMessageProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.group.GroupNotificationProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.group.GroupOrMemberListNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.group.GroupRecallProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.FriendGroupNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.FriendNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.OtherClientNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.priv.PrivateMessageProcessor
|
||||
@ -71,6 +73,8 @@ internal open class QQAndroidBot constructor(
|
||||
configuration: BotConfiguration,
|
||||
) : AbstractBot(configuration, account.id) {
|
||||
override val bot: QQAndroidBot get() = this
|
||||
override val friendGroups: FriendGroupsImpl by lazy { FriendGroupsImpl(this) }
|
||||
|
||||
val client get() = components[SsoProcessor].client
|
||||
|
||||
override fun close(cause: Throwable?) {
|
||||
@ -191,6 +195,7 @@ internal open class QQAndroidBot constructor(
|
||||
GroupOrMemberListNoticeProcessor(pipelineLogger.subLogger("GroupOrMemberListNoticeProcessor")),
|
||||
GroupMessageProcessor(pipelineLogger.subLogger("GroupMessageProcessor")),
|
||||
GroupNotificationProcessor(pipelineLogger.subLogger("GroupNotificationProcessor")),
|
||||
FriendGroupNoticeProcessor(pipelineLogger.subLogger("FriendGroupNoticeProcessor")),
|
||||
PrivateMessageProcessor(),
|
||||
OtherClientNoticeProcessor(),
|
||||
GroupRecallProcessor(),
|
||||
|
@ -14,11 +14,11 @@
|
||||
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||
import net.mamoe.mirai.contact.roaming.RoamingMessages
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
|
||||
@ -53,7 +53,8 @@ internal fun net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo.toMir
|
||||
FriendInfoImpl(
|
||||
friendUin,
|
||||
nick,
|
||||
remark
|
||||
remark,
|
||||
groupId.toInt(),
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
@ -83,6 +84,9 @@ internal class FriendImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override val friendGroup: FriendGroup
|
||||
get() = bot.friendGroups[info.friendGroupId] ?: bot.friendGroups[0]!!
|
||||
|
||||
private val messageProtocolStrategy: MessageProtocolStrategy<FriendImpl> = FriendMessageProtocolStrategy(this)
|
||||
|
||||
override suspend fun delete() {
|
||||
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.contact.friendgroup
|
||||
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.FriendImpl
|
||||
import net.mamoe.mirai.internal.contact.impl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal inline fun FriendGroup.impl(): FriendGroupImpl {
|
||||
contract {
|
||||
returns() implies (this@impl is FriendGroupImpl)
|
||||
}
|
||||
check(this is FriendGroupImpl) { "A FriendGroup instance is not instance of FriendGroupImpl. Your instance: ${this::class.qualifiedName}" }
|
||||
return this
|
||||
}
|
||||
|
||||
internal class FriendGroupImpl constructor(
|
||||
val bot: QQAndroidBot,
|
||||
val info: FriendGroupInfo
|
||||
) : FriendGroup {
|
||||
override val id: Int by info::groupId
|
||||
|
||||
override var name: String by info::groupName
|
||||
override val count: Int
|
||||
get() = friends.size
|
||||
override val friends: Collection<Friend> = object : AbstractCollection<Friend>() {
|
||||
override val size: Int
|
||||
get() = bot.friends.count { it.impl().info.friendGroupId == id }
|
||||
|
||||
private val delegateSequence = sequence<Friend> {
|
||||
bot.friends.forEach { friend ->
|
||||
friend.impl()
|
||||
if (friend.info.friendGroupId == id) {
|
||||
yield(friend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Friend> = delegateSequence.iterator()
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return bot.friends.none { it.impl().info.friendGroupId == id }
|
||||
}
|
||||
|
||||
override fun contains(element: Friend): Boolean {
|
||||
if (element !is FriendImpl) return false
|
||||
return element.info.friendGroupId == id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun renameTo(newName: String): Boolean {
|
||||
bot.network.sendAndExpect(FriendList.SetGroupReqPack.Rename(bot.client, newName, id)).let {
|
||||
if (it.result.toInt() == 1) {
|
||||
return false
|
||||
}
|
||||
check(it.isSuccess) {
|
||||
"Cannot rename friendGroup(id=$id) to $newName, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||
}
|
||||
}
|
||||
info.groupName = newName
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun moveIn(friend: Friend): Boolean {
|
||||
bot.network.sendAndExpect(FriendList.MoveGroupMemReqPack(bot.client, friend.id, id)).let {
|
||||
check(it.isSuccess) {
|
||||
"Cannot move friend to $this, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||
}
|
||||
}
|
||||
// 因为 MoveGroupMemReqPack 协议在测试里如果移动到不存在的分组,他会自动移动好友到 id = 0 的默认好友分组然后返回 result = 0
|
||||
val id = friend.queryProfile().friendGroupId
|
||||
friend.impl().info.friendGroupId = id
|
||||
if (id != this.id && id == 0) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun delete(): Boolean {
|
||||
bot.network.sendAndExpect(FriendList.SetGroupReqPack.Delete(bot.client, id)).let {
|
||||
if (it.result.toInt() == 1) {
|
||||
return false
|
||||
}
|
||||
check(it.isSuccess) {
|
||||
"Cannot delete friendGroup, code=${it.result.toInt()}, errStr=${it.errStr}"
|
||||
}
|
||||
}
|
||||
friends.forEach {
|
||||
it.impl().info.friendGroupId = 0
|
||||
}
|
||||
bot.friendGroups.friendGroups.remove(this)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "FriendGroup(id=$id, name=$name)"
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.contact.friendgroup
|
||||
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroup
|
||||
import net.mamoe.mirai.contact.friendgroup.FriendGroups
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.utils.ConcurrentLinkedDeque
|
||||
import net.mamoe.mirai.utils.asImmutable
|
||||
|
||||
internal class FriendGroupsImpl(
|
||||
val bot: QQAndroidBot
|
||||
) : FriendGroups {
|
||||
val friendGroups = ConcurrentLinkedDeque<FriendGroupImpl>()
|
||||
private val friendGroupsImmutable by lazy { friendGroups.asImmutable() }
|
||||
|
||||
override suspend fun create(name: String): FriendGroup {
|
||||
val resp = bot.network.sendAndExpect(FriendList.SetGroupReqPack.New(bot.client, name))
|
||||
check(resp.isSuccess) {
|
||||
"Cannot create friendGroup, code=${resp.result.toInt()}, errStr=${resp.errStr}"
|
||||
}
|
||||
return FriendGroupImpl(bot, FriendGroupInfo(resp.groupId, name)).apply { friendGroups.add(this) }
|
||||
}
|
||||
|
||||
override fun get(id: Int): FriendGroup? = friendGroups.firstOrNull { it.id == id }
|
||||
|
||||
override fun asCollection(): Collection<FriendGroup> = friendGroupsImmutable
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.contact.info
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
internal data class FriendGroupInfo(
|
||||
val groupId: Int,
|
||||
var groupName: String,
|
||||
// val friendCount: Int,
|
||||
// val onlineFriendCount: Int
|
||||
)
|
@ -18,8 +18,9 @@ internal data class FriendInfoImpl(
|
||||
override val uin: Long,
|
||||
override var nick: String,
|
||||
override var remark: String,
|
||||
override var friendGroupId: Int
|
||||
) : FriendInfo {
|
||||
companion object {
|
||||
fun FriendInfo.impl() = if (this is FriendInfoImpl) this else FriendInfoImpl(uin, nick, remark)
|
||||
fun FriendInfo.impl() = if (this is FriendInfoImpl) this else FriendInfoImpl(uin, nick, remark, friendGroupId)
|
||||
}
|
||||
}
|
@ -23,10 +23,8 @@ import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.StrangerImpl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupImpl
|
||||
import net.mamoe.mirai.internal.contact.info.*
|
||||
import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||
@ -160,6 +158,38 @@ internal class ContactUpdaterImpl(
|
||||
return friendInfos
|
||||
}
|
||||
|
||||
suspend fun refreshFriendGroupList(): List<FriendGroupImpl> {
|
||||
logger.info { "Start loading friendGroup list..." }
|
||||
val friendGroupInfos = mutableListOf<FriendGroupImpl>()
|
||||
|
||||
var count = 0
|
||||
var total: Short
|
||||
while (true) {
|
||||
val data = bot.network.sendAndExpect(
|
||||
FriendList.GetFriendGroupList(bot.client, 0, 0, count, 150)
|
||||
)
|
||||
|
||||
total = data.totoalGroupCount
|
||||
|
||||
for (jceInfo in data.groupList) {
|
||||
friendGroupInfos.add(
|
||||
FriendGroupImpl(
|
||||
bot, FriendGroupInfo(
|
||||
jceInfo.groupId.toInt(),
|
||||
jceInfo.groupname
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
count += data.groupList.size
|
||||
logger.verbose { "Loading friendGroup list: ${count}/${total}" }
|
||||
if (count >= total) break
|
||||
}
|
||||
logger.info { "Successfully loaded friendGroup list: $count in total" }
|
||||
return friendGroupInfos
|
||||
}
|
||||
|
||||
val list = if (friendListCache?.isValid(registerResp) == true) {
|
||||
val list = friendListCache.list
|
||||
logger.info { "Loaded ${list.size} friends from local cache." }
|
||||
@ -178,11 +208,13 @@ internal class ContactUpdaterImpl(
|
||||
}
|
||||
}
|
||||
|
||||
bot.friendGroups.friendGroups.clear()
|
||||
bot.friendGroups.friendGroups.addAll(refreshFriendGroupList())
|
||||
|
||||
for (friendInfoImpl in list) {
|
||||
bot.addNewFriendAndRemoveStranger(friendInfoImpl)
|
||||
}
|
||||
|
||||
|
||||
initFriendOk = true
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.notice.priv
|
||||
|
||||
import net.mamoe.mirai.internal.contact.friendgroup.FriendGroupImpl
|
||||
import net.mamoe.mirai.internal.contact.friendgroup.impl
|
||||
import net.mamoe.mirai.internal.contact.impl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendGroupInfo
|
||||
import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.components.NoticePipelineContext
|
||||
import net.mamoe.mirai.internal.network.notice.NewContactSupport
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.context
|
||||
import net.mamoe.mirai.utils.error
|
||||
import net.mamoe.mirai.utils.warning
|
||||
|
||||
internal class FriendGroupNoticeProcessor(
|
||||
private val logger: MiraiLogger,
|
||||
) : MixedNoticeProcessor(), NewContactSupport {
|
||||
|
||||
override suspend fun NoticePipelineContext.processImpl(data: MsgType0x210) = data.context {
|
||||
when (data.uSubMsgType) {
|
||||
0x27L -> {
|
||||
val body = vProtobuf.loadAs(Submsgtype0x27.SubMsgType0x27.SubMsgType0x27MsgBody.serializer())
|
||||
for (msgModInfo in body.msgModInfos) {
|
||||
markAsConsumed(msgModInfo)
|
||||
when {
|
||||
msgModInfo.msgModFriendGroup != null -> handleFriendGroupChanged(
|
||||
msgModInfo.msgModFriendGroup, logger
|
||||
)
|
||||
msgModInfo.msgModGroupName != null -> handleFriendGroupNameChanged(
|
||||
msgModInfo.msgModGroupName, logger
|
||||
)
|
||||
msgModInfo.msgDelGroup != null -> handleDelGroup(msgModInfo.msgDelGroup, logger)
|
||||
msgModInfo.msgAddGroup != null -> handleAddGroup(msgModInfo.msgAddGroup)
|
||||
else -> markNotConsumed(msgModInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun NoticePipelineContext.handleAddGroup(
|
||||
addGroup: Submsgtype0x27.SubMsgType0x27.AddGroup
|
||||
) {
|
||||
bot.friendGroups.friendGroups.add(
|
||||
FriendGroupImpl(
|
||||
bot,
|
||||
FriendGroupInfo(addGroup.groupid, addGroup.groupname.decodeToString())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun NoticePipelineContext.handleDelGroup(
|
||||
delGroup: Submsgtype0x27.SubMsgType0x27.DelGroup, logger: MiraiLogger
|
||||
) {
|
||||
bot.friendGroups[delGroup.groupid]?.let { friendGroup ->
|
||||
friendGroup.friends.forEach {
|
||||
it.impl().info.friendGroupId = 0
|
||||
}
|
||||
bot.friendGroups.friendGroups.remove(friendGroup)
|
||||
} ?: let {
|
||||
logger.warning { "Detected friendGroup(id=${delGroup.groupid}) was removed but it isn't available in bot's friendGroups list" }
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun NoticePipelineContext.handleFriendGroupNameChanged(
|
||||
modFriendGroup: Submsgtype0x27.SubMsgType0x27.ModGroupName, logger: MiraiLogger
|
||||
) {
|
||||
bot.friendGroups[modFriendGroup.groupid]?.let {
|
||||
it.impl().name = modFriendGroup.groupname.decodeToString()
|
||||
} ?: let {
|
||||
logger.warning { "Detected friendGroup(id=${modFriendGroup.groupid}) was renamed but it cannot be found in bot's friendGroups list" }
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun NoticePipelineContext.handleFriendGroupChanged(
|
||||
modFriendGroup: Submsgtype0x27.SubMsgType0x27.ModFriendGroup,
|
||||
logger: MiraiLogger
|
||||
) {
|
||||
modFriendGroup.msgFrdGroup.forEach { body ->
|
||||
val friend = bot.getFriend(body.fuin) ?: let {
|
||||
logger.error { "Detected friend(id=${body.fuin}) was moved to friendGroup(id=${body.uint32NewGroupId}) but friend not found in bot's friends list" }
|
||||
return
|
||||
}
|
||||
if (friend.impl().info.friendGroupId == body.uint32NewGroupId.first()) return@forEach
|
||||
friend.info.friendGroupId = body.uint32NewGroupId.first()
|
||||
}
|
||||
}
|
||||
}
|
@ -264,6 +264,7 @@ internal class FriendNoticeProcessor(
|
||||
uin = body.msgAddFrdNotify.fuin,
|
||||
nick = body.msgAddFrdNotify.fuinNick,
|
||||
remark = "",
|
||||
friendGroupId = 0,
|
||||
)
|
||||
|
||||
val removed = bot.removeStranger(info.uin)
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 MovGroupMemReq(
|
||||
@JvmField @TarsId(0) val uin: Long = 0L,
|
||||
@JvmField @TarsId(1) val reqtype: Byte = 0,
|
||||
@JvmField @TarsId(2) val vecBody: ByteArray? = null
|
||||
) : JceStruct
|
||||
|
||||
@Serializable
|
||||
internal class MovGroupMemResp(
|
||||
@JvmField @TarsId(0) val uin: Long = 0L,
|
||||
@JvmField @TarsId(1) val reqtype: Byte = 0,
|
||||
@JvmField @TarsId(2) val result: Byte = 0,
|
||||
@JvmField @TarsId(3) val errorString: String = ""
|
||||
) : JceStruct
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 SetGroupReq(
|
||||
@JvmField @TarsId(0) val reqtype: Int = 0,
|
||||
@JvmField @TarsId(1) val uin: Long = 0L,
|
||||
@JvmField @TarsId(2) val vecBody: ByteArray? = null
|
||||
) : JceStruct
|
||||
|
||||
@Serializable
|
||||
internal class SetGroupResp(
|
||||
@JvmField @TarsId(0) val reqtype: Byte = 0,
|
||||
@JvmField @TarsId(1) val result: Byte = 0,
|
||||
@JvmField @TarsId(2) val vecBody: ByteArray? = null,
|
||||
@JvmField @TarsId(3) val errorString: String = ""
|
||||
) : JceStruct
|
@ -144,6 +144,8 @@ internal object KnownPacketFactories {
|
||||
FriendList.DelFriend,
|
||||
FriendList.GetTroopListSimplify,
|
||||
FriendList.GetTroopMemberList,
|
||||
FriendList.SetGroupReqPack,
|
||||
FriendList.MoveGroupMemReqPack,
|
||||
ImgStore.GroupPicUp,
|
||||
PttStore.GroupPttUp,
|
||||
PttStore.GroupPttDown,
|
||||
|
@ -20,11 +20,9 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.Vec0xd50
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Vec0xd6b
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.jceRequestSBuffer
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeJceStruct
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.*
|
||||
import net.mamoe.mirai.utils.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.utils.toByteArray
|
||||
|
||||
|
||||
internal class FriendList {
|
||||
@ -163,7 +161,10 @@ internal class FriendList {
|
||||
class Response(
|
||||
val selfInfo: FriendInfo?,
|
||||
val totalFriendCount: Short,
|
||||
val friendList: List<FriendInfo>
|
||||
val friendList: List<FriendInfo>,
|
||||
// for FriendGroup
|
||||
val groupList: List<GroupInfo>,
|
||||
val totoalGroupCount: Short
|
||||
) : Packet {
|
||||
override fun toString(): String = "FriendList.GetFriendGroupList.Response"
|
||||
}
|
||||
@ -177,7 +178,9 @@ internal class FriendList {
|
||||
return Response(
|
||||
res.stSelfInfo,
|
||||
res.totoalFriendCount,
|
||||
res.vecFriendInfo.orEmpty()
|
||||
res.vecFriendInfo.orEmpty(),
|
||||
res.vecGroupInfo.orEmpty(),
|
||||
res.totoalGroupCount ?: -1
|
||||
)
|
||||
}
|
||||
|
||||
@ -247,7 +250,7 @@ internal class FriendList {
|
||||
GetFriendListReq.serializer(),
|
||||
GetFriendListReq(
|
||||
reqtype = 3,
|
||||
ifReflush = if (friendListStartIndex <= 0) {
|
||||
ifReflush = if (friendListStartIndex + groupListStartIndex <= 0) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
@ -285,4 +288,118 @@ internal class FriendList {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// for FriendGroup
|
||||
internal object SetGroupReqPack : OutgoingPacketFactory<SetGroupReqPack.Response>("friendlist.SetGroupReq") {
|
||||
class Response(
|
||||
// Success: result == 0x00
|
||||
val result: Byte,
|
||||
val errStr: String,
|
||||
// groupId for delete
|
||||
val groupId: Int,
|
||||
val isSuccess: Boolean = result.toInt() == 0
|
||||
) : Packet {
|
||||
override fun toString(): String {
|
||||
return "SetGroupResp(isSuccess=$isSuccess,resultCode=$result, errString=$errStr, groupId=$groupId)"
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val pack = this.readUniPacket(SetGroupResp.serializer())
|
||||
return if (pack.result.toInt() == 0) {
|
||||
Response(pack.result, pack.errorString, pack.vecBody?.get(8)?.toInt() ?: -1)
|
||||
} else {
|
||||
Response(pack.result, pack.errorString, -1)
|
||||
}
|
||||
}
|
||||
|
||||
object New {
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient, groupName: String
|
||||
) = buildOutgoingUniPacket(client) {
|
||||
val arr = groupName.toByteArray()
|
||||
// maybe is constant
|
||||
val constant: Byte = 0x01
|
||||
writeJceRequestPacket(
|
||||
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||
funcName = "SetGroupReq",
|
||||
serializer = SetGroupReq.serializer(),
|
||||
body = SetGroupReq(0, client.uin, byteArrayOf(constant, arr.size.toByte()) + arr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object Rename {
|
||||
operator fun invoke(client: QQAndroidClient, newName: String, id: Int) = buildOutgoingUniPacket(client) {
|
||||
val arr = newName.toByteArray()
|
||||
writeJceRequestPacket(
|
||||
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||
funcName = "SetGroupReq",
|
||||
serializer = SetGroupReq.serializer(),
|
||||
body = SetGroupReq(1, client.uin, byteArrayOf(id.toByte(), arr.size.toByte()) + arr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object Delete {
|
||||
operator fun invoke(client: QQAndroidClient, id: Int) = buildOutgoingUniPacket(client) {
|
||||
writeJceRequestPacket(
|
||||
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||
funcName = "SetGroupReq",
|
||||
serializer = SetGroupReq.serializer(),
|
||||
body = SetGroupReq(2, client.uin, byteArrayOf(id.toByte()))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for FriendGroup
|
||||
internal object MoveGroupMemReqPack :
|
||||
OutgoingPacketFactory<MoveGroupMemReqPack.Response>("friendlist.MovGroupMemReq") {
|
||||
private fun Long.toByteArray2(): ByteArray {
|
||||
val arr = this.toByteArray()
|
||||
val index = arr.indexOfFirst { it.toInt() != 0 }
|
||||
return arr.sliceArray(index until arr.size)
|
||||
}
|
||||
|
||||
// 如果不成功会自动移动到id = 0的默认好友分组, result 还是会返回0
|
||||
class Response(
|
||||
// Success: result == 0x00
|
||||
val result: Byte,
|
||||
val errStr: String,
|
||||
val isSuccess: Boolean = result.toInt() == 0
|
||||
) : Packet {
|
||||
override fun toString(): String {
|
||||
return "MoveGroupMemReq(isSuccess=$isSuccess,resultCode=$result, errString=$errStr)"
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val pack = this.readUniPacket(MovGroupMemResp.serializer())
|
||||
return Response(pack.result, pack.errorString)
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
// friend id
|
||||
id: Long,
|
||||
// friend group id
|
||||
groupId: Int
|
||||
) = buildOutgoingUniPacket(client) {
|
||||
writeJceRequestPacket(
|
||||
servantName = "mqq.IMService.FriendListServiceServantObj",
|
||||
funcName = "MovGroupMemReq",
|
||||
serializer = MovGroupMemReq.serializer(),
|
||||
body = MovGroupMemReq(
|
||||
client.uin,
|
||||
0,
|
||||
byteArrayOf(
|
||||
0x01,
|
||||
0x00,
|
||||
(id.toByteArray2().size + 1).toByte()
|
||||
) + id.toByteArray2() + byteArrayOf(groupId.toByte(), 0x00, 0x00)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,9 +35,10 @@ internal data class UserProfileImpl(
|
||||
override val qLevel: Int,
|
||||
override val sex: UserProfile.Sex,
|
||||
override val sign: String,
|
||||
override val friendGroupId: Int,
|
||||
) : Packet, UserProfile {
|
||||
override fun toString(): String {
|
||||
return "UserProfile(nickname=$nickname, email=$email, age=$age, qLevel=$qLevel, sex=$sex, sign=$sign)"
|
||||
return "UserProfile(nickname=$nickname, email=$email, age=$age, qLevel=$qLevel, sex=$sex, sign=$sign, friendGroupId=$friendGroupId)"
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +119,8 @@ internal object SummaryCard {
|
||||
1 -> UserProfile.Sex.FEMALE
|
||||
else -> UserProfile.Sex.UNKNOWN
|
||||
},
|
||||
sign = sign
|
||||
sign = sign,
|
||||
friendGroupId = response.uFriendGroupId?.toInt() ?: 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ internal interface GroupExtensions {
|
||||
friends.delegate.add(friend)
|
||||
}
|
||||
|
||||
fun Bot.addFriend(id: Long, nick: String = "friend$id", remark: String = ""): FriendImpl {
|
||||
return FriendImpl(bot.cast(), bot.coroutineContext, FriendInfoImpl(id, nick, remark)).also {
|
||||
fun Bot.addFriend(id: Long, nick: String = "friend$id", remark: String = "", friendGroupId: Int = 0): FriendImpl {
|
||||
return FriendImpl(bot.cast(), bot.coroutineContext, FriendInfoImpl(id, nick, remark, friendGroupId)).also {
|
||||
friends.delegate.add(it)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user