Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: essence message setting #2314

Merged
merged 19 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions mirai-core-api/compatibility-validation/android/api/android.api
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
public abstract fun getBotAsMember ()Lnet/mamoe/mirai/contact/NormalMember;
public fun getBotMuteRemaining ()I
public fun getBotPermission ()Lnet/mamoe/mirai/contact/MemberPermission;
public abstract fun getEssences ()Lnet/mamoe/mirai/contact/essence/Essences;
public abstract fun getId ()J
public abstract fun getMembers ()Lnet/mamoe/mirai/contact/ContactList;
public abstract fun getName ()Ljava/lang/String;
Expand Down Expand Up @@ -900,6 +901,30 @@ public final class net/mamoe/mirai/contact/announcement/OnlineAnnouncementKt {
public static final fun getBot (Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;)Lnet/mamoe/mirai/Bot;
}

public final class net/mamoe/mirai/contact/essence/EssenceMessageRecord {
public final fun getGroup ()Lnet/mamoe/mirai/contact/Group;
public final fun getOperator ()Lnet/mamoe/mirai/contact/NormalMember;
public final fun getOperatorId ()J
public final fun getOperatorNick ()Ljava/lang/String;
public final fun getOperatorTime ()I
public final fun getSender ()Lnet/mamoe/mirai/contact/NormalMember;
public final fun getSenderId ()J
public final fun getSenderNick ()Ljava/lang/String;
public final fun getSenderTime ()I
public final fun getSource ()Lnet/mamoe/mirai/message/data/MessageSource;
public final fun getSource (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun toString ()Ljava/lang/String;
}

public abstract interface class net/mamoe/mirai/contact/essence/Essences : net/mamoe/mirai/utils/Streamable {
public fun getPage (II)Ljava/util/List;
public abstract fun getPage (IILkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun remove (Lnet/mamoe/mirai/message/data/MessageSource;)V
public abstract fun remove (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun share (Lnet/mamoe/mirai/message/data/MessageSource;)Ljava/lang/String;
public abstract fun share (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class net/mamoe/mirai/contact/file/AbsoluteFile : net/mamoe/mirai/contact/file/AbsoluteFileFolder {
public abstract fun getExpiryTime ()J
public abstract fun getMd5 ()[B
Expand Down
25 changes: 25 additions & 0 deletions mirai-core-api/compatibility-validation/jvm/api/jvm.api
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
public abstract fun getBotAsMember ()Lnet/mamoe/mirai/contact/NormalMember;
public fun getBotMuteRemaining ()I
public fun getBotPermission ()Lnet/mamoe/mirai/contact/MemberPermission;
public abstract fun getEssences ()Lnet/mamoe/mirai/contact/essence/Essences;
public abstract fun getId ()J
public abstract fun getMembers ()Lnet/mamoe/mirai/contact/ContactList;
public abstract fun getName ()Ljava/lang/String;
Expand Down Expand Up @@ -900,6 +901,30 @@ public final class net/mamoe/mirai/contact/announcement/OnlineAnnouncementKt {
public static final fun getBot (Lnet/mamoe/mirai/contact/announcement/OnlineAnnouncement;)Lnet/mamoe/mirai/Bot;
}

public final class net/mamoe/mirai/contact/essence/EssenceMessageRecord {
public final fun getGroup ()Lnet/mamoe/mirai/contact/Group;
public final fun getOperator ()Lnet/mamoe/mirai/contact/NormalMember;
public final fun getOperatorId ()J
public final fun getOperatorNick ()Ljava/lang/String;
public final fun getOperatorTime ()I
public final fun getSender ()Lnet/mamoe/mirai/contact/NormalMember;
public final fun getSenderId ()J
public final fun getSenderNick ()Ljava/lang/String;
public final fun getSenderTime ()I
public final fun getSource ()Lnet/mamoe/mirai/message/data/MessageSource;
public final fun getSource (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun toString ()Ljava/lang/String;
}

public abstract interface class net/mamoe/mirai/contact/essence/Essences : net/mamoe/mirai/utils/Streamable {
public fun getPage (II)Ljava/util/List;
public abstract fun getPage (IILkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun remove (Lnet/mamoe/mirai/message/data/MessageSource;)V
public abstract fun remove (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun share (Lnet/mamoe/mirai/message/data/MessageSource;)Ljava/lang/String;
public abstract fun share (Lnet/mamoe/mirai/message/data/MessageSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract interface class net/mamoe/mirai/contact/file/AbsoluteFile : net/mamoe/mirai/contact/file/AbsoluteFileFolder {
public abstract fun getExpiryTime ()J
public abstract fun getMd5 ()[B
Expand Down
10 changes: 9 additions & 1 deletion mirai-core-api/src/commonMain/kotlin/contact/Group.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
* Copyright 2019-2023 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.
Expand All @@ -17,6 +17,7 @@ import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.active.GroupActive
import net.mamoe.mirai.contact.announcement.Announcements
import net.mamoe.mirai.contact.essence.Essences
import net.mamoe.mirai.contact.file.RemoteFiles
import net.mamoe.mirai.contact.roaming.RoamingSupported
import net.mamoe.mirai.event.events.*
Expand Down Expand Up @@ -229,6 +230,13 @@ public interface Group : Contact, CoroutineScope, FileSupported, AudioSupported,
*/
public suspend fun setEssenceMessage(source: MessageSource): Boolean

/**
* 群精华消息相关功能接口
*
* @since 2.15
*/
public val essences: Essences

public companion object {
/**
* 将一条消息设置为群精华消息, 需要管理员或群主权限.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2019-2023 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.essence

import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.NormalMember
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.utils.MiraiInternalApi

/**
* 精华消息记录
* @since 2.15
* @param group 记录的群聊
* @param sender 消息的发送者
* @param senderId 消息的发送者的ID
* @param senderNick 消息的发送者的Nick
* @param senderTime 消息的发送的时间 *
* @param operator 设置精华的操作者
* @param operatorId 设置精华的操作者的ID
* @param operatorNick 设置精华的操作者的Nick
* @param operatorTime 设置精华的时间
*/
public class EssenceMessageRecord @MiraiInternalApi constructor(
public val group: Group,
public val sender: NormalMember?,
public val senderId: Long,
public val senderNick: String,
public val senderTime: Int,
public val operator: NormalMember?,
public val operatorId: Long,
public val operatorNick: String,
public val operatorTime: Int,
private val loadMessageSource: suspend () -> MessageSource
) {
override fun toString(): String {
return "EssenceMessageRecord(group=${group}, sender=${senderNick}(${senderId}), senderTime=${senderTime}, operator=${operatorNick}(${operatorId}), operatorTime=${operatorTime})"
}

/**
* 获取消息源
*
* **注意** 当精华消息中包含 图片 时,会尝试将其下载然后重新上传, 以保证可用性
*/
@JvmBlockingBridge
public suspend fun getSource(): MessageSource {
return loadMessageSource()
}
}
69 changes: 69 additions & 0 deletions mirai-core-api/src/commonMain/kotlin/contact/essence/Essences.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2019-2023 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.essence

import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.NotStableForInheritance
import net.mamoe.mirai.utils.Streamable

/**
* 表示一个群精华消息管理.
*
* ## 获取 [Essences] 实例
*
* 只可以通过 [Group.essences] 获取一个群的精华消息管理, 即 [Essences] 实例.
*
* ### 获取精华消息列表
*
* 通过 [asFlow] 或 `asStream` 可以获取到*惰性*流, 在从流中收集数据时才会请求服务器获取数据. 通常建议在 Kotlin 使用协程的 [asFlow], 在 Java 使用 `asStream`.
*
* 若要获取全部精华消息列表, 可使用 [toList].
*
* ### 获取精华消息分享链接
*
* 通过 [share] 可以获得一个精华消息的分享链接
*
* ### 移除精华消息
*
* 通过 [remove] 可以从列表中移除指定精华消息 (WEB API)
*
* @since 2.15
*/
@NotStableForInheritance
public interface Essences : Streamable<EssenceMessageRecord> {

/**
* 按页获取精华消息记录
* @param start 起始索引 从 0 开始
* @param limit 页大小 返回的记录最大数量,最大取 50
* @throws IllegalStateException [limit] 过大或其他参数错误时会触发异常
*/
@JvmBlockingBridge
public suspend fun getPage(start: Int, limit: Int): List<EssenceMessageRecord>

/**
* 分享精华消息
* @param source 要分享的消息源
* @throws IllegalStateException [source] 不为精华消息时将会触发异常
* @return 分享 URL
*/
@JvmBlockingBridge
public suspend fun share(source: MessageSource): String

/**
* 移除精华消息
* @throws IllegalStateException [source] 不为精华消息或权限不足时将会触发异常
* @param source 要移除的消息源
*/
@JvmBlockingBridge
public suspend fun remove(source: MessageSource)
}
24 changes: 24 additions & 0 deletions mirai-core-mock/src/contact/essence/MockEssences.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/

package net.mamoe.mirai.mock.contact.essence

import net.mamoe.mirai.contact.NormalMember
import net.mamoe.mirai.contact.essence.Essences
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.mock.MockBotDSL

public interface MockEssences : Essences {

/**
* 直接以 [actor] 的身份设置一条精华消息
*/
@MockBotDSL
public fun mockSetEssences(source: MessageSource, actor: NormalMember)
}
6 changes: 6 additions & 0 deletions mirai-core-mock/src/internal/contact/MockGroupImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import net.mamoe.mirai.mock.contact.MockGroup
import net.mamoe.mirai.mock.contact.MockGroupControlPane
import net.mamoe.mirai.mock.contact.MockNormalMember
import net.mamoe.mirai.mock.contact.active.MockGroupActive
import net.mamoe.mirai.mock.contact.essence.MockEssences
import net.mamoe.mirai.mock.internal.contact.active.MockGroupActiveImpl
import net.mamoe.mirai.mock.internal.contact.essence.MockEssencesImpl
import net.mamoe.mirai.mock.internal.contact.roaming.MockRoamingMessages
import net.mamoe.mirai.mock.internal.msgsrc.OnlineMsgSrcToGroup
import net.mamoe.mirai.mock.internal.msgsrc.newMsgSrc
Expand Down Expand Up @@ -337,9 +339,13 @@ internal class MockGroupImpl(
resource.mockUploadVoice(bot)

override suspend fun setEssenceMessage(source: MessageSource): Boolean {
checkBotPermission(MemberPermission.ADMINISTRATOR)
essences.mockSetEssences(source, this.botAsMember)
return true
}

override val essences: MockEssences = MockEssencesImpl(this)

@Deprecated("Please use files instead.", replaceWith = ReplaceWith("files.root"))
@Suppress("OverridingDeprecatedMember", "DEPRECATION", "DEPRECATION_ERROR")
override val filesRoot: RemoteFile by lazy {
Expand Down
59 changes: 59 additions & 0 deletions mirai-core-mock/src/internal/contact/essence/MockEssences.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/

package net.mamoe.mirai.mock.internal.contact.essence

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import net.mamoe.mirai.contact.NormalMember
import net.mamoe.mirai.contact.essence.EssenceMessageRecord
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.mock.contact.essence.MockEssences
import net.mamoe.mirai.mock.internal.contact.MockGroupImpl
import net.mamoe.mirai.utils.ConcurrentHashMap
import net.mamoe.mirai.utils.currentTimeSeconds

internal class MockEssencesImpl(
private val group: MockGroupImpl
) : MockEssences {

private val cache: MutableMap<MessageSource, EssenceMessageRecord> = ConcurrentHashMap()

override fun mockSetEssences(source: MessageSource, actor: NormalMember) {
val record = EssenceMessageRecord(
group = group,
sender = group[source.fromId],
senderId = source.fromId,
senderNick = group[source.fromId]?.nick.orEmpty(),
senderTime = source.time,
operator = actor,
operatorId = actor.id,
operatorNick = actor.nick,
operatorTime = currentTimeSeconds().toInt(),
loadMessageSource = { source }
)
cache[source] = record
}

override suspend fun getPage(start: Int, limit: Int): List<EssenceMessageRecord> {
return cache.values.toList().subList(start, start + limit)
}

override suspend fun share(source: MessageSource): String {
return "https://qun.qq.com/essence/share?_wv=3&_wwv=128&_wvx=2&sharekey=..."
}

override suspend fun remove(source: MessageSource) {
cache.remove(source)
}

override fun asFlow(): Flow<EssenceMessageRecord> {
return cache.values.asFlow()
}
}
23 changes: 23 additions & 0 deletions mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import net.mamoe.mirai.LowLevelApi
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.contact.active.GroupActive
import net.mamoe.mirai.contact.announcement.Announcements
import net.mamoe.mirai.contact.essence.Essences
import net.mamoe.mirai.contact.file.RemoteFiles
import net.mamoe.mirai.contact.roaming.RoamingMessages
import net.mamoe.mirai.data.GroupHonorType
Expand All @@ -29,6 +30,7 @@ import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.active.GroupActiveImpl
import net.mamoe.mirai.internal.contact.announcement.AnnouncementsImpl
import net.mamoe.mirai.internal.contact.essence.EssencesImpl
import net.mamoe.mirai.internal.contact.file.RemoteFilesImpl
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
import net.mamoe.mirai.internal.contact.roaming.RoamingMessagesImplGroup
Expand Down Expand Up @@ -393,6 +395,27 @@ internal abstract class CommonGroupImpl constructor(

override val roamingMessages: RoamingMessages by lazy { RoamingMessagesImplGroup(this) }

// 鉴于在 [essences] 中 有相同的功能的 Web API 所以此方法移除
// override suspend fun removeEssenceMessage(source: MessageSource): Boolean {
// checkBotPermission(MemberPermission.ADMINISTRATOR)
// val result = bot.network.sendAndExpect(
// TroopEssenceMsgManager.RemoveEssence(
// bot.client,
// [email protected],
// source.internalIds.first(),
// source.ids.first()
// ), 5000, 2
// )
// return result.success
// }

override val essences: Essences by lazy {
EssencesImpl(
this as GroupImpl,
bot.network.logger.subLogger("Group $id"),
)
}

override fun toString(): String = "Group($id)"
}

Expand Down
Loading