mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-03 15:10:14 +08:00
Multiple MessageSource.id and MessageSource.internalId for split sources now, and split messages in the future. Close #618
This commit is contained in:
parent
8fdfe830fe
commit
64bd63d7a0
@ -107,8 +107,8 @@ public interface IMirai : LowLevelApiAccessor {
|
||||
/**
|
||||
* 构造一个 [OfflineMessageSource]
|
||||
*
|
||||
* @param id 即 [MessageSource.id]
|
||||
* @param internalId 即 [MessageSource.internalId]
|
||||
* @param ids 即 [MessageSource.ids]
|
||||
* @param internalIds 即 [MessageSource.internalIds]
|
||||
*
|
||||
* @param fromUin 为用户时为 [Friend.id], 为群时需使用 [Group.calculateGroupUinByGroupCode] 计算
|
||||
* @param targetUin 为用户时为 [Friend.id], 为群时需使用 [Group.calculateGroupUinByGroupCode] 计算
|
||||
@ -118,7 +118,7 @@ public interface IMirai : LowLevelApiAccessor {
|
||||
bot: Bot,
|
||||
kind: OfflineMessageSource.Kind,
|
||||
fromUin: Long, targetUin: Long,
|
||||
id: Int, time: Int, internalId: Int,
|
||||
ids: IntArray, time: Int, internalIds: IntArray,
|
||||
originalMessage: MessageChain
|
||||
): OfflineMessageSource
|
||||
|
||||
|
@ -259,16 +259,16 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
|
||||
public abstract val authorId: Long
|
||||
|
||||
/**
|
||||
* 消息 id.
|
||||
* @see MessageSource.id
|
||||
* 消息 ids.
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
public abstract val messageId: Int
|
||||
public abstract val messageIds: IntArray
|
||||
|
||||
/**
|
||||
* 消息内部 id.
|
||||
* @see MessageSource.id
|
||||
* 消息内部 ids.
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
public abstract val messageInternalId: Int
|
||||
public abstract val messageInternalIds: IntArray
|
||||
|
||||
/**
|
||||
* 原发送时间
|
||||
@ -280,8 +280,8 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
|
||||
*/
|
||||
public data class FriendRecall internal constructor(
|
||||
public override val bot: Bot,
|
||||
public override val messageId: Int,
|
||||
public override val messageInternalId: Int,
|
||||
public override val messageIds: IntArray,
|
||||
public override val messageInternalIds: IntArray,
|
||||
public override val messageTime: Int,
|
||||
/**
|
||||
* 撤回操作人, 好友的 [User.id]
|
||||
@ -290,6 +290,30 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
|
||||
) : MessageRecallEvent(), Packet {
|
||||
public override val authorId: Long
|
||||
get() = bot.id
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as FriendRecall
|
||||
|
||||
if (bot != other.bot) return false
|
||||
if (!messageIds.contentEquals(other.messageIds)) return false
|
||||
if (!messageInternalIds.contentEquals(other.messageInternalIds)) return false
|
||||
if (messageTime != other.messageTime) return false
|
||||
if (operator != other.operator) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + messageIds.contentHashCode()
|
||||
result = 31 * result + messageInternalIds.contentHashCode()
|
||||
result = 31 * result + messageTime
|
||||
result = 31 * result + operator.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,15 +322,43 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
|
||||
public data class GroupRecall @PublishedApi internal constructor(
|
||||
public override val bot: Bot,
|
||||
public override val authorId: Long,
|
||||
public override val messageId: Int,
|
||||
public override val messageInternalId: Int,
|
||||
public override val messageIds: IntArray,
|
||||
public override val messageInternalIds: IntArray,
|
||||
public override val messageTime: Int,
|
||||
/**
|
||||
* 操作人. 为 null 时则为 [Bot] 操作.
|
||||
*/
|
||||
public override val operator: Member?,
|
||||
public override val group: Group
|
||||
) : MessageRecallEvent(), GroupOperableEvent, Packet
|
||||
) : MessageRecallEvent(), GroupOperableEvent, Packet {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as GroupRecall
|
||||
|
||||
if (bot != other.bot) return false
|
||||
if (authorId != other.authorId) return false
|
||||
if (!messageIds.contentEquals(other.messageIds)) return false
|
||||
if (!messageInternalIds.contentEquals(other.messageInternalIds)) return false
|
||||
if (messageTime != other.messageTime) return false
|
||||
if (operator != other.operator) return false
|
||||
if (group != other.group) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + authorId.hashCode()
|
||||
result = 31 * result + messageIds.contentHashCode()
|
||||
result = 31 * result + messageInternalIds.contentHashCode()
|
||||
result = 31 * result + messageTime
|
||||
result = 31 * result + (operator?.hashCode() ?: 0)
|
||||
result = 31 * result + group.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public val MessageRecallEvent.GroupRecall.author: Member
|
||||
|
@ -78,7 +78,7 @@ public abstract class MessageEvent : ContactMessage(),
|
||||
/**
|
||||
* 消息内容.
|
||||
*
|
||||
* 第一个元素一定为 [MessageSource], 存储此消息的发送人, 发送时间, 收信人, 消息 id 等数据.
|
||||
* 第一个元素一定为 [MessageSource], 存储此消息的发送人, 发送时间, 收信人, 消息 ids 等数据.
|
||||
* 随后的元素为拥有顺序的真实消息内容.
|
||||
*/
|
||||
public abstract override val message: MessageChain
|
||||
|
@ -16,7 +16,6 @@ import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
/**
|
||||
* 发送消息后得到的回执. 可用于撤回, 引用回复等.
|
||||
@ -32,7 +31,7 @@ import kotlin.jvm.JvmSynthetic
|
||||
* @see User.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see Member.sendMessage 发送临时消息, 返回回执(此对象)
|
||||
*
|
||||
* @see MessageReceipt.sourceId 源 id
|
||||
* @see MessageReceipt.sourceIds 源 ids
|
||||
* @see MessageReceipt.sourceTime 源时间
|
||||
*/
|
||||
public open class MessageReceipt<out C : Contact> @MiraiExperimentalApi("The constructor is subject to change.") constructor(
|
||||
@ -95,23 +94,23 @@ public suspend inline fun <C : Contact> MessageReceipt<C>.quoteReply(message: St
|
||||
|
||||
|
||||
/**
|
||||
* 获取源消息 [MessageSource.id]
|
||||
* 获取源消息 [MessageSource.ids]
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public inline val MessageReceipt<*>.sourceId: Int
|
||||
get() = this.source.id
|
||||
public inline val MessageReceipt<*>.sourceIds: IntArray
|
||||
get() = this.source.ids
|
||||
|
||||
|
||||
/**
|
||||
* 获取源消息 [MessageSource.internalId]
|
||||
* 获取源消息 [MessageSource.internalIds]
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public inline val MessageReceipt<*>.sourceInternalId: Int
|
||||
get() = this.source.internalId
|
||||
public inline val MessageReceipt<*>.sourceInternalIds: IntArray
|
||||
get() = this.source.internalIds
|
||||
|
||||
/**
|
||||
* 获取源消息 [MessageSource.time]
|
||||
|
@ -22,9 +22,6 @@ import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.quote
|
||||
import net.mamoe.mirai.message.recall
|
||||
import net.mamoe.mirai.utils.LazyProperty
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
/**
|
||||
* 消息源. 消息源存在于 [MessageChain] 中, 用于表示这个消息的来源, 也可以用来分辨 [MessageChain].
|
||||
@ -36,8 +33,8 @@ import kotlin.jvm.JvmSynthetic
|
||||
* [MessageSource] 由 metadata (元数据), form & target, content 组成
|
||||
*
|
||||
* #### metadata
|
||||
* - [id] 消息 id (序列号)
|
||||
* - [internalId] 消息内部 id
|
||||
* - [ids] 消息 ids (序列号)
|
||||
* - [internalIds] 消息内部 ids
|
||||
* - [time] 时间
|
||||
*
|
||||
* 官方客户端通过 metadata 这三个数据定位消息, 撤回和引用回复都是如此.
|
||||
@ -51,9 +48,9 @@ import kotlin.jvm.JvmSynthetic
|
||||
*
|
||||
* ### 使用
|
||||
*
|
||||
* 消息源可用于 [引用回复][QuoteReply] 或 [撤回][Bot.recall].
|
||||
* 消息源可用于 [引用回复][QuoteReply] 或 [撤回][IMirai.recall].
|
||||
*
|
||||
* @see Bot.recall 撤回一条消息
|
||||
* @see IMirai.recall 撤回一条消息
|
||||
* @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
|
||||
*
|
||||
* @see OnlineMessageSource 在线消息的 [MessageSource]
|
||||
@ -74,28 +71,28 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<Me
|
||||
public abstract val bot: Bot
|
||||
|
||||
/**
|
||||
* 消息 id (序列号). 在获取失败时 (概率很低) 为 `-1`.
|
||||
* 消息 ids (序列号). 在获取失败时 (概率很低) 为 `-1`.
|
||||
**
|
||||
* #### 值域
|
||||
* 值的范围约为 [UShort] 的范围.
|
||||
*
|
||||
* #### 顺序
|
||||
* 群消息的 id 由服务器维护. 好友消息的 id 由 mirai 维护.
|
||||
* 此 id 不一定从 0 开始.
|
||||
* 群消息的 ids 由服务器维护. 好友消息的 ids 由 mirai 维护.
|
||||
* 此 ids 不一定从 0 开始.
|
||||
*
|
||||
* - 在同一个群的消息中此值随每条消息递增 1, 但此行为由服务器决定, mirai 不保证自增顺序.
|
||||
* - 在好友消息中无法保证每次都递增 1. 也可能会产生大幅跳过的情况.
|
||||
*/
|
||||
public abstract val id: Int
|
||||
public abstract val ids: IntArray
|
||||
|
||||
/**
|
||||
* 内部 id. **仅用于协议模块使用**
|
||||
* 内部 ids. **仅用于协议模块使用**
|
||||
*
|
||||
* 值没有顺序, 也可能为 0, 取决于服务器是否提供.
|
||||
*
|
||||
* 在事件中和在引用中无法保证同一条消息的 [internalId] 相同.
|
||||
* 在事件中和在引用中无法保证同一条消息的 [internalIds] 相同.
|
||||
*/
|
||||
public abstract val internalId: Int
|
||||
public abstract val internalIds: IntArray
|
||||
|
||||
/**
|
||||
* 发送时间时间戳, 单位为秒.
|
||||
@ -131,9 +128,9 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<Me
|
||||
public abstract val originalMessage: MessageChain
|
||||
|
||||
/**
|
||||
* 返回 `"[mirai:source:$id,$internalId]"`
|
||||
* 返回 `"[mirai:source:$ids,$internalIds]"`
|
||||
*/
|
||||
public final override fun toString(): String = "[mirai:source:$id,$internalId]"
|
||||
public final override fun toString(): String = "[mirai:source:$ids,$internalIds]"
|
||||
}
|
||||
|
||||
|
||||
@ -206,7 +203,7 @@ public sealed class OnlineMessageSource : MessageSource() {
|
||||
|
||||
public abstract override val target: Friend
|
||||
public final override val subject: Friend get() = target
|
||||
// final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})"
|
||||
// final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.ids})"
|
||||
}
|
||||
|
||||
public abstract class ToTemp : Outgoing() {
|
||||
@ -250,7 +247,7 @@ public sealed class OnlineMessageSource : MessageSource() {
|
||||
public abstract override val sender: Friend
|
||||
public final override val subject: Friend get() = sender
|
||||
public final override val target: Bot get() = sender.bot
|
||||
// final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})"
|
||||
// final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.ids})"
|
||||
}
|
||||
|
||||
public abstract class FromTemp : Incoming() {
|
||||
@ -367,44 +364,44 @@ public suspend inline fun MessageSource.recall(): Unit = Mirai.recall(bot, this)
|
||||
// For MessageChain
|
||||
|
||||
/**
|
||||
* 消息 id.
|
||||
* 消息 ids.
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.id: Int
|
||||
get() = this.source.id
|
||||
public val MessageChain.ids: IntArray
|
||||
get() = this.source.ids
|
||||
|
||||
/**
|
||||
* 消息内部 id.
|
||||
* 消息内部 ids.
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.internalId: Int
|
||||
get() = this.source.internalId
|
||||
public val MessageChain.internalId: IntArray
|
||||
get() = this.source.internalIds
|
||||
|
||||
/**
|
||||
* 消息时间.
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.time: Int
|
||||
get() = this.source.time
|
||||
|
||||
/**
|
||||
* 消息内部 id.
|
||||
* 消息内部 ids.
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取. 否则将抛出异常 [NoSuchElementException]
|
||||
*
|
||||
* @see MessageSource.id
|
||||
* @see MessageSource.ids
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.bot: Bot
|
||||
@ -414,11 +411,24 @@ public val MessageChain.bot: Bot
|
||||
* 获取这条消息的 [消息源][MessageSource].
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源, 否则将抛出异常 [NoSuchElementException]
|
||||
*
|
||||
* @see sourceOrNull
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.source: MessageSource
|
||||
get() = this.getOrFail(MessageSource)
|
||||
|
||||
/**
|
||||
* 获取这条消息的 [消息源][MessageSource].
|
||||
*
|
||||
* 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源, 否则返回 `null`
|
||||
*
|
||||
* @see source
|
||||
*/
|
||||
@get:JvmSynthetic
|
||||
public val MessageChain.sourceOrNull: MessageSource?
|
||||
get() = this[MessageSource]
|
||||
|
||||
/**
|
||||
* 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
|
||||
*
|
||||
|
@ -52,16 +52,16 @@ public interface MessageSourceAmender {
|
||||
public var kind: OfflineMessageSource.Kind
|
||||
public var fromUin: Long
|
||||
public var targetUin: Long
|
||||
public var id: Int
|
||||
public var ids: IntArray
|
||||
public var time: Int
|
||||
public var internalId: Int
|
||||
public var internalIds: IntArray
|
||||
|
||||
public var originalMessage: MessageChain
|
||||
|
||||
/** 从另一个 [MessageSource] 中复制 [id], [internalId], [time]*/
|
||||
/** 从另一个 [MessageSource] 中复制 [ids], [internalIds], [time]*/
|
||||
public fun metadataFrom(another: MessageSource) {
|
||||
this.id = another.id
|
||||
this.internalId = another.internalId
|
||||
this.ids = another.ids
|
||||
this.internalIds = another.internalIds
|
||||
this.time = another.time
|
||||
}
|
||||
}
|
||||
@ -78,9 +78,9 @@ public interface MessageSourceAmender {
|
||||
* ### 参数
|
||||
* 一个 [OfflineMessageSource] 须要以下参数:
|
||||
* - 发送人和发送目标: 通过 [MessageSourceBuilder.sendTo] 设置
|
||||
* - 消息元数据 (即 [MessageSource.id], [MessageSource.internalId], [MessageSource.time])
|
||||
* - 消息元数据 (即 [MessageSource.ids], [MessageSource.internalIds], [MessageSource.time])
|
||||
* 元数据用于 [撤回][MessageSource.recall], [引用回复][MessageSource.quote], 和官方客户端定位原消息.
|
||||
* 可通过 [MessageSourceBuilder.id], [MessageSourceBuilder.time], [MessageSourceBuilder.internalId] 设置
|
||||
* 可通过 [MessageSourceBuilder.ids], [MessageSourceBuilder.time], [MessageSourceBuilder.internalIds] 设置
|
||||
* 可通过 [MessageSourceBuilder.metadata] 从另一个 [MessageSource] 复制
|
||||
* - 消息内容: 通过 [MessageSourceBuilder.messages] 设置
|
||||
*
|
||||
@ -92,7 +92,7 @@ public interface MessageSourceAmender {
|
||||
* ```
|
||||
* bot.buildMessageSource {
|
||||
* bot sendTo target // 指定发送人和发送目标
|
||||
* metadata(source) // 从另一个消息源复制 id, internalId, time
|
||||
* metadata(source) // 从另一个消息源复制 ids, internalIds, time
|
||||
*
|
||||
* messages { // 指定消息内容
|
||||
* +"hi"
|
||||
@ -109,9 +109,9 @@ public fun Bot.buildMessageSource(block: MessageSourceBuilder.() -> Unit): Messa
|
||||
builder.kind ?: error("You must call `Contact.sendTo(Contact)` when `buildMessageSource`"),
|
||||
builder.fromUin,
|
||||
builder.targetUin,
|
||||
builder.id,
|
||||
builder.ids,
|
||||
builder.time,
|
||||
builder.internalId,
|
||||
builder.internalIds,
|
||||
builder.originalMessages.build()
|
||||
)
|
||||
}
|
||||
@ -124,9 +124,9 @@ public abstract class MessageSourceBuilder {
|
||||
internal abstract var fromUin: Long
|
||||
internal abstract var targetUin: Long
|
||||
|
||||
internal abstract var id: Int
|
||||
internal abstract var ids: IntArray
|
||||
internal abstract var time: Int
|
||||
internal abstract var internalId: Int
|
||||
internal abstract var internalIds: IntArray
|
||||
|
||||
@PublishedApi
|
||||
internal val originalMessages: MessageChainBuilder = MessageChainBuilder()
|
||||
@ -135,15 +135,15 @@ public abstract class MessageSourceBuilder {
|
||||
public val now: Int get() = currentTimeSeconds.toInt()
|
||||
public fun time(value: Int): MessageSourceBuilder = apply { this.time = value }
|
||||
|
||||
public fun internalId(from: MessageSource): MessageSourceBuilder = apply { this.internalId = from.internalId }
|
||||
public fun internalId(value: Int): MessageSourceBuilder = apply { this.internalId = value }
|
||||
public fun internalId(from: MessageSource): MessageSourceBuilder = apply { this.internalIds = from.internalIds }
|
||||
public fun internalId(vararg value: Int): MessageSourceBuilder = apply { this.internalIds = value }
|
||||
|
||||
public fun id(from: MessageSource): MessageSourceBuilder = apply { this.id = from.id }
|
||||
public fun id(value: Int): MessageSourceBuilder = apply { this.id = value }
|
||||
public fun id(from: MessageSource): MessageSourceBuilder = apply { this.ids = from.ids }
|
||||
public fun id(vararg value: Int): MessageSourceBuilder = apply { this.ids = value }
|
||||
|
||||
|
||||
/**
|
||||
* 从另一个 [MessageSource] 复制 [id], [time], [internalId].
|
||||
* 从另一个 [MessageSource] 复制 [ids], [time], [internalIds].
|
||||
* 这三个数据决定官方客户端能 "定位" 到的原消息
|
||||
*/
|
||||
public fun metadata(from: MessageSource): MessageSourceBuilder = apply {
|
||||
@ -157,11 +157,11 @@ public abstract class MessageSourceBuilder {
|
||||
*/
|
||||
public fun allFrom(source: MessageSource): MessageSourceBuilder {
|
||||
this.kind = determineKind(source)
|
||||
this.id = source.id
|
||||
this.ids = source.ids
|
||||
this.time = source.time
|
||||
this.fromUin = source.fromId
|
||||
this.targetUin = source.targetId
|
||||
this.internalId = source.internalId
|
||||
this.internalIds = source.internalIds
|
||||
this.originalMessages.addAll(source.originalMessage)
|
||||
return this
|
||||
}
|
||||
@ -212,9 +212,9 @@ internal class MessageSourceBuilderImpl : MessageSourceBuilder() {
|
||||
override var fromUin: Long = 0
|
||||
override var targetUin: Long = 0
|
||||
|
||||
override var id: Int = 0
|
||||
override var ids: IntArray = intArrayOf()
|
||||
override var time: Int = currentTimeSeconds.toInt()
|
||||
override var internalId: Int = 0
|
||||
override var internalIds: IntArray = intArrayOf()
|
||||
|
||||
@JvmSynthetic
|
||||
override fun ContactOrBot.sendTo(target: ContactOrBot): MessageSourceBuilder {
|
||||
@ -259,8 +259,8 @@ internal class MutableOfflineMessageSourceByOnline(
|
||||
targetId = value
|
||||
}
|
||||
override var bot: Bot = origin.bot
|
||||
override var id: Int = origin.id
|
||||
override var internalId: Int = origin.internalId
|
||||
override var ids: IntArray = origin.ids
|
||||
override var internalIds: IntArray = origin.internalIds
|
||||
override var time: Int = origin.time
|
||||
override var fromId: Long = origin.fromId
|
||||
override var targetId: Long = origin.targetId
|
||||
@ -287,8 +287,8 @@ internal class OfflineMessageSourceByOnline(
|
||||
else -> error("stub")
|
||||
}
|
||||
override val bot: Bot get() = onlineMessageSource.bot
|
||||
override val id: Int get() = onlineMessageSource.id
|
||||
override val internalId: Int get() = onlineMessageSource.internalId
|
||||
override val ids: IntArray get() = onlineMessageSource.ids
|
||||
override val internalIds: IntArray get() = onlineMessageSource.internalIds
|
||||
override val time: Int get() = onlineMessageSource.time
|
||||
override val fromId: Long get() = onlineMessageSource.fromId
|
||||
override val targetId: Long get() = onlineMessageSource.targetId
|
||||
|
@ -14,9 +14,6 @@
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
|
||||
/**
|
||||
@ -35,7 +32,7 @@ import kotlin.jvm.JvmSynthetic
|
||||
* 引用回复的原消息内容完全由 [source] 中 [MessageSource.originalMessage] 控制, 客户端不会自行寻找原消息.
|
||||
*
|
||||
* #### 客户端内跳转
|
||||
* 客户端在跳转原消息时, 会通过 [MessageSource.id] 等 metadata
|
||||
* 客户端在跳转原消息时, 会通过 [MessageSource.ids] 等 metadata
|
||||
*
|
||||
* @see MessageSource 获取有关消息源的更多信息
|
||||
*/
|
||||
@ -47,7 +44,8 @@ public class QuoteReply(public val source: MessageSource) : Message, MessageMeta
|
||||
|
||||
public override val key: Message.Key<QuoteReply> get() = Key
|
||||
|
||||
public override fun toString(): String = "[mirai:quote:${source.id},${source.internalId}]"
|
||||
// TODO: 2020/12/2 QuoteReply.toString
|
||||
public override fun toString(): String = "[mirai:quote:${source.ids},${source.internalIds}]"
|
||||
public override fun equals(other: Any?): Boolean = other is QuoteReply && other.source == this.source
|
||||
public override fun hashCode(): Int = source.hashCode()
|
||||
}
|
||||
|
@ -7,7 +7,31 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("MiraiUtils")
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
public inline fun <A, reified B> Array<A>.mapToArray(block: (element: A) -> B): Array<B> {
|
||||
val result = arrayOfNulls<B>(size)
|
||||
this.forEachIndexed { index, element ->
|
||||
result[index] = block(element)
|
||||
}
|
||||
return result.cast()
|
||||
}
|
||||
|
||||
public inline fun <A, reified B> Collection<A>.mapToArray(block: (element: A) -> B): Array<B> {
|
||||
val result = arrayOfNulls<B>(size)
|
||||
this.forEachIndexed { index, element ->
|
||||
result[index] = block(element)
|
||||
}
|
||||
return result.cast()
|
||||
}
|
||||
|
||||
public inline fun <A> Collection<A>.mapToIntArray(block: (element: A) -> Int): IntArray {
|
||||
val result = IntArray(size)
|
||||
this.forEachIndexed { index, element ->
|
||||
result[index] = block(element)
|
||||
}
|
||||
return result.cast()
|
||||
}
|
15
mirai-core-utils/src/commonMain/kotlin/Numbers.kt
Normal file
15
mirai-core-utils/src/commonMain/kotlin/Numbers.kt
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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:JvmMultifileClass
|
||||
@file:JvmName("MiraiUtils")
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
public fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF)
|
@ -7,12 +7,13 @@
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("MiraiUtils")
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
inline fun <reified T> Any?.cast(): T = this as T
|
||||
public inline fun <reified T> Any?.cast(): T = this as T
|
||||
|
||||
inline fun <reified T> Any?.safeCast(): T? = this as? T
|
||||
public inline fun <reified T> Any?.safeCast(): T? = this as? T
|
||||
|
||||
inline fun <reified T> Any?.castOrNull(): T? = this as? T
|
||||
public inline fun <reified T> Any?.castOrNull(): T? = this as? T
|
||||
|
@ -280,8 +280,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
MessageRecallEvent.GroupRecall(
|
||||
bot,
|
||||
source.fromId,
|
||||
source.id,
|
||||
source.internalId,
|
||||
source.ids,
|
||||
source.internalIds,
|
||||
source.time,
|
||||
null,
|
||||
group
|
||||
@ -291,8 +291,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
|
||||
bot.asQQAndroidBot().client,
|
||||
group.id,
|
||||
source.sequenceId,
|
||||
source.internalId
|
||||
source.sequenceIds,
|
||||
source.internalIds
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
}
|
||||
@ -305,8 +305,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
|
||||
bot.client,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.internalId,
|
||||
source.sequenceIds,
|
||||
source.internalIds,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
@ -321,8 +321,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
bot.client,
|
||||
(source.target.group as GroupImpl).uin,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.internalId,
|
||||
source.sequenceIds,
|
||||
source.internalIds,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
@ -335,8 +335,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
|
||||
bot.client,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.internalId,
|
||||
source.sequenceIds,
|
||||
source.internalIds,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
@ -348,8 +348,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
bot.client,
|
||||
source.targetId, // groupUin
|
||||
source.targetId, // memberUin
|
||||
source.sequenceId,
|
||||
source.internalId,
|
||||
source.sequenceIds,
|
||||
source.internalIds,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
@ -357,8 +357,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
|
||||
bot.client,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.internalId
|
||||
source.sequenceIds,
|
||||
source.internalIds
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
}
|
||||
@ -370,7 +370,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
// 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息)
|
||||
// 154: timeout
|
||||
// 3: <no message>
|
||||
check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.id}: $response" }
|
||||
check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.ids}: $response" }
|
||||
}
|
||||
|
||||
@LowLevelApi
|
||||
@ -813,28 +813,28 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
kind: OfflineMessageSource.Kind,
|
||||
fromUin: Long,
|
||||
targetUin: Long,
|
||||
id: Int,
|
||||
ids: IntArray,
|
||||
time: Int,
|
||||
internalId: Int,
|
||||
internalIds: IntArray,
|
||||
originalMessage: MessageChain
|
||||
): OfflineMessageSource {
|
||||
return object : OfflineMessageSource(), MessageSourceInternal {
|
||||
override val kind: Kind get() = kind
|
||||
override val id: Int get() = id
|
||||
override val ids: IntArray get() = ids
|
||||
override val bot: Bot get() = bot
|
||||
override val time: Int get() = time
|
||||
override val fromId: Long get() = fromUin
|
||||
override val targetId: Long get() = targetUin
|
||||
override val originalMessage: MessageChain get() = originalMessage
|
||||
override val sequenceId: Int = id
|
||||
override val internalId: Int = internalId
|
||||
override val sequenceIds: IntArray = ids
|
||||
override val internalIds: IntArray = internalIds
|
||||
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(sequenceId),
|
||||
origSeqs = sequenceIds,
|
||||
senderUin = fromUin,
|
||||
toUin = 0,
|
||||
flag = 1,
|
||||
|
@ -29,11 +29,11 @@ import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
internal interface MessageSourceInternal {
|
||||
val sequenceId: Int
|
||||
val internalId: Int // randomId
|
||||
val sequenceIds: IntArray
|
||||
val internalIds: IntArray // randomId
|
||||
|
||||
@Deprecated("don't use this internally. Use sequenceId or random instead.", level = DeprecationLevel.ERROR)
|
||||
val id: Int
|
||||
val ids: IntArray
|
||||
|
||||
val isRecalledOrPlanned: AtomicBoolean
|
||||
|
||||
@ -66,25 +66,25 @@ internal class MessageSourceFromFriendImpl(
|
||||
override val bot: Bot,
|
||||
val msg: MsgComm.Msg
|
||||
) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal {
|
||||
override val sequenceId: Int get() = msg.msgHead.msgSeq
|
||||
override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val id: Int get() = sequenceId// msg.msgBody.richText.attr!!.random
|
||||
override val internalId: Int get() = msg.msgBody.richText.attr!!.random
|
||||
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
|
||||
override val internalIds: IntArray get() = intArrayOf(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: Friend get() = bot.getFriend(msg.msgHead.fromUin)
|
||||
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalId) }
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
|
||||
private fun MsgComm.Msg.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.SourceMsg {
|
||||
val elements = msgBody.richText.elems.toMutableList().also {
|
||||
if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
|
||||
}
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(this.msgHead.msgSeq),
|
||||
origSeqs = intArrayOf(this.msgHead.msgSeq),
|
||||
senderUin = this.msgHead.fromUin,
|
||||
toUin = this.msgHead.toUin,
|
||||
flag = 1,
|
||||
@ -92,7 +92,7 @@ private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
|
||||
type = 0,
|
||||
time = this.msgHead.msgTime,
|
||||
pbReserve = SourceMsg.ResvAttr(
|
||||
origUids = id.toLong() and 0xFFFF_FFFF
|
||||
origUids = ids.map { it.toLong() and 0xFFFF_FFFF }
|
||||
).toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
srcMsg = MsgComm.Msg(
|
||||
msgHead = MsgComm.MsgHead(
|
||||
@ -102,7 +102,7 @@ private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
|
||||
c2cCmd = this.msgHead.c2cCmd,
|
||||
msgSeq = this.msgHead.msgSeq,
|
||||
msgTime = this.msgHead.msgTime,
|
||||
msgUid = id.toLong() and 0xFFFF_FFFF, // ok
|
||||
msgUid = ids.single().toLong() and 0xFFFF_FFFF, // ok
|
||||
// groupInfo = MsgComm.GroupInfo(groupCode = this.msgHead.groupInfo.groupCode),
|
||||
isSrcMsg = true
|
||||
),
|
||||
@ -119,15 +119,15 @@ internal class MessageSourceFromTempImpl(
|
||||
override val bot: Bot,
|
||||
private val msg: MsgComm.Msg
|
||||
) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal {
|
||||
override val sequenceId: Int get() = msg.msgHead.msgSeq
|
||||
override val internalId: Int get() = msg.msgBody.richText.attr!!.random
|
||||
override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
|
||||
override val internalIds: IntArray get() = intArrayOf(msg.msgBody.richText.attr!!.random)
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val id: Int get() = sequenceId//
|
||||
override val ids: IntArray get() = sequenceIds//
|
||||
override val time: Int get() = msg.msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, 0, false) }
|
||||
override val sender: Member get() = with(msg.msgHead) { bot.getGroup(c2cTmpMsgHead!!.groupUin)[fromUin] }
|
||||
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalId) }
|
||||
private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
@ -136,9 +136,9 @@ internal data class MessageSourceFromGroupImpl(
|
||||
private val msg: MsgComm.Msg
|
||||
) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal {
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val sequenceId: Int get() = msg.msgHead.msgSeq
|
||||
override val internalId: Int get() = msg.msgBody.richText.attr!!.random
|
||||
override val id: Int get() = sequenceId
|
||||
override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
|
||||
override val internalIds: IntArray get() = intArrayOf(msg.msgBody.richText.attr!!.random)
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
override val time: Int get() = msg.msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
msg.toMessageChain(bot, groupIdOrZero = group.id, onlineSource = false)
|
||||
@ -159,7 +159,7 @@ internal data class MessageSourceFromGroupImpl(
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(msg.msgHead.msgSeq),
|
||||
origSeqs = intArrayOf(msg.msgHead.msgSeq),
|
||||
senderUin = msg.msgHead.fromUin,
|
||||
toUin = 0,
|
||||
flag = 1,
|
||||
|
@ -19,6 +19,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.OfflineMessageSource
|
||||
import net.mamoe.mirai.utils.mapToIntArray
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
|
||||
@ -28,9 +29,8 @@ internal class OfflineMessageSourceImplByMsg(
|
||||
override val bot: Bot
|
||||
) : OfflineMessageSource(), MessageSourceInternal {
|
||||
override val kind: Kind = if (delegate.msgHead.groupInfo != null) Kind.GROUP else Kind.FRIEND
|
||||
override val id: Int get() = sequenceId
|
||||
override val internalId: Int
|
||||
get() = delegate.msgHead.msgUid.toInt()
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
override val internalIds: IntArray = intArrayOf(delegate.msgHead.msgUid.toInt())
|
||||
override val time: Int
|
||||
get() = delegate.msgHead.msgTime
|
||||
override val fromId: Long
|
||||
@ -38,20 +38,20 @@ internal class OfflineMessageSourceImplByMsg(
|
||||
override val targetId: Long
|
||||
get() = delegate.msgHead.groupInfo?.groupCode ?: delegate.msgHead.toUin
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
delegate.toMessageChain(bot,
|
||||
delegate.toMessageChain(
|
||||
bot,
|
||||
groupIdOrZero = delegate.msgHead.groupInfo?.groupCode ?: 0,
|
||||
onlineSource = false,
|
||||
isTemp = delegate.msgHead.c2cTmpMsgHead != null
|
||||
)
|
||||
}
|
||||
override val sequenceId: Int
|
||||
get() = delegate.msgHead.msgSeq
|
||||
override val sequenceIds: IntArray = intArrayOf(delegate.msgHead.msgSeq)
|
||||
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(delegate.msgHead.msgSeq),
|
||||
origSeqs = intArrayOf(delegate.msgHead.msgSeq),
|
||||
senderUin = delegate.msgHead.fromUin,
|
||||
toUin = 0,
|
||||
flag = 1,
|
||||
@ -73,20 +73,19 @@ internal class OfflineMessageSourceImplBySourceMsg(
|
||||
override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND
|
||||
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val sequenceId: Int
|
||||
get() = delegate.origSeqs.firstOrNull() ?: error("cannot find sequenceId")
|
||||
override val internalId: Int
|
||||
get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt() ?: 0
|
||||
override val sequenceIds: IntArray = delegate.origSeqs
|
||||
override val internalIds: IntArray = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer())
|
||||
.origUids?.mapToIntArray { it.toInt() } ?: intArrayOf()
|
||||
override val time: Int get() = delegate.time
|
||||
override val originalMessage: MessageChain by lazy { delegate.toMessageChain(bot, groupIdOrZero) }
|
||||
/*
|
||||
override val id: Long
|
||||
override val ids: Long
|
||||
get() = (delegate.origSeqs?.firstOrNull()
|
||||
?: error("cannot find sequenceId from ImMsgBody.SourceMsg")).toLong().shl(32) or
|
||||
delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!!.and(0xFFFFFFFF)
|
||||
*/
|
||||
|
||||
override val id: Int get() = sequenceId
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
// delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt()
|
||||
// ?: 0
|
||||
|
||||
|
@ -24,6 +24,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg.SendGroupMessageReceipt
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
@ -35,27 +36,30 @@ private fun <T> T.toJceDataImpl(): ImMsgBody.SourceMsg
|
||||
where T : MessageSourceInternal, T : MessageSource {
|
||||
|
||||
val elements = originalMessage.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
val messageUid: Long = sequenceId.toLong().shl(32) or internalId.toLong().and(0xffFFffFF)
|
||||
|
||||
val pdReserve = SourceMsg.ResvAttr(
|
||||
origUids = sequenceIds.zip(internalIds)
|
||||
.map { (seq, internal) -> seq.toLong().shl(32) or internal.toLongUnsigned() }
|
||||
)
|
||||
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(sequenceId),
|
||||
origSeqs = sequenceIds,
|
||||
senderUin = fromId,
|
||||
toUin = targetId,
|
||||
flag = 1,
|
||||
elems = elements,
|
||||
type = 0,
|
||||
time = time,
|
||||
pbReserve = SourceMsg.ResvAttr(
|
||||
origUids = messageUid
|
||||
).toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
pbReserve = pdReserve.toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
srcMsg = MsgComm.Msg(
|
||||
msgHead = MsgComm.MsgHead(
|
||||
fromUin = fromId, // qq
|
||||
toUin = targetId, // group
|
||||
msgType = 9, // 82?
|
||||
c2cCmd = 11,
|
||||
msgSeq = sequenceId,
|
||||
msgSeq = sequenceIds.single(), // TODO !!
|
||||
msgTime = time,
|
||||
msgUid = messageUid, // ok
|
||||
msgUid = pdReserve.origUids!!.single(), // TODO !!
|
||||
// groupInfo = MsgComm.GroupInfo(groupCode = delegate.msgHead.groupInfo.groupCode),
|
||||
isSrcMsg = true
|
||||
),
|
||||
@ -71,8 +75,8 @@ private fun <T> T.toJceDataImpl(): ImMsgBody.SourceMsg
|
||||
}
|
||||
|
||||
internal class MessageSourceToFriendImpl(
|
||||
override val sequenceId: Int,
|
||||
override val internalId: Int,
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
@ -80,16 +84,16 @@ internal class MessageSourceToFriendImpl(
|
||||
) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal {
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val id: Int
|
||||
get() = sequenceId
|
||||
override val ids: IntArray
|
||||
get() = sequenceIds
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
private val jceData by lazy { toJceDataImpl() }
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToTempImpl(
|
||||
override val sequenceId: Int,
|
||||
override val internalId: Int,
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
@ -97,8 +101,8 @@ internal class MessageSourceToTempImpl(
|
||||
) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal {
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val id: Int
|
||||
get() = sequenceId
|
||||
override val ids: IntArray
|
||||
get() = sequenceIds
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
private val jceData by lazy { toJceDataImpl() }
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
@ -106,14 +110,14 @@ internal class MessageSourceToTempImpl(
|
||||
|
||||
internal class MessageSourceToGroupImpl(
|
||||
coroutineScope: CoroutineScope,
|
||||
override val internalId: Int,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
override val target: Group
|
||||
) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
|
||||
override val id: Int
|
||||
get() = sequenceId
|
||||
override val ids: IntArray
|
||||
get() = sequenceIds
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
@ -122,25 +126,27 @@ internal class MessageSourceToGroupImpl(
|
||||
coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>(
|
||||
timeoutMillis = 3000
|
||||
) {
|
||||
if (it.messageRandom == this@MessageSourceToGroupImpl.internalId) {
|
||||
if (it.messageRandom in this@MessageSourceToGroupImpl.internalIds) {
|
||||
it.sequenceId
|
||||
} else null
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override val sequenceId: Int
|
||||
get() = when {
|
||||
sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: -1
|
||||
!sequenceIdDeferred.isActive -> -1
|
||||
else -> error("sequenceId not yet available")
|
||||
}
|
||||
override val sequenceIds: IntArray
|
||||
get() = intArrayOf(
|
||||
when {
|
||||
sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: -1
|
||||
!sequenceIdDeferred.isActive -> -1
|
||||
else -> error("sequenceIds not yet available")
|
||||
}
|
||||
)
|
||||
|
||||
suspend fun ensureSequenceIdAvailable() = kotlin.run { sequenceIdDeferred.await() }
|
||||
|
||||
private val jceData by lazy {
|
||||
val elements = originalMessage.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(sequenceId),
|
||||
origSeqs = sequenceIds,
|
||||
senderUin = fromId,
|
||||
toUin = Mirai.calculateGroupUinByGroupCode(targetId),
|
||||
flag = 1,
|
||||
@ -148,7 +154,7 @@ internal class MessageSourceToGroupImpl(
|
||||
type = 0,
|
||||
time = time,
|
||||
pbReserve = SourceMsg.ResvAttr(
|
||||
origUids = internalId.toLong() and 0xffFFffFF // id is actually messageRandom
|
||||
origUids = internalIds.map { it.toLongUnsigned() } // ids is actually messageRandom
|
||||
).toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
srcMsg = MsgComm.Msg(
|
||||
msgHead = MsgComm.MsgHead(
|
||||
@ -156,9 +162,9 @@ internal class MessageSourceToGroupImpl(
|
||||
toUin = Mirai.calculateGroupUinByGroupCode(targetId), // group
|
||||
msgType = 82, // 82?
|
||||
c2cCmd = 1,
|
||||
msgSeq = sequenceId,
|
||||
msgSeq = sequenceIds.single(), // TODO !!
|
||||
msgTime = time,
|
||||
msgUid = internalId.toLong() and 0xffFFffFF, // ok
|
||||
msgUid = internalIds.single().toLongUnsigned(), // TODO !!
|
||||
groupInfo = MsgComm.GroupInfo(groupCode = targetId),
|
||||
isSrcMsg = true
|
||||
),
|
||||
|
@ -16,7 +16,6 @@ import kotlinx.serialization.protobuf.ProtoType
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
@Serializable
|
||||
internal class ImCommon : ProtoBuf {
|
||||
@ -879,7 +878,7 @@ internal class ImMsgBody : ProtoBuf {
|
||||
|
||||
@Serializable
|
||||
internal class SourceMsg(
|
||||
@ProtoNumber(1) @JvmField val origSeqs: List<Int> = emptyList(),
|
||||
@ProtoNumber(1) @JvmField val origSeqs: IntArray = intArrayOf(),
|
||||
@ProtoNumber(2) @JvmField val senderUin: Long = 0L,
|
||||
@ProtoNumber(3) @JvmField val time: Int = 0,
|
||||
@ProtoNumber(4) @JvmField val flag: Int = 0,
|
||||
|
@ -13,7 +13,6 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
internal class Generalflags : ProtoBuf {
|
||||
@Serializable
|
||||
@ -117,7 +116,7 @@ internal class SourceMsg : ProtoBuf {
|
||||
internal class ResvAttr(
|
||||
@ProtoNumber(1) @JvmField val richMsg2: ByteArray? = null,
|
||||
@ProtoNumber(2) @JvmField val oriMsgtype: Int? = null,
|
||||
@ProtoNumber(3) @JvmField val origUids: Long? = null // 原来是 list
|
||||
@ProtoNumber(3) @JvmField val origUids: List<Long>? = null
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
|
@ -46,66 +46,74 @@ internal class PbMessageSvc {
|
||||
fun createForGroupMessage(
|
||||
client: QQAndroidClient,
|
||||
groupCode: Long,
|
||||
messageSequenceId: Int, // 56639
|
||||
messageRandom: Int, // 921878719
|
||||
messageSequenceId: IntArray, // 56639
|
||||
messageRandom: IntArray, // 921878719
|
||||
messageType: Int = 0
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
groupWithDraw = listOf(
|
||||
MsgSvc.PbGroupMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
groupType = 0, // 普通群
|
||||
groupCode = groupCode,
|
||||
msgList = listOf(
|
||||
MsgSvc.PbGroupMsgWithDrawReq.MessageInfo(
|
||||
msgSeq = messageSequenceId,
|
||||
msgRandom = messageRandom,
|
||||
msgType = messageType
|
||||
)
|
||||
),
|
||||
userdef = MsgRevokeUserDef.MsgInfoUserDef(
|
||||
longMessageFlag = 0
|
||||
).toByteArray(MsgRevokeUserDef.MsgInfoUserDef.serializer())
|
||||
): OutgoingPacket {
|
||||
require(messageSequenceId.size == messageRandom.size)
|
||||
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
groupWithDraw = listOf(
|
||||
MsgSvc.PbGroupMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
groupType = 0, // 普通群
|
||||
groupCode = groupCode,
|
||||
msgList = messageSequenceId.zip(messageRandom).map { (seq, random) ->
|
||||
MsgSvc.PbGroupMsgWithDrawReq.MessageInfo(
|
||||
msgSeq = seq,
|
||||
msgRandom = random,
|
||||
msgType = messageType
|
||||
)
|
||||
},
|
||||
userdef = MsgRevokeUserDef.MsgInfoUserDef(
|
||||
longMessageFlag = 0
|
||||
).toByteArray(MsgRevokeUserDef.MsgInfoUserDef.serializer())
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun createForTempMessage(
|
||||
client: QQAndroidClient,
|
||||
groupUin: Long,
|
||||
toUin: Long,
|
||||
messageSequenceId: Int, // 56639
|
||||
messageRandom: Int, // 921878719
|
||||
messageSequenceId: IntArray, // 56639
|
||||
messageRandom: IntArray, // 921878719
|
||||
time: Int
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
c2cWithDraw = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
msgInfo = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
|
||||
fromUin = client.bot.id,
|
||||
toUin = toUin,
|
||||
msgSeq = messageSequenceId,
|
||||
msgRandom = messageRandom,
|
||||
msgUid = 0x0100000000000000 or (messageRandom.toLong() and 0xFFFFFFFF),
|
||||
msgTime = time.toLong(),
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
|
||||
): OutgoingPacket {
|
||||
require(messageSequenceId.size == messageRandom.size)
|
||||
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
c2cWithDraw = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
msgInfo = messageSequenceId.zip(messageRandom).map { (seq, random) ->
|
||||
MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
|
||||
fromUin = client.bot.id,
|
||||
toUin = toUin,
|
||||
msgSeq = seq,
|
||||
msgRandom = random,
|
||||
msgUid = 0x0100000000000000 or random.toLongUnsigned(),
|
||||
msgTime = time.toLong(),
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
reserved = RESERVED_TEMP
|
||||
},
|
||||
reserved = RESERVED_TEMP
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val RESERVED_TEMP = "08 01 10 E3 E9 D6 80 02".hexToBytes()
|
||||
@ -113,36 +121,40 @@ internal class PbMessageSvc {
|
||||
fun createForFriendMessage(
|
||||
client: QQAndroidClient,
|
||||
toUin: Long,
|
||||
messageSequenceId: Int, // 56639
|
||||
messageRandom: Int, // 921878719
|
||||
messageSequenceId: IntArray, // 56639
|
||||
messageRandom: IntArray, // 921878719
|
||||
time: Int
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
c2cWithDraw = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
msgInfo = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
|
||||
fromUin = client.bot.id,
|
||||
toUin = toUin,
|
||||
msgSeq = messageSequenceId,
|
||||
msgRandom = messageRandom,
|
||||
msgUid = 0x0100000000000000 or (messageRandom.toLong() and 0xFFFFFFFF),
|
||||
msgTime = time.toLong(),
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
c2c = MsgSvc.C2C(
|
||||
toUin = toUin
|
||||
): OutgoingPacket {
|
||||
require(messageSequenceId.size == messageRandom.size)
|
||||
|
||||
return buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
c2cWithDraw = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
msgInfo = messageSequenceId.zip(messageRandom).map { (seq, random) ->
|
||||
MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
|
||||
fromUin = client.bot.id,
|
||||
toUin = toUin,
|
||||
msgSeq = seq,
|
||||
msgRandom = random,
|
||||
msgUid = 0x0100000000000000 or random.toLongUnsigned(),
|
||||
msgTime = time.toLong(),
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
c2c = MsgSvc.C2C(
|
||||
toUin = toUin
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
reserved = byteArrayOf(0x08, 0x00)
|
||||
},
|
||||
reserved = byteArrayOf(0x08, 0x00)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
|
@ -78,8 +78,8 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
)
|
||||
),
|
||||
msgSeq = source.sequenceId,
|
||||
msgRand = source.internalId,
|
||||
msgSeq = source.sequenceIds.single(),
|
||||
msgRand = source.internalIds.single(),
|
||||
syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
|
||||
// msgVia = 1
|
||||
)
|
||||
@ -108,8 +108,8 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
)
|
||||
),
|
||||
msgSeq = source.sequenceId,
|
||||
msgRand = source.internalId,
|
||||
msgSeq = source.sequenceIds.single(),
|
||||
msgRand = source.internalIds.single(),
|
||||
syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
|
||||
)
|
||||
)
|
||||
@ -152,7 +152,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
)
|
||||
),
|
||||
msgSeq = client.atomicNextMessageSequenceId(),
|
||||
msgRand = source.internalId,
|
||||
msgRand = source.internalIds.single(),
|
||||
syncCookie = EMPTY_BYTE_ARRAY,
|
||||
msgVia = 1,
|
||||
msgCtrl = if (isForward) MsgCtrl.MsgCtrl(
|
||||
@ -186,11 +186,11 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val source = MessageSourceToTempImpl(
|
||||
internalId = Random.nextInt().absoluteValue,
|
||||
internalIds = intArrayOf(Random.nextInt().absoluteValue),
|
||||
sender = client.bot,
|
||||
target = member,
|
||||
time = currentTimeSeconds.toInt(),
|
||||
sequenceId = client.atomicNextMessageSequenceId(),
|
||||
sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
|
||||
originalMessage = message
|
||||
)
|
||||
sourceCallback(source)
|
||||
@ -214,11 +214,11 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
|
||||
}
|
||||
val rand = Random.nextInt().absoluteValue
|
||||
val source = MessageSourceToFriendImpl(
|
||||
internalId = rand,
|
||||
internalIds = intArrayOf(rand),
|
||||
sender = client.bot,
|
||||
target = qq,
|
||||
time = currentTimeSeconds.toInt(),
|
||||
sequenceId = client.nextFriendSeq(),
|
||||
sequenceIds = intArrayOf(client.nextFriendSeq()),
|
||||
originalMessage = message
|
||||
)
|
||||
sourceCallback(source)
|
||||
@ -242,7 +242,7 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
|
||||
}
|
||||
val source = MessageSourceToGroupImpl(
|
||||
group,
|
||||
internalId = Random.nextInt().absoluteValue,
|
||||
internalIds = intArrayOf(Random.nextInt().absoluteValue),
|
||||
sender = client.bot,
|
||||
target = group,
|
||||
time = currentTimeSeconds.toInt(),
|
||||
|
@ -367,8 +367,8 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
|
||||
MessageRecallEvent.GroupRecall(
|
||||
bot,
|
||||
pkg.authorUin,
|
||||
pkg.seq,
|
||||
pkg.msgRandom,
|
||||
intArrayOf(pkg.seq),
|
||||
intArrayOf(pkg.msgRandom),
|
||||
pkg.time,
|
||||
operator,
|
||||
group
|
||||
@ -440,8 +440,8 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
.filter { it.botUin == bot.id }.map {
|
||||
MessageRecallEvent.FriendRecall(
|
||||
bot = bot,
|
||||
messageId = it.srcId,
|
||||
messageInternalId = it.srcInternalId,
|
||||
messageIds = intArrayOf(it.srcId),
|
||||
messageInternalIds = intArrayOf(it.srcInternalId),
|
||||
messageTime = it.time,
|
||||
operator = it.fromUin
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user