mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-30 10:50:18 +08:00
Message serialization, fix #767
This commit is contained in:
parent
bfd21cbb92
commit
ebc7d655e3
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -10,15 +10,12 @@
|
||||
package net.mamoe.mirai.message
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.modules.PolymorphicModuleBuilder
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.plus
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
import kotlinx.serialization.modules.*
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
@ -29,21 +26,44 @@ import kotlin.reflect.KClass
|
||||
public interface MessageSerializer {
|
||||
public val serializersModule: SerializersModule
|
||||
|
||||
public fun <M : Message> registerSerializer(clazz: KClass<M>, serializer: KSerializer<M>)
|
||||
public fun <M : SingleMessage> registerSerializer(baseClass: KClass<M>, serializer: KSerializer<M>)
|
||||
|
||||
public fun registerSerializers(serializersModule: SerializersModule)
|
||||
|
||||
public fun clearRegisteredSerializers()
|
||||
|
||||
public companion object INSTANCE : MessageSerializer by MessageSerializerImpl
|
||||
}
|
||||
|
||||
internal fun ClassSerialDescriptorBuilder.takeElementsFrom(descriptor: SerialDescriptor) {
|
||||
with(descriptor) {
|
||||
repeat(descriptor.elementsCount) { index ->
|
||||
element(
|
||||
elementName = getElementName(index),
|
||||
descriptor = getElementDescriptor(index),
|
||||
annotations = getElementAnnotations(index),
|
||||
isOptional = isElementOptional(index),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MiraiInternalApi
|
||||
public open class MessageSourceSerializerImpl(serialName: String) : KSerializer<MessageSource> {
|
||||
public companion object : MessageSourceSerializerImpl("net.mamoe.mirai.message.data.MessageSource")
|
||||
|
||||
public open class MessageSourceSerializerImpl(serialName: String) :
|
||||
KSerializer<MessageSource> by SerialData.serializer().map(
|
||||
resultantDescriptor = buildClassSerialDescriptor(serialName) {
|
||||
takeElementsFrom(SerialData.serializer().descriptor)
|
||||
},
|
||||
serialize = { SerialData(kind, botId, ids, internalIds, time, fromId, targetId, originalMessage) },
|
||||
deserialize = {
|
||||
Mirai.constructMessageSource(botId, kind, fromId, targetId, ids, time, internalIds, originalMessage)
|
||||
}
|
||||
) {
|
||||
@SerialName(MessageSource.SERIAL_NAME)
|
||||
@Serializable
|
||||
internal class SerialData(
|
||||
val kind: MessageSourceKind,
|
||||
val bot: Long,
|
||||
val botId: Long,
|
||||
val ids: IntArray,
|
||||
val internalIds: IntArray,
|
||||
val time: Int,
|
||||
@ -51,49 +71,6 @@ public open class MessageSourceSerializerImpl(serialName: String) : KSerializer<
|
||||
val targetId: Long,
|
||||
val originalMessage: MessageChain,
|
||||
)
|
||||
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(serialName) {
|
||||
val desc = SerialData.serializer().descriptor
|
||||
repeat(SerialData.serializer().descriptor.elementsCount) { index ->
|
||||
element(
|
||||
desc.getElementName(index),
|
||||
desc.getElementDescriptor(index),
|
||||
desc.getElementAnnotations(index),
|
||||
desc.isElementOptional(index)
|
||||
)
|
||||
}
|
||||
}
|
||||
// buildClassSerialDescriptor("MessageSource") {
|
||||
// element("bot", Long.serializer().descriptor)
|
||||
// element("ids", ArraySerializer(Int.serializer()).descriptor)
|
||||
// element("internalIds", ArraySerializer(Int.serializer()).descriptor)
|
||||
// element("time", Int.serializer().descriptor)
|
||||
// element("fromId", Int.serializer().descriptor)
|
||||
// element("targetId", Int.serializer().descriptor)
|
||||
// element("originalMessage", MessageChain.Serializer.descriptor)
|
||||
// }
|
||||
|
||||
override fun deserialize(decoder: Decoder): MessageSource {
|
||||
val data = SerialData.serializer().deserialize(decoder)
|
||||
data.run {
|
||||
return Mirai.constructMessageSource(
|
||||
botId = bot, kind = kind, fromUin = fromId, targetUin = targetId, ids = ids,
|
||||
time = time, internalIds = internalIds, originalMessage = originalMessage.asMessageChain()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: MessageSource) {
|
||||
value.run {
|
||||
SerialData.serializer().serialize(
|
||||
encoder = encoder,
|
||||
value = SerialData(
|
||||
kind = kind, bot = botId, ids = ids, internalIds = internalIds,
|
||||
time = time, fromId = fromId, targetId = targetId, originalMessage = originalMessage
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -121,8 +98,6 @@ private val builtInSerializersModule by lazy {
|
||||
contextual(LightApp::class, LightApp.serializer())
|
||||
contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
|
||||
contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer())
|
||||
contextual(LongMessage::class, LongMessage.serializer())
|
||||
contextual(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
|
||||
|
||||
contextual(PttMessage::class, PttMessage.serializer())
|
||||
contextual(Voice::class, Voice.serializer())
|
||||
@ -130,12 +105,7 @@ private val builtInSerializersModule by lazy {
|
||||
contextual(VipFace::class, VipFace.serializer())
|
||||
contextual(FlashImage::class, FlashImage.serializer())
|
||||
|
||||
fun PolymorphicModuleBuilder<SingleMessage>.singleMessageSubclasses() {
|
||||
// subclass(MessageSource::class, MessageSource.serializer())
|
||||
}
|
||||
|
||||
// contextual(MessageSource::class, MessageSource.serializer())
|
||||
polymorphicDefault(MessageSource::class) { MessageSource.serializer() }
|
||||
contextual(MessageSource::class, MessageSource.serializer())
|
||||
|
||||
fun PolymorphicModuleBuilder<MessageMetadata>.messageMetadataSubclasses() {
|
||||
subclass(MessageSource::class, MessageSource.serializer())
|
||||
@ -154,8 +124,6 @@ private val builtInSerializersModule by lazy {
|
||||
|
||||
subclass(LightApp::class, LightApp.serializer())
|
||||
subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
|
||||
subclass(LongMessage::class, LongMessage.serializer())
|
||||
subclass(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
|
||||
|
||||
// subclass(PttMessage::class, PttMessage.serializer())
|
||||
subclass(Voice::class, Voice.serializer())
|
||||
@ -166,21 +134,11 @@ private val builtInSerializersModule by lazy {
|
||||
subclass(FlashImage::class, FlashImage.serializer())
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
contextual(Message::class, Message.Serializer)
|
||||
// contextual(SingleMessage::class, SingleMessage.Serializer)
|
||||
contextual(SingleMessage::class, SingleMessage.Serializer)
|
||||
contextual(MessageChain::class, MessageChain.Serializer)
|
||||
contextual(MessageChainImpl::class, MessageChainImpl.serializer())
|
||||
|
||||
polymorphic(MessageChain::class) {
|
||||
subclass(MessageChainImpl::class, MessageChainImpl.serializer())
|
||||
}
|
||||
polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() }
|
||||
|
||||
polymorphic(AbstractServiceMessage::class) {
|
||||
subclass(LongMessage::class, LongMessage.serializer())
|
||||
subclass(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
|
||||
}
|
||||
// polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() }
|
||||
|
||||
// polymorphic(SingleMessage::class) {
|
||||
// subclass(MessageSource::class, MessageSource.serializer())
|
||||
@ -189,16 +147,12 @@ private val builtInSerializersModule by lazy {
|
||||
// }
|
||||
// }
|
||||
|
||||
polymorphicDefault(Image::class) { Image.Serializer }
|
||||
|
||||
// polymorphic(Message::class) {
|
||||
// subclass(PlainText::class, PlainText.serializer())
|
||||
// }
|
||||
polymorphic(Message::class) {
|
||||
polymorphic(SingleMessage::class) {
|
||||
messageContentSubclasses()
|
||||
messageMetadataSubclasses()
|
||||
singleMessageSubclasses()
|
||||
subclass(MessageChainImpl::class, MessageChainImpl.serializer())
|
||||
}
|
||||
|
||||
//contextual(SingleMessage::class, SingleMessage.Serializer)
|
||||
@ -216,7 +170,7 @@ private val builtInSerializersModule by lazy {
|
||||
// contextual(MessageMetadata::class, MessageMetadata.Serializer)
|
||||
// polymorphic(MessageMetadata::class, MessageMetadata.Serializer) {
|
||||
// messageMetadataSubclasses()
|
||||
// }
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,22 +180,51 @@ internal object MessageSerializerImpl : MessageSerializer {
|
||||
override val serializersModule: SerializersModule get() = serializersModuleField ?: builtInSerializersModule
|
||||
|
||||
@Synchronized
|
||||
override fun <M : Message> registerSerializer(clazz: KClass<M>, serializer: KSerializer<M>) {
|
||||
serializersModuleField = serializersModule.plus(SerializersModule {
|
||||
contextual(clazz, serializer)
|
||||
polymorphic(Message::class) {
|
||||
subclass(clazz, serializer)
|
||||
override fun <M : SingleMessage> registerSerializer(baseClass: KClass<M>, serializer: KSerializer<M>) {
|
||||
serializersModuleField = serializersModule.overwriteWith(SerializersModule {
|
||||
contextual(baseClass, serializer)
|
||||
polymorphic(SingleMessage::class) {
|
||||
subclass(baseClass, serializer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun registerSerializers(serializersModule: SerializersModule) {
|
||||
serializersModuleField = serializersModule
|
||||
serializersModuleField = serializersModule.overwriteWith(serializersModule)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun clearRegisteredSerializers() {
|
||||
serializersModuleField = builtInSerializersModule
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T, R> KSerializer<T>.map(
|
||||
resultantDescriptor: SerialDescriptor,
|
||||
crossinline deserialize: T.(T) -> R,
|
||||
crossinline serialize: R.(R) -> T,
|
||||
): KSerializer<R> {
|
||||
return object : KSerializer<R> {
|
||||
override val descriptor: SerialDescriptor get() = resultantDescriptor
|
||||
override fun deserialize(decoder: Decoder): R = this@map.deserialize(decoder).let { deserialize(it, it) }
|
||||
override fun serialize(encoder: Encoder, value: R) = serialize(encoder, value.let { serialize(it, it) })
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <T, R> KSerializer<T>.mapPrimitive(
|
||||
serialName: String,
|
||||
crossinline deserialize: (T) -> R,
|
||||
crossinline serialize: R.(R) -> T,
|
||||
): KSerializer<R> {
|
||||
val kind = this@mapPrimitive.descriptor.kind
|
||||
check(kind is PrimitiveKind) { "kind must be PrimitiveKind but found $kind" }
|
||||
return object : KSerializer<R> {
|
||||
override fun deserialize(decoder: Decoder): R =
|
||||
this@mapPrimitive.deserialize(decoder).let(deserialize)
|
||||
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(serialName, kind)
|
||||
override fun serialize(encoder: Encoder, value: R) =
|
||||
this@mapPrimitive.serialize(encoder, value.let { serialize(it, it) })
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
@ -30,6 +31,7 @@ import net.mamoe.mirai.message.code.CodableMessage
|
||||
*
|
||||
* @see AtAll 全体成员
|
||||
*/
|
||||
@SerialName(At.SERIAL_NAME)
|
||||
@Serializable
|
||||
public data class At(
|
||||
public val target: Long,
|
||||
@ -51,7 +53,9 @@ public data class At(
|
||||
builder.append("[mirai:at:").append(target).append(']')
|
||||
}
|
||||
|
||||
public companion object;
|
||||
public companion object {
|
||||
public const val SERIAL_NAME: String = "At"
|
||||
}
|
||||
|
||||
// 自动为消息补充 " "
|
||||
public override fun followedBy(tail: Message): MessageChain {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
|
||||
@ -28,10 +29,12 @@ private const val displayA = "@全体成员"
|
||||
*
|
||||
* @see At at 单个群成员
|
||||
*/
|
||||
@SerialName(AtAll.SERIAL_NAME)
|
||||
@Serializable
|
||||
public object AtAll :
|
||||
MessageContent, CodableMessage {
|
||||
public const val display: String = displayA
|
||||
public const val SERIAL_NAME: String = "AtAll"
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
public override fun toString(): String = "[mirai:atall]"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
|
||||
@ -22,10 +23,11 @@ import net.mamoe.mirai.message.code.CodableMessage
|
||||
* 格式: [mirai:face:*[id]*]
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName(Face.SERIAL_NAME)
|
||||
public data class Face(public val id: Int) : // used in delegation
|
||||
MessageContent, CodableMessage {
|
||||
|
||||
public override fun toString(): String = "[mirai:face:$id]";
|
||||
public override fun toString(): String = "[mirai:face:$id]"
|
||||
public val name: String get() = contentToString().let { it.substring(1, it.length - 1) }
|
||||
public override fun contentToString(): String = names.getOrElse(id) { "[表情]" }
|
||||
|
||||
@ -39,6 +41,9 @@ public data class Face(public val id: Int) : // used in delegation
|
||||
//Auto generated
|
||||
@Suppress("NonAsciiCharacters", "unused", "SpellCheckingInspection", "all")
|
||||
public companion object {
|
||||
public const val SERIAL_NAME: String = "Face"
|
||||
|
||||
|
||||
public const val JING_YA: Int = 0
|
||||
public const val 惊讶: Int = JING_YA
|
||||
public const val PIE_ZUI: Int = 1
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,6 +13,7 @@ package net.mamoe.mirai.message.data
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.util.*
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
@ -96,6 +97,7 @@ public data class RawForwardMessage(
|
||||
*
|
||||
* @see buildForwardMessage
|
||||
*/
|
||||
@SerialName(ForwardMessage.SERIAL_NAME)
|
||||
@Serializable
|
||||
public data class ForwardMessage(
|
||||
val preview: List<String>,
|
||||
@ -136,7 +138,7 @@ public data class ForwardMessage(
|
||||
* Java 用户: 使用 [sequenceOf] (`SequenceKt.sequenceOf`) 或 [asSequence] (`SequenceKt.asSequence`)
|
||||
*/
|
||||
public fun generatePreview(forward: RawForwardMessage): List<String> =
|
||||
forward.nodeList.map { it.senderName + ": " + it.message.contentToString() }
|
||||
forward.nodeList.map { it.senderName + ": " + it.messageChain.contentToString() }
|
||||
|
||||
/**
|
||||
* 显示在卡片底部
|
||||
@ -152,8 +154,15 @@ public data class ForwardMessage(
|
||||
override val senderId: Long,
|
||||
override val time: Int,
|
||||
override val senderName: String,
|
||||
override val message: Message
|
||||
) : INode
|
||||
override val messageChain: MessageChain
|
||||
) : INode {
|
||||
public constructor(
|
||||
senderId: Long,
|
||||
time: Int,
|
||||
senderName: String,
|
||||
message: Message
|
||||
) : this(senderId, time, senderName, message.asMessageChain())
|
||||
}
|
||||
|
||||
@MiraiExperimentalApi
|
||||
public interface INode {
|
||||
@ -175,11 +184,13 @@ public data class ForwardMessage(
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
public val message: Message
|
||||
public val messageChain: MessageChain
|
||||
}
|
||||
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<MessageContent, ForwardMessage>(MessageContent, { it.safeCast() })
|
||||
AbstractPolymorphicMessageKey<MessageContent, ForwardMessage>(MessageContent, { it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "ForwardMessage"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -358,7 +369,7 @@ public class ForwardMessageBuilder private constructor(
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
public override lateinit var message: Message
|
||||
public override lateinit var messageChain: MessageChain
|
||||
|
||||
|
||||
/**
|
||||
@ -410,19 +421,21 @@ public class ForwardMessageBuilder private constructor(
|
||||
* 指定消息内容
|
||||
*/
|
||||
@ForwardMessageDsl
|
||||
public infix fun message(message: Message): BuilderNode = this.apply { this.message = message }
|
||||
public infix fun message(message: Message): BuilderNode =
|
||||
this.apply { this.messageChain = message.asMessageChain() }
|
||||
|
||||
/**
|
||||
* 指定消息内容
|
||||
*/
|
||||
@ForwardMessageDsl
|
||||
public infix fun message(message: String): BuilderNode = this.apply { this.message = PlainText(message) }
|
||||
public infix fun message(message: String): BuilderNode =
|
||||
this.apply { this.messageChain = PlainText(message).asMessageChain() }
|
||||
|
||||
/** 添加一条消息 */
|
||||
@ForwardMessageDsl
|
||||
public infix fun says(message: Message): ForwardMessageBuilder = this@ForwardMessageBuilder.apply {
|
||||
checkBuilt()
|
||||
this@BuilderNode.message = message
|
||||
this@BuilderNode.messageChain = message.asMessageChain()
|
||||
add(this@BuilderNode)
|
||||
}
|
||||
|
||||
@ -454,7 +467,7 @@ public class ForwardMessageBuilder private constructor(
|
||||
checkBuilt()
|
||||
add(BuilderNode().apply {
|
||||
senderId = this@says
|
||||
this.message = message
|
||||
this.messageChain = message.asMessageChain()
|
||||
})
|
||||
}
|
||||
|
||||
@ -551,7 +564,7 @@ public class ForwardMessageBuilder private constructor(
|
||||
it.senderId,
|
||||
it.time,
|
||||
it.senderName,
|
||||
it.message
|
||||
it.messageChain
|
||||
)
|
||||
}).render(this.displayStrategy)
|
||||
|
||||
@ -565,5 +578,5 @@ public class ForwardMessageBuilder private constructor(
|
||||
internal inline fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF)
|
||||
|
||||
private fun ForwardMessage.INode.toNode(): ForwardMessage.Node {
|
||||
return ForwardMessage.Node(senderId, time, senderName, message)
|
||||
return ForwardMessage.Node(senderId, time, senderName, messageChain)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
@ -46,6 +46,7 @@ public interface HummerMessage : MessageContent, ConstrainSingle {
|
||||
*
|
||||
* @see PokeMessage.Companion 使用伴生对象中的常量
|
||||
*/
|
||||
@SerialName(PokeMessage.SERIAL_NAME)
|
||||
@Serializable
|
||||
public data class PokeMessage @MiraiInternalApi constructor(
|
||||
/**
|
||||
@ -63,6 +64,8 @@ public data class PokeMessage @MiraiInternalApi constructor(
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<HummerMessage, PokeMessage>(HummerMessage, { it.castOrNull() }) {
|
||||
|
||||
public const val SERIAL_NAME: String = "PokeMessage"
|
||||
|
||||
/** 戳一戳 */
|
||||
@JvmField
|
||||
public val ChuoYiChuo: PokeMessage = PokeMessage("戳一戳", 1, -1)
|
||||
@ -195,7 +198,9 @@ public interface MarketFace : HummerMessage {
|
||||
get() = Key
|
||||
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<HummerMessage, MarketFace>(HummerMessage, { it.safeCast() })
|
||||
AbstractPolymorphicMessageKey<HummerMessage, MarketFace>(HummerMessage, { it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "MarketFace"
|
||||
}
|
||||
|
||||
override fun contentToString(): String = name
|
||||
}
|
||||
@ -215,6 +220,7 @@ public interface MarketFace : HummerMessage {
|
||||
*
|
||||
* @see VipFace.Key 使用伴生对象中的常量
|
||||
*/
|
||||
@SerialName(VipFace.SERIAL_NAME)
|
||||
@Serializable
|
||||
public data class VipFace @MiraiInternalApi constructor(
|
||||
/**
|
||||
@ -239,6 +245,8 @@ public data class VipFace @MiraiInternalApi constructor(
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<HummerMessage, VipFace>(HummerMessage, { it.safeCast() }) {
|
||||
|
||||
public const val SERIAL_NAME: String = "VipFace"
|
||||
|
||||
@JvmField
|
||||
public val LiuLian: Kind = 9 to "榴莲"
|
||||
|
||||
@ -310,12 +318,14 @@ public data class VipFace @MiraiInternalApi constructor(
|
||||
*
|
||||
* @see Image 查看图片相关信息
|
||||
*/
|
||||
@SerialName(FlashImage.SERIAL_NAME)
|
||||
@Serializable
|
||||
public data class FlashImage(
|
||||
/**
|
||||
* 闪照的内容图片, 即一个普通图片.
|
||||
*/
|
||||
@Contextual
|
||||
@SerialName("imageId")
|
||||
@Serializable(Image.AsStringSerializer::class)
|
||||
public val image: Image
|
||||
) : MessageContent, HummerMessage, CodableMessage, ConstrainSingle {
|
||||
override val key: MessageKey<FlashImage>
|
||||
@ -323,6 +333,7 @@ public data class FlashImage(
|
||||
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<HummerMessage, FlashImage>(HummerMessage, { it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "FlashImage"
|
||||
|
||||
/**
|
||||
* 将普通图片转换为闪照.
|
||||
|
@ -20,14 +20,10 @@
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.encoding.decodeStructure
|
||||
import kotlinx.serialization.encoding.encodeStructure
|
||||
import net.mamoe.kjbb.JvmBlockingBridge
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.IMirai
|
||||
@ -40,6 +36,8 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
|
||||
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||
import net.mamoe.mirai.message.data.Image.Key.queryUrl
|
||||
import net.mamoe.mirai.message.map
|
||||
import net.mamoe.mirai.message.mapPrimitive
|
||||
import net.mamoe.mirai.utils.ExternalResource
|
||||
import net.mamoe.mirai.utils.ExternalResource.Companion.sendAsImageTo
|
||||
import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage
|
||||
@ -90,26 +88,32 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
*/
|
||||
public val imageId: String
|
||||
|
||||
public object Serializer : KSerializer<Image> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("net.mamoe.mirai.message.data.Image") {
|
||||
element("imageId", String.serializer().descriptor)
|
||||
}
|
||||
@kotlinx.serialization.Serializer(forClass = Image::class)
|
||||
public object AsStringSerializer : KSerializer<Image> by String.serializer().mapPrimitive(
|
||||
SERIAL_NAME,
|
||||
serialize = { imageId },
|
||||
deserialize = { Image(it) },
|
||||
)
|
||||
|
||||
override fun deserialize(decoder: Decoder): Image = decoder.decodeStructure(descriptor) {
|
||||
val imageId = if (decodeSequentially()) {
|
||||
decodeStringElement(descriptor, 0)
|
||||
} else {
|
||||
decodeStringElement(descriptor, decodeElementIndex(descriptor))
|
||||
}
|
||||
Image(imageId)
|
||||
}
|
||||
@kotlinx.serialization.Serializer(forClass = Image::class)
|
||||
public object Serializer : KSerializer<Image> by FallbackSerializer("Image")
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Image): Unit = encoder.encodeStructure(descriptor) {
|
||||
encodeStringElement(descriptor, 0, value.imageId)
|
||||
}
|
||||
@MiraiInternalApi
|
||||
public open class FallbackSerializer(serialName: String) : KSerializer<Image> by Delegate.serializer().map(
|
||||
buildClassSerialDescriptor(serialName) { element("imageId", String.serializer().descriptor) },
|
||||
serialize = { Delegate(imageId) },
|
||||
deserialize = { Image(imageId) },
|
||||
) {
|
||||
@SerialName(SERIAL_NAME)
|
||||
@Serializable
|
||||
internal data class Delegate(
|
||||
val imageId: String
|
||||
)
|
||||
}
|
||||
|
||||
public companion object Key : AbstractMessageKey<Image>({ it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "Image"
|
||||
|
||||
/**
|
||||
* 通过 [Image.imageId] 构造一个 [Image] 以便发送.
|
||||
* 这个图片必须是服务器已经存在的图片.
|
||||
@ -148,8 +152,9 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
@Suppress("RegExpRedundantEscape") // This is required on Android
|
||||
@JvmStatic
|
||||
@get:JvmName("getImageIdRegex")
|
||||
public val IMAGE_ID_REGEX: Regex =
|
||||
Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""")
|
||||
// inline because compilation error
|
||||
public inline val IMAGE_ID_REGEX: Regex
|
||||
get() = Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""")
|
||||
|
||||
/**
|
||||
* 图片资源 ID 正则表达式 1. mirai 内部使用.
|
||||
@ -160,7 +165,9 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
@JvmStatic
|
||||
@MiraiInternalApi
|
||||
@get:JvmName("getImageResourceIdRegex1")
|
||||
public val IMAGE_RESOURCE_ID_REGEX_1: Regex = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""")
|
||||
// inline because compilation error
|
||||
public inline val IMAGE_RESOURCE_ID_REGEX_1: Regex
|
||||
get() = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""")
|
||||
|
||||
/**
|
||||
* 图片资源 ID 正则表达式 2. mirai 内部使用.
|
||||
@ -171,7 +178,9 @@ public interface Image : Message, MessageContent, CodableMessage {
|
||||
@JvmStatic
|
||||
@MiraiInternalApi
|
||||
@get:JvmName("getImageResourceIdRegex2")
|
||||
public val IMAGE_RESOURCE_ID_REGEX_2: Regex = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""")
|
||||
// inline because compilation error
|
||||
public inline val IMAGE_RESOURCE_ID_REGEX_2: Regex
|
||||
get() = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -20,12 +20,9 @@ package net.mamoe.mirai.message.data
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.fold
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.MessageSerializer
|
||||
import net.mamoe.mirai.message.MessageSerializerImpl
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
import kotlin.contracts.contract
|
||||
@ -73,8 +70,6 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
||||
*
|
||||
* @see Contact.sendMessage 发送消息
|
||||
*/
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
@Serializable(Message.Serializer::class)
|
||||
public interface Message { // must be interface. Don't consider any changes.
|
||||
|
||||
/**
|
||||
@ -198,50 +193,7 @@ public interface Message { // must be interface. Don't consider any changes.
|
||||
public operator fun plus(another: Sequence<Message>): MessageChain =
|
||||
another.fold(this, Message::plus).asMessageChain()
|
||||
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
public object Serializer :
|
||||
MessageSerializer by MessageSerializerImpl,
|
||||
KSerializer<Message> by PolymorphicSerializer(Message::class)
|
||||
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
public companion object {
|
||||
/**
|
||||
* 从 JSON 字符串解析 [Message]
|
||||
* @see serializeToJsonString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
public fun deserializeFromJsonString(
|
||||
string: String,
|
||||
json: Json = Json { serializersModule = Serializer.serializersModule }
|
||||
): Message {
|
||||
return json.decodeFromString(Serializer, string)
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 [Message] 序列化为 JSON 字符串.
|
||||
* @see deserializeFromJsonString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
public fun Message.serializeToJsonString(
|
||||
json: Json = Json { serializersModule = Serializer.serializersModule }
|
||||
): String = json.encodeToString(Serializer, this)
|
||||
|
||||
/**
|
||||
* 将 [Message] 序列化为指定格式的字符串.
|
||||
*
|
||||
* @see serializeToJsonString
|
||||
* @see StringFormat.encodeToString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@ExperimentalSerializationApi
|
||||
@JvmStatic
|
||||
public fun Message.serializeToString(format: StringFormat): String =
|
||||
format.encodeToString(Serializer, this)
|
||||
}
|
||||
public companion object
|
||||
}
|
||||
|
||||
|
||||
@ -320,10 +272,11 @@ public inline operator fun Message.times(count: Int): MessageChain = this.repeat
|
||||
/**
|
||||
* 单个消息元素. 与之相对的是 [MessageChain], 是多个 [SingleMessage] 的集合.
|
||||
*/
|
||||
// @Serializable(SingleMessage.Serializer::class)
|
||||
@Serializable(SingleMessage.Serializer::class)
|
||||
public interface SingleMessage : Message {
|
||||
// @kotlinx.serialization.Serializer(forClass = SingleMessage::class)
|
||||
// public object Serializer : KSerializer<SingleMessage> by PolymorphicSerializer(SingleMessage::class)
|
||||
@kotlinx.serialization.Serializer(forClass = SingleMessage::class)
|
||||
public object Serializer :
|
||||
KSerializer<SingleMessage> by PolymorphicSerializer(SingleMessage::class)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -339,14 +292,11 @@ public interface SingleMessage : Message {
|
||||
*
|
||||
* @see ConstrainSingle 约束一个 [MessageChain] 中只存在这一种类型的元素
|
||||
*/
|
||||
@Serializable(MessageMetadata.Serializer::class)
|
||||
public interface MessageMetadata : SingleMessage {
|
||||
/**
|
||||
* 返回空字符串
|
||||
*/
|
||||
override fun contentToString(): String = ""
|
||||
|
||||
public object Serializer : KSerializer<MessageMetadata> by PolymorphicSerializer(MessageMetadata::class)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,11 +331,8 @@ public interface ConstrainSingle : SingleMessage {
|
||||
* @see ForwardMessage 合并转发
|
||||
* @see Voice 语音
|
||||
*/
|
||||
@Serializable(MessageContent.Serializer::class)
|
||||
public interface MessageContent : SingleMessage {
|
||||
public companion object Key : AbstractMessageKey<MessageContent>({ it.safeCast() })
|
||||
|
||||
public object Serializer : KSerializer<MessageContent> by PolymorphicSerializer(MessageContent::class)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -20,6 +20,7 @@ import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.mamoe.mirai.event.events.MessageEvent
|
||||
import net.mamoe.mirai.message.MessageSerializerImpl
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.quote
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.recall
|
||||
@ -92,9 +93,10 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
|
||||
public operator fun <M : SingleMessage> contains(key: MessageKey<M>): Boolean =
|
||||
asSequence().any { key.safeCast.invoke(it) != null }
|
||||
|
||||
@kotlinx.serialization.Serializer(MessageChain::class)
|
||||
public object Serializer : KSerializer<MessageChain> {
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
private val delegate = ListSerializer<Message>(Message.Serializer)
|
||||
private val delegate = ListSerializer(PolymorphicSerializer(SingleMessage::class))
|
||||
override val descriptor: SerialDescriptor = delegate.descriptor
|
||||
override fun deserialize(decoder: Decoder): MessageChain = delegate.deserialize(decoder).asMessageChain()
|
||||
override fun serialize(encoder: Encoder, value: MessageChain): Unit = delegate.serialize(encoder, value)
|
||||
@ -110,12 +112,11 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
|
||||
* 从 JSON 字符串解析 [MessageChain]
|
||||
* @see serializeToJsonString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
public fun deserializeFromJsonString(
|
||||
string: String,
|
||||
json: Json = Json { serializersModule = Message.Serializer.serializersModule }
|
||||
json: Json = Json { serializersModule = MessageSerializerImpl.serializersModule }
|
||||
): MessageChain {
|
||||
return json.decodeFromString(Serializer, string)
|
||||
}
|
||||
@ -124,12 +125,11 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
|
||||
* 将 [MessageChain] 序列化为 JSON 字符串.
|
||||
* @see deserializeFromJsonString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
public fun MessageChain.serializeToJsonString(
|
||||
json: Json = Json { serializersModule = Message.Serializer.serializersModule }
|
||||
): String = json.encodeToString(Message.Serializer, this)
|
||||
json: Json = Json { serializersModule = MessageSerializerImpl.serializersModule }
|
||||
): String = json.encodeToString(MessageChain.Serializer, this)
|
||||
|
||||
/**
|
||||
* 将 [MessageChain] 序列化为指定格式的字符串.
|
||||
@ -137,7 +137,6 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
|
||||
* @see serializeToJsonString
|
||||
* @see StringFormat.encodeToString
|
||||
*/
|
||||
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
|
||||
@ExperimentalSerializationApi
|
||||
@JvmStatic
|
||||
public fun MessageChain.serializeToString(format: StringFormat): String =
|
||||
|
@ -36,7 +36,6 @@ public interface MessageKey<out M : SingleMessage> {
|
||||
* @see AbstractPolymorphicMessageKey
|
||||
*/
|
||||
public abstract class AbstractMessageKey<out M : SingleMessage>(
|
||||
@JvmField
|
||||
override val safeCast: (SingleMessage) -> M?,
|
||||
) : MessageKey<M>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -68,7 +68,7 @@ import net.mamoe.mirai.utils.safeCast
|
||||
*
|
||||
* @see buildMessageSource 构造一个 [OfflineMessageSource]
|
||||
*/
|
||||
@Serializable(MessageSourceSerializerImpl.Companion::class)
|
||||
@Serializable(MessageSource.Serializer::class)
|
||||
public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
|
||||
public final override val key: MessageKey<MessageSource>
|
||||
get() = Key
|
||||
@ -150,7 +150,11 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
|
||||
public final override fun toString(): String =
|
||||
"[mirai:source:${ids.contentToString()},${internalIds.contentToString()}]"
|
||||
|
||||
public object Serializer : MessageSourceSerializerImpl("MessageSource")
|
||||
|
||||
public companion object Key : AbstractMessageKey<MessageSource>({ it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "MessageSource"
|
||||
|
||||
/**
|
||||
* 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
|
||||
*
|
||||
@ -361,7 +365,8 @@ public sealed class OnlineMessageSource : MessageSource() {
|
||||
}
|
||||
|
||||
public abstract class ToStranger : Outgoing() {
|
||||
public companion object Key : AbstractPolymorphicMessageKey<Outgoing, ToStranger>(Outgoing, { it.safeCast() })
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<Outgoing, ToStranger>(Outgoing, { it.safeCast() })
|
||||
|
||||
public abstract override val target: Stranger
|
||||
public final override val subject: Stranger get() = target
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
@ -23,6 +24,7 @@ import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
* 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [Message.plus]
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName(PlainText.SERIAL_NAME)
|
||||
public data class PlainText(
|
||||
public val content: String
|
||||
) : MessageContent, CodableMessage {
|
||||
@ -36,7 +38,9 @@ public data class PlainText(
|
||||
builder.appendAsMiraiCode(content)
|
||||
}
|
||||
|
||||
public companion object
|
||||
public companion object {
|
||||
public const val SERIAL_NAME: String = "PlainText"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.message.data.MessageSource.Key.recall
|
||||
@ -40,8 +41,13 @@ import net.mamoe.mirai.utils.safeCast
|
||||
* @see MessageSource 获取有关消息源的更多信息
|
||||
*/
|
||||
@Serializable
|
||||
public data class QuoteReply(public val source: MessageSource) : Message, MessageMetadata, ConstrainSingle {
|
||||
public companion object Key : AbstractMessageKey<QuoteReply>({ it.safeCast() })
|
||||
@SerialName(QuoteReply.SERIAL_NAME)
|
||||
public data class QuoteReply(
|
||||
public val source: MessageSource
|
||||
) : Message, MessageMetadata, ConstrainSingle {
|
||||
public companion object Key : AbstractMessageKey<QuoteReply>({ it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "QuoteReply"
|
||||
}
|
||||
|
||||
public override val key: MessageKey<QuoteReply> get() = Key
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.message.code.CodableMessage
|
||||
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
|
||||
@ -95,8 +96,11 @@ public interface RichMessage : MessageContent, ConstrainSingle {
|
||||
* @see ServiceMessage 服务消息
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName(LightApp.SERIAL_NAME)
|
||||
public data class LightApp(override val content: String) : RichMessage, CodableMessage {
|
||||
public companion object Key : AbstractMessageKey<LightApp>({ it.safeCast() })
|
||||
public companion object Key : AbstractMessageKey<LightApp>({ it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "LightApp"
|
||||
}
|
||||
|
||||
public override fun toString(): String = "[mirai:app:$content]"
|
||||
|
||||
@ -117,6 +121,7 @@ public data class LightApp(override val content: String) : RichMessage, CodableM
|
||||
*/
|
||||
@MiraiExperimentalApi
|
||||
@Serializable
|
||||
@SerialName(SimpleServiceMessage.SERIAL_NAME)
|
||||
public class SimpleServiceMessage(
|
||||
public override val serviceId: Int,
|
||||
public override val content: String
|
||||
@ -136,6 +141,9 @@ public class SimpleServiceMessage(
|
||||
return result
|
||||
}
|
||||
|
||||
public companion object {
|
||||
public const val SERIAL_NAME: String = "SimpleServiceMessage"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -257,8 +265,7 @@ public class XmlMessageBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@MiraiExperimentalApi
|
||||
// internal runtime value, not serializable
|
||||
internal data class LongMessage internal constructor(override val content: String, val resId: String) :
|
||||
AbstractServiceMessage() {
|
||||
override val serviceId: Int get() = 35
|
||||
@ -266,7 +273,7 @@ internal data class LongMessage internal constructor(override val content: Strin
|
||||
companion object Key : AbstractPolymorphicMessageKey<ServiceMessage, LongMessage>(ServiceMessage, { it.safeCast() })
|
||||
}
|
||||
|
||||
@Serializable
|
||||
// internal runtime value, not serializable
|
||||
internal data class ForwardMessageInternal(override val content: String) : AbstractServiceMessage() {
|
||||
override val serviceId: Int get() = 35
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
@ -40,6 +41,7 @@ public abstract class PttMessage : MessageContent {
|
||||
* 语音消息, 目前只支持接收和转发
|
||||
*/
|
||||
@Serializable // experimental
|
||||
@SerialName(Voice.SERIAL_NAME)
|
||||
public class Voice @MiraiInternalApi constructor(
|
||||
@MiraiExperimentalApi public override val fileName: String,
|
||||
@MiraiExperimentalApi public override val md5: ByteArray,
|
||||
@ -49,7 +51,9 @@ public class Voice @MiraiInternalApi constructor(
|
||||
private val _url: String
|
||||
) : PttMessage() {
|
||||
|
||||
public companion object Key : AbstractPolymorphicMessageKey<PttMessage, Voice>(PttMessage, { it.safeCast() })
|
||||
public companion object Key : AbstractPolymorphicMessageKey<PttMessage, Voice>(PttMessage, { it.safeCast() }) {
|
||||
public const val SERIAL_NAME: String = "Voice"
|
||||
}
|
||||
|
||||
public val url: String?
|
||||
get() = when {
|
||||
|
@ -156,7 +156,7 @@ internal fun <M : SingleMessage> MessageChain.getImpl(key: MessageKey<M>): M? {
|
||||
/**
|
||||
* 使用 [Collection] 作为委托的 [MessageChain]
|
||||
*/
|
||||
@Serializable
|
||||
@Serializable(MessageChain.Serializer::class)
|
||||
internal data class MessageChainImpl constructor(
|
||||
@JvmField
|
||||
internal val delegate: List<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable
|
||||
|
@ -34,6 +34,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.MessageSerializer
|
||||
import net.mamoe.mirai.message.action.Nudge
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
|
||||
@ -50,17 +51,54 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
companion object INSTANCE : MiraiImpl() {
|
||||
@Suppress("ObjectPropertyName", "unused", "DEPRECATION_ERROR")
|
||||
private val _init = Mirai.let {
|
||||
Message.Serializer.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer())
|
||||
Message.Serializer.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer())
|
||||
Message.Serializer.registerSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer())
|
||||
Message.Serializer.registerSerializer(
|
||||
MessageSerializer.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer())
|
||||
MessageSerializer.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer())
|
||||
MessageSerializer.registerSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer())
|
||||
MessageSerializer.registerSerializer(OnlineGroupImageImpl::class, OnlineGroupImageImpl.serializer())
|
||||
|
||||
MessageSerializer.registerSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer())
|
||||
|
||||
// MessageSource
|
||||
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceFromGroupImpl::class,
|
||||
OnlineMessageSourceFromGroupImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceFromFriendImpl::class,
|
||||
OnlineMessageSourceFromFriendImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceFromTempImpl::class,
|
||||
OnlineMessageSourceFromTempImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceFromStrangerImpl::class,
|
||||
OnlineMessageSourceFromStrangerImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceToGroupImpl::class,
|
||||
OnlineMessageSourceToGroupImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceToFriendImpl::class,
|
||||
OnlineMessageSourceToFriendImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceToTempImpl::class,
|
||||
OnlineMessageSourceToTempImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OnlineMessageSourceToStrangerImpl::class,
|
||||
OnlineMessageSourceToStrangerImpl.serializer()
|
||||
)
|
||||
MessageSerializer.registerSerializer(
|
||||
OfflineMessageSourceImplData::class,
|
||||
OfflineMessageSourceImplData.serializer()
|
||||
)
|
||||
|
||||
Message.Serializer.registerSerializer(
|
||||
MessageSourceFromGroupImpl::class,
|
||||
MessageSourceFromGroupImpl.serializer()
|
||||
MessageSerializer.registerSerializer(
|
||||
OfflineMessageSourceImplData::class,
|
||||
OfflineMessageSourceImplData.serializer()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -305,12 +343,12 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
}
|
||||
|
||||
val response: PbMessageSvc.PbMsgWithDraw.Response = when (source) {
|
||||
is MessageSourceToGroupImpl,
|
||||
is MessageSourceFromGroupImpl
|
||||
is OnlineMessageSourceToGroupImpl,
|
||||
is OnlineMessageSourceFromGroupImpl
|
||||
-> {
|
||||
val group = when (source) {
|
||||
is MessageSourceToGroupImpl -> source.target
|
||||
is MessageSourceFromGroupImpl -> source.group
|
||||
is OnlineMessageSourceToGroupImpl -> source.target
|
||||
is OnlineMessageSourceFromGroupImpl -> source.group
|
||||
else -> error("stub")
|
||||
}
|
||||
if (bot.id != source.fromId) {
|
||||
@ -326,10 +364,10 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
}
|
||||
is MessageSourceFromFriendImpl,
|
||||
is MessageSourceToFriendImpl,
|
||||
is MessageSourceFromStrangerImpl,
|
||||
is MessageSourceToStrangerImpl,
|
||||
is OnlineMessageSourceFromFriendImpl,
|
||||
is OnlineMessageSourceToFriendImpl,
|
||||
is OnlineMessageSourceFromStrangerImpl,
|
||||
is OnlineMessageSourceToStrangerImpl,
|
||||
-> network.run {
|
||||
check(source.fromId == bot.id) {
|
||||
"can only recall a message sent by bot"
|
||||
@ -342,13 +380,13 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
is MessageSourceFromTempImpl,
|
||||
is MessageSourceToTempImpl
|
||||
is OnlineMessageSourceFromTempImpl,
|
||||
is OnlineMessageSourceToTempImpl
|
||||
-> network.run {
|
||||
check(source.fromId == bot.id) {
|
||||
"can only recall a message sent by bot"
|
||||
}
|
||||
source as MessageSourceToTempImpl
|
||||
source as OnlineMessageSourceToTempImpl
|
||||
PbMessageSvc.PbMsgWithDraw.createForTempMessage(
|
||||
bot.client,
|
||||
(source.target.group as GroupImpl).uin,
|
||||
@ -592,7 +630,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
forwardMessage: ForwardMessage?
|
||||
): MessageReceipt<Group> = with(bot.asQQAndroidBot()) {
|
||||
message.forEach {
|
||||
it.message.ensureSequenceIdAvailable()
|
||||
it.messageChain.ensureSequenceIdAvailable()
|
||||
}
|
||||
|
||||
val group = getGroupOrFail(groupCode)
|
||||
@ -655,7 +693,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
||||
if (isLong) {
|
||||
group.sendMessage(
|
||||
RichMessage.longMessage(
|
||||
brief = message.joinToString(limit = 27) { it.message.contentToString() },
|
||||
brief = message.joinToString(limit = 27) { it.messageChain.contentToString() },
|
||||
resId = resId,
|
||||
timeSeconds = time
|
||||
)
|
||||
|
@ -170,7 +170,7 @@ internal class GroupImpl(
|
||||
ForwardMessage.Node(
|
||||
senderId = bot.id,
|
||||
time = currentTimeSeconds().toInt(),
|
||||
message = chain,
|
||||
messageChain = chain,
|
||||
senderName = bot.nick
|
||||
)
|
||||
),
|
||||
@ -195,7 +195,7 @@ internal class GroupImpl(
|
||||
}
|
||||
|
||||
val result = bot.network.runCatching {
|
||||
val source: MessageSourceToGroupImpl
|
||||
val source: OnlineMessageSourceToGroupImpl
|
||||
MessageSvcPbSendMsg.createToGroup(
|
||||
bot.client,
|
||||
this@GroupImpl,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -19,7 +19,7 @@ import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToTempImpl
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceToTempImpl
|
||||
import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
|
||||
import net.mamoe.mirai.internal.message.firstIsInstanceOrNull
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
|
||||
@ -81,7 +81,7 @@ internal class NormalMemberImpl constructor(
|
||||
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
|
||||
|
||||
val result = bot.network.runCatching {
|
||||
val source: MessageSourceToTempImpl
|
||||
val source: OnlineMessageSourceToTempImpl
|
||||
MessageSvcPbSendMsg.createToTemp(
|
||||
bot.client,
|
||||
this@NormalMemberImpl,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -16,8 +16,8 @@ import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.asQQAndroidBot
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToFriendImpl
|
||||
import net.mamoe.mirai.internal.message.MessageSourceToStrangerImpl
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceToFriendImpl
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceToStrangerImpl
|
||||
import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToFriend
|
||||
@ -37,8 +37,8 @@ internal inline val Bot.uin: Long get() = this.id
|
||||
|
||||
internal suspend fun <T : User> Friend.sendMessageImpl(
|
||||
message: Message,
|
||||
friendReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<Friend>,
|
||||
tReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<T>
|
||||
friendReceiptConstructor: (OnlineMessageSourceToFriendImpl) -> MessageReceipt<Friend>,
|
||||
tReceiptConstructor: (OnlineMessageSourceToFriendImpl) -> MessageReceipt<T>
|
||||
): MessageReceipt<T> {
|
||||
contract { callsInPlace(friendReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
|
||||
val bot = bot.asQQAndroidBot()
|
||||
@ -56,7 +56,7 @@ internal suspend fun <T : User> Friend.sendMessageImpl(
|
||||
|
||||
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
|
||||
|
||||
lateinit var source: MessageSourceToFriendImpl
|
||||
lateinit var source: OnlineMessageSourceToFriendImpl
|
||||
val result = bot.network.runCatching {
|
||||
MessageSvcPbSendMsg.createToFriend(
|
||||
bot.client,
|
||||
@ -89,8 +89,8 @@ internal suspend fun <T : User> Friend.sendMessageImpl(
|
||||
|
||||
internal suspend fun <T : User> Stranger.sendMessageImpl(
|
||||
message: Message,
|
||||
strangerReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<Stranger>,
|
||||
tReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<T>
|
||||
strangerReceiptConstructor: (OnlineMessageSourceToStrangerImpl) -> MessageReceipt<Stranger>,
|
||||
tReceiptConstructor: (OnlineMessageSourceToStrangerImpl) -> MessageReceipt<T>
|
||||
): MessageReceipt<T> {
|
||||
contract { callsInPlace(strangerReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
|
||||
val bot = bot.asQQAndroidBot()
|
||||
@ -108,7 +108,7 @@ internal suspend fun <T : User> Stranger.sendMessageImpl(
|
||||
|
||||
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
|
||||
|
||||
lateinit var source: MessageSourceToStrangerImpl
|
||||
lateinit var source: OnlineMessageSourceToStrangerImpl
|
||||
val result = bot.network.runCatching {
|
||||
MessageSvcPbSendMsg.createToStranger(
|
||||
bot.client,
|
||||
|
@ -328,13 +328,13 @@ internal fun List<MsgComm.Msg>.toMessageChain(
|
||||
checkNotNull(bot) { "bot is null" }
|
||||
|
||||
when (messageSourceKind) {
|
||||
MessageSourceKind.TEMP -> +MessageSourceFromTempImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.GROUP -> +MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.FRIEND -> +MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.STRANGER -> +MessageSourceFromStrangerImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.TEMP -> +OnlineMessageSourceFromTempImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.GROUP -> +OnlineMessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.FRIEND -> +OnlineMessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
MessageSourceKind.STRANGER -> +OnlineMessageSourceFromStrangerImpl(bot, this@toMessageChain)
|
||||
}
|
||||
} else {
|
||||
+OfflineMessageSourceImplByMsg(bot, this@toMessageChain, botId)
|
||||
+OfflineMessageSourceImplData(bot, this@toMessageChain, botId)
|
||||
}
|
||||
elements.joinToMessageChain(groupIdOrZero, botId, this)
|
||||
addAll(ptts)
|
||||
@ -348,7 +348,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(botId: Long, groupIdOrZero: Long
|
||||
if (elements.isEmpty())
|
||||
error("elements for SourceMsg is empty")
|
||||
return buildMessageChain(elements.size + 1) {
|
||||
+OfflineMessageSourceImplBySourceMsg(
|
||||
+OfflineMessageSourceImplData(
|
||||
delegate = this@toMessageChain,
|
||||
botId = botId,
|
||||
groupIdOrZero = groupIdOrZero
|
||||
@ -422,7 +422,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, botId:
|
||||
this.forEach { element ->
|
||||
when {
|
||||
element.srcMsg != null -> {
|
||||
list.add(QuoteReply(OfflineMessageSourceImplBySourceMsg(element.srcMsg, botId, groupIdOrZero)))
|
||||
list.add(QuoteReply(OfflineMessageSourceImplData(element.srcMsg, botId, groupIdOrZero)))
|
||||
}
|
||||
element.notOnlineImage != null -> list.add(OnlineFriendImageImpl(element.notOnlineImage))
|
||||
element.customFace != null -> list.add(OnlineGroupImageImpl(element.customFace))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -10,6 +10,7 @@
|
||||
package net.mamoe.mirai.internal.message
|
||||
|
||||
import kotlinx.io.core.toByteArray
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
|
||||
@ -43,6 +44,7 @@ internal fun Face.toCommData(): ImMsgBody.CommonElem {
|
||||
|
||||
}
|
||||
|
||||
@SerialName(MarketFace.SERIAL_NAME)
|
||||
@Serializable
|
||||
internal data class MarketFaceImpl internal constructor(
|
||||
internal val delegate: ImMsgBody.MarketFace,
|
||||
|
@ -30,10 +30,13 @@ import net.mamoe.mirai.utils.generateImageIdFromResourceId
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
@Serializable(with = OnlineGroupImageImpl.Serializer::class)
|
||||
internal class OnlineGroupImageImpl(
|
||||
internal val delegate: ImMsgBody.CustomFace
|
||||
) : @Suppress("DEPRECATION")
|
||||
OnlineGroupImage() {
|
||||
) : OnlineGroupImage() {
|
||||
object Serializer : Image.FallbackSerializer("OnlineGroupImage")
|
||||
|
||||
|
||||
override val imageId: String = generateImageId(
|
||||
delegate.picMd5,
|
||||
delegate.filePath.substringAfterLast('.')
|
||||
@ -58,10 +61,13 @@ OnlineGroupImage() {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable(with = OnlineFriendImageImpl.Serializer::class)
|
||||
internal class OnlineFriendImageImpl(
|
||||
internal val delegate: ImMsgBody.NotOnlineImage
|
||||
) : @Suppress("DEPRECATION")
|
||||
OnlineFriendImage() {
|
||||
object Serializer : Image.FallbackSerializer("OnlineFriendImage")
|
||||
|
||||
override val imageId: String =
|
||||
generateImageIdFromResourceId(delegate.resId, getImageType(delegate.imgType)) ?: delegate.resId
|
||||
override val originUrl: String
|
||||
@ -212,7 +218,6 @@ internal interface SuspendDeferredOriginUrlAware : Image {
|
||||
suspend fun getUrl(bot: Bot): String
|
||||
}
|
||||
|
||||
@Suppress("EXPOSED_SUPER_INTERFACE")
|
||||
internal interface OnlineImage : Image, ConstOriginUrlAware {
|
||||
override val originUrl: String
|
||||
}
|
||||
@ -228,11 +233,12 @@ internal interface OfflineImage : Image
|
||||
/**
|
||||
* @param imageId 参考 [Image.imageId]
|
||||
*/
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
@Serializable
|
||||
@Serializable(with = OfflineGroupImage.Serializer::class)
|
||||
internal data class OfflineGroupImage(
|
||||
override val imageId: String
|
||||
) : GroupImage(), OfflineImage, DeferredOriginUrlAware {
|
||||
object Serializer : Image.FallbackSerializer("OfflineGroupImage")
|
||||
|
||||
override fun getUrl(bot: Bot): String {
|
||||
return "http://gchat.qpic.cn/gchatpic_new/${bot.id}/0-0-${
|
||||
imageId.substring(1..36)
|
||||
@ -265,10 +271,12 @@ internal val Image.friendImageId: String
|
||||
*
|
||||
* @param imageId 参考 [Image.imageId]
|
||||
*/
|
||||
@Serializable
|
||||
@Serializable(with = OfflineFriendImage.Serializer::class)
|
||||
internal data class OfflineFriendImage(
|
||||
override val imageId: String
|
||||
) : FriendImage(), OfflineImage, DeferredOriginUrlAware {
|
||||
object Serializer : Image.FallbackSerializer("OfflineFriendImage")
|
||||
|
||||
override fun getUrl(bot: Bot): String {
|
||||
return "http://c2cpicdw.qpic.cn/offpic_new/${bot.id}${this.friendImageId}/0?term=2"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -71,10 +71,13 @@ internal suspend inline fun Message.ensureSequenceIdAvailable() {
|
||||
}*/
|
||||
}
|
||||
|
||||
internal class MessageSourceFromFriendImpl(
|
||||
@Serializable(OnlineMessageSourceFromFriendImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceFromFriendImpl(
|
||||
override val bot: Bot,
|
||||
val msg: List<MsgComm.Msg>
|
||||
) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromFriend")
|
||||
|
||||
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
|
||||
@ -99,10 +102,13 @@ internal class MessageSourceFromFriendImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceFromStrangerImpl(
|
||||
@Serializable(OnlineMessageSourceFromStrangerImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceFromStrangerImpl(
|
||||
override val bot: Bot,
|
||||
val msg: List<MsgComm.Msg>
|
||||
) : OnlineMessageSource.Incoming.FromStranger(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromStranger")
|
||||
|
||||
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
|
||||
@ -163,10 +169,13 @@ private fun List<MsgComm.Msg>.toJceDataPrivate(ids: IntArray): ImMsgBody.SourceM
|
||||
)
|
||||
}
|
||||
|
||||
internal class MessageSourceFromTempImpl(
|
||||
@Serializable(OnlineMessageSourceFromTempImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceFromTempImpl(
|
||||
override val bot: Bot,
|
||||
private val msg: List<MsgComm.Msg>
|
||||
) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromTemp")
|
||||
|
||||
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
|
||||
override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
@ -190,12 +199,12 @@ internal class MessageSourceFromTempImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
@Serializable(MessageSourceFromGroupImpl.Serializer::class)
|
||||
internal data class MessageSourceFromGroupImpl(
|
||||
@Serializable(OnlineMessageSourceFromGroupImpl.Serializer::class)
|
||||
internal data class OnlineMessageSourceFromGroupImpl(
|
||||
override val bot: Bot,
|
||||
private val msg: List<MsgComm.Msg>
|
||||
) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("net.mamoe.mirai.internal.message.MessageSourceFromGroupImpl")
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromGroupImpl")
|
||||
|
||||
@Transient
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -17,15 +17,15 @@ import net.mamoe.mirai.Bot
|
||||
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.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.MessageSourceSerializerImpl
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.OfflineMessageSource
|
||||
import net.mamoe.mirai.utils.mapToIntArray
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
@Serializable
|
||||
@Serializable(OfflineMessageSourceImplData.Serializer::class)
|
||||
internal data class OfflineMessageSourceImplData(
|
||||
override val kind: MessageSourceKind,
|
||||
override val ids: IntArray,
|
||||
@ -36,19 +36,30 @@ internal data class OfflineMessageSourceImplData(
|
||||
override val originalMessage: MessageChain,
|
||||
override val internalIds: IntArray,
|
||||
) : OfflineMessageSource(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OfflineMessageSource")
|
||||
|
||||
override val sequenceIds: IntArray get() = ids
|
||||
|
||||
// for override.
|
||||
// if provided, no need to serialize from message
|
||||
@Transient
|
||||
var originElems: List<ImMsgBody.Elem>? = null
|
||||
|
||||
// may provided by OfflineMessageSourceImplBySourceMsg
|
||||
@Transient
|
||||
var jceData: ImMsgBody.SourceMsg? = null
|
||||
|
||||
@Transient
|
||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
return jceData ?: ImMsgBody.SourceMsg(
|
||||
origSeqs = sequenceIds,
|
||||
senderUin = fromId,
|
||||
toUin = 0,
|
||||
flag = 1,
|
||||
elems = originalMessage.toRichTextElems(
|
||||
elems = originElems ?: originalMessage.toRichTextElems(
|
||||
null, //forGroup = kind == MessageSourceKind.GROUP,
|
||||
withGeneralFlags = false
|
||||
),
|
||||
@ -56,7 +67,7 @@ internal data class OfflineMessageSourceImplData(
|
||||
time = time,
|
||||
pbReserve = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY,
|
||||
srcMsg = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY
|
||||
)
|
||||
).also { jceData = it }
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -90,92 +101,60 @@ internal data class OfflineMessageSourceImplData(
|
||||
}
|
||||
}
|
||||
|
||||
internal class OfflineMessageSourceImplByMsg(
|
||||
// from other sources' originalMessage
|
||||
internal fun OfflineMessageSourceImplData(
|
||||
bot: Bot?,
|
||||
val delegate: List<MsgComm.Msg>,
|
||||
override val botId: Long,
|
||||
) : OfflineMessageSource(), MessageSourceInternal {
|
||||
override val kind: MessageSourceKind =
|
||||
when {
|
||||
delegate.first().msgHead.groupInfo != null -> {
|
||||
MessageSourceKind.GROUP
|
||||
}
|
||||
delegate.first().msgHead.c2cTmpMsgHead != null -> {
|
||||
MessageSourceKind.TEMP
|
||||
}
|
||||
bot?.getStranger(delegate.first().msgHead.fromUin) != null -> {
|
||||
MessageSourceKind.STRANGER
|
||||
}
|
||||
else -> {
|
||||
MessageSourceKind.FRIEND
|
||||
}
|
||||
delegate: List<MsgComm.Msg>,
|
||||
botId: Long,
|
||||
): OfflineMessageSourceImplData {
|
||||
val kind = when {
|
||||
delegate.first().msgHead.groupInfo != null -> {
|
||||
MessageSourceKind.GROUP
|
||||
}
|
||||
override val ids: IntArray get() = sequenceIds
|
||||
override val internalIds: IntArray = delegate.mapToIntArray { it.msgHead.msgUid.toInt() }
|
||||
override val time: Int
|
||||
get() = delegate.first().msgHead.msgTime
|
||||
override val fromId: Long
|
||||
get() = delegate.first().msgHead.fromUin
|
||||
override val targetId: Long
|
||||
get() = delegate.first().msgHead.groupInfo?.groupCode ?: delegate.first().msgHead.toUin
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
delegate.toMessageChain(
|
||||
delegate.first().msgHead.c2cTmpMsgHead != null -> {
|
||||
MessageSourceKind.TEMP
|
||||
}
|
||||
bot?.getStranger(delegate.first().msgHead.fromUin) != null -> {
|
||||
MessageSourceKind.STRANGER
|
||||
}
|
||||
else -> {
|
||||
MessageSourceKind.FRIEND
|
||||
}
|
||||
}
|
||||
return OfflineMessageSourceImplData(
|
||||
kind = kind,
|
||||
time = delegate.first().msgHead.msgTime,
|
||||
fromId = delegate.first().msgHead.fromUin,
|
||||
targetId = delegate.first().msgHead.groupInfo?.groupCode ?: delegate.first().msgHead.toUin,
|
||||
originalMessage = delegate.toMessageChain(
|
||||
null,
|
||||
botId,
|
||||
groupIdOrZero = delegate.first().msgHead.groupInfo?.groupCode ?: 0,
|
||||
onlineSource = false,
|
||||
messageSourceKind = kind
|
||||
)
|
||||
}
|
||||
override val sequenceIds: IntArray = delegate.mapToIntArray { it.msgHead.msgSeq }
|
||||
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = delegate.mapToIntArray { it.msgHead.msgSeq },
|
||||
senderUin = delegate.first().msgHead.fromUin,
|
||||
toUin = 0,
|
||||
flag = 1,
|
||||
elems = delegate.flatMap { it.msgBody.richText.elems },
|
||||
type = 0,
|
||||
time = delegate.first().msgHead.msgTime,
|
||||
pbReserve = EMPTY_BYTE_ARRAY,
|
||||
srcMsg = EMPTY_BYTE_ARRAY
|
||||
)
|
||||
),
|
||||
ids = delegate.mapToIntArray { it.msgHead.msgSeq },
|
||||
internalIds = delegate.mapToIntArray { it.msgHead.msgUid.toInt() },
|
||||
botId = botId
|
||||
).apply {
|
||||
originElems = delegate.flatMap { it.msgBody.richText.elems }
|
||||
}
|
||||
}
|
||||
|
||||
internal class OfflineMessageSourceImplBySourceMsg(
|
||||
// from others' quotation
|
||||
val delegate: ImMsgBody.SourceMsg,
|
||||
override val botId: Long,
|
||||
groupIdOrZero: Long
|
||||
) : OfflineMessageSource(), MessageSourceInternal {
|
||||
override val kind: MessageSourceKind get() = if (delegate.srcMsg == null) MessageSourceKind.GROUP else MessageSourceKind.FRIEND
|
||||
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
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(botId, groupIdOrZero) }
|
||||
/*
|
||||
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 ids: IntArray get() = sequenceIds
|
||||
// delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt()
|
||||
// ?: 0
|
||||
|
||||
// override val sourceMessage: MessageChain get() = delegate.toMessageChain()
|
||||
override val fromId: Long get() = delegate.senderUin
|
||||
override val targetId: Long by lazy {
|
||||
when {
|
||||
internal fun OfflineMessageSourceImplData(
|
||||
delegate: ImMsgBody.SourceMsg,
|
||||
botId: Long,
|
||||
groupIdOrZero: Long,
|
||||
): OfflineMessageSourceImplData {
|
||||
return OfflineMessageSourceImplData(
|
||||
kind = if (delegate.srcMsg == null) MessageSourceKind.GROUP else MessageSourceKind.FRIEND,
|
||||
ids = delegate.origSeqs,
|
||||
internalIds = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer())
|
||||
.origUids?.mapToIntArray { it.toInt() } ?: intArrayOf(),
|
||||
time = delegate.time,
|
||||
originalMessage = delegate.toMessageChain(botId, groupIdOrZero),
|
||||
fromId = delegate.senderUin,
|
||||
targetId = when {
|
||||
groupIdOrZero != 0L -> groupIdOrZero
|
||||
delegate.toUin != 0L -> delegate.toUin
|
||||
delegate.srcMsg != null -> delegate.srcMsg.loadAs(MsgComm.Msg.serializer()).msgHead.toUin
|
||||
@ -187,10 +166,9 @@ internal class OfflineMessageSourceImplBySourceMsg(
|
||||
)
|
||||
}"
|
||||
)*/
|
||||
}
|
||||
}
|
||||
|
||||
override fun toJceData(): ImMsgBody.SourceMsg {
|
||||
return delegate
|
||||
},
|
||||
botId = botId
|
||||
).apply {
|
||||
jceData = delegate
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -14,6 +14,7 @@ package net.mamoe.mirai.internal.message
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.*
|
||||
@ -24,6 +25,7 @@ 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.MessageSourceSerializerImpl
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
@ -72,7 +74,8 @@ private fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
|
||||
)
|
||||
}
|
||||
|
||||
internal class MessageSourceToFriendImpl(
|
||||
@Serializable(OnlineMessageSourceToFriendImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceToFriendImpl(
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
@ -80,6 +83,8 @@ internal class MessageSourceToFriendImpl(
|
||||
override val sender: Bot,
|
||||
override val target: Friend
|
||||
) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToFriend")
|
||||
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val ids: IntArray
|
||||
@ -89,7 +94,8 @@ internal class MessageSourceToFriendImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToStrangerImpl(
|
||||
@Serializable(OnlineMessageSourceToStrangerImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceToStrangerImpl(
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
@ -97,6 +103,8 @@ internal class MessageSourceToStrangerImpl(
|
||||
override val sender: Bot,
|
||||
override val target: Stranger
|
||||
) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToStranger")
|
||||
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val ids: IntArray
|
||||
@ -106,7 +114,8 @@ internal class MessageSourceToStrangerImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToTempImpl(
|
||||
@Serializable(OnlineMessageSourceToTempImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceToTempImpl(
|
||||
override val sequenceIds: IntArray,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
@ -114,6 +123,8 @@ internal class MessageSourceToTempImpl(
|
||||
override val sender: Bot,
|
||||
override val target: Member
|
||||
) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToTemp")
|
||||
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
override val ids: IntArray
|
||||
@ -123,7 +134,8 @@ internal class MessageSourceToTempImpl(
|
||||
override fun toJceData(): ImMsgBody.SourceMsg = jceData
|
||||
}
|
||||
|
||||
internal class MessageSourceToGroupImpl(
|
||||
@Serializable(OnlineMessageSourceToGroupImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceToGroupImpl(
|
||||
coroutineScope: CoroutineScope,
|
||||
override val internalIds: IntArray,
|
||||
override val time: Int,
|
||||
@ -131,6 +143,8 @@ internal class MessageSourceToGroupImpl(
|
||||
override val sender: Bot,
|
||||
override val target: Group
|
||||
) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToGroup")
|
||||
|
||||
override val ids: IntArray
|
||||
get() = sequenceIds
|
||||
override val bot: Bot
|
||||
@ -141,7 +155,7 @@ internal class MessageSourceToGroupImpl(
|
||||
coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>(
|
||||
timeoutMillis = 3000
|
||||
) {
|
||||
if (it.messageRandom in this@MessageSourceToGroupImpl.internalIds) {
|
||||
if (it.messageRandom in this@OnlineMessageSourceToGroupImpl.internalIds) {
|
||||
it.sequenceId
|
||||
} else null
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -71,7 +71,7 @@ internal fun Collection<ForwardMessage.INode>.calculateValidationDataForGroup(
|
||||
),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = chain.message.asMessageChain()
|
||||
elems = chain.messageChain.asMessageChain()
|
||||
.toRichTextElems(targetGroup, withGeneralFlags = false).toMutableList()
|
||||
)
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -17,10 +17,6 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUByte
|
||||
import kotlinx.io.core.readUShort
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Group
|
||||
@ -34,7 +30,7 @@ import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
import net.mamoe.mirai.internal.message.MessageSourceFromFriendImpl
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceFromFriendImpl
|
||||
import net.mamoe.mirai.internal.message.toMessageChain
|
||||
import net.mamoe.mirai.internal.network.MultiPacket
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
@ -437,7 +433,7 @@ internal suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
||||
?: return null// don't compare with dstAppId. diff.
|
||||
|
||||
val chain = buildMessageChain {
|
||||
+MessageSourceFromFriendImpl(bot, listOf(this@transform))
|
||||
+OnlineMessageSourceFromFriendImpl(bot, listOf(this@transform))
|
||||
for (msgItem in textMsg.msgItems) {
|
||||
when (msgItem.type) {
|
||||
1 -> +PlainText(msgItem.text)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -143,7 +143,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
client: QQAndroidClient,
|
||||
target: Stranger,
|
||||
message: MessageChain,
|
||||
source: MessageSourceToStrangerImpl
|
||||
source: OnlineMessageSourceToStrangerImpl
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
|
||||
|
||||
@ -173,7 +173,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
client: QQAndroidClient,
|
||||
targetFriend: Friend,
|
||||
message: MessageChain,
|
||||
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit
|
||||
crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit
|
||||
): List<OutgoingPacket> {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
@ -209,7 +209,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
},
|
||||
postInit = {
|
||||
sourceCallback(
|
||||
MessageSourceToFriendImpl(
|
||||
OnlineMessageSourceToFriendImpl(
|
||||
internalIds = randIds.get(),
|
||||
sender = client.bot,
|
||||
target = targetFriend,
|
||||
@ -262,7 +262,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
client: QQAndroidClient,
|
||||
targetMember: Member,
|
||||
message: MessageChain,
|
||||
source: MessageSourceToTempImpl
|
||||
source: OnlineMessageSourceToTempImpl
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
|
||||
@ -292,7 +292,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
targetGroup: Group,
|
||||
message: MessageChain,
|
||||
isForward: Boolean,
|
||||
source: MessageSourceToGroupImpl
|
||||
source: OnlineMessageSourceToGroupImpl
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
|
||||
|
||||
@ -354,12 +354,12 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
|
||||
client: QQAndroidClient,
|
||||
member: Member,
|
||||
message: MessageChain,
|
||||
crossinline sourceCallback: (MessageSourceToTempImpl) -> Unit
|
||||
crossinline sourceCallback: (OnlineMessageSourceToTempImpl) -> Unit
|
||||
): OutgoingPacket {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val source = MessageSourceToTempImpl(
|
||||
val source = OnlineMessageSourceToTempImpl(
|
||||
internalIds = intArrayOf(Random.nextInt().absoluteValue),
|
||||
sender = client.bot,
|
||||
target = member,
|
||||
@ -380,12 +380,12 @@ internal inline fun MessageSvcPbSendMsg.createToStranger(
|
||||
client: QQAndroidClient,
|
||||
stranger: Stranger,
|
||||
message: MessageChain,
|
||||
crossinline sourceCallback: (MessageSourceToStrangerImpl) -> Unit
|
||||
crossinline sourceCallback: (OnlineMessageSourceToStrangerImpl) -> Unit
|
||||
): OutgoingPacket {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val source = MessageSourceToStrangerImpl(
|
||||
val source = OnlineMessageSourceToStrangerImpl(
|
||||
internalIds = intArrayOf(Random.nextInt().absoluteValue),
|
||||
sender = client.bot,
|
||||
target = stranger,
|
||||
@ -406,7 +406,7 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
|
||||
client: QQAndroidClient,
|
||||
qq: Friend,
|
||||
message: MessageChain,
|
||||
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit
|
||||
crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit
|
||||
): List<OutgoingPacket> {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
@ -425,13 +425,13 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
|
||||
group: Group,
|
||||
message: MessageChain,
|
||||
isForward: Boolean,
|
||||
crossinline sourceCallback: (MessageSourceToGroupImpl) -> Unit
|
||||
crossinline sourceCallback: (OnlineMessageSourceToGroupImpl) -> Unit
|
||||
): OutgoingPacket {
|
||||
contract {
|
||||
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
val messageRandom = Random.nextInt().absoluteValue
|
||||
val source = MessageSourceToGroupImpl(
|
||||
val source = OnlineMessageSourceToGroupImpl(
|
||||
group,
|
||||
internalIds = intArrayOf(messageRandom),
|
||||
sender = client.bot,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -15,6 +15,7 @@ import kotlinx.serialization.serializer
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.internal.message.MarketFaceImpl
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.message.MessageSerializer
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
@ -22,11 +23,13 @@ import kotlin.test.assertEquals
|
||||
|
||||
internal class MessageSerializationTest {
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
private val module get() = Message.Serializer.serializersModule
|
||||
private val module
|
||||
get() = MessageSerializer.serializersModule
|
||||
private val format
|
||||
get() = Json {
|
||||
serializersModule = module
|
||||
useArrayPolymorphism = false // ?
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> T.serialize(serializer: KSerializer<T> = module.serializer()): String {
|
||||
@ -38,7 +41,14 @@ internal class MessageSerializationTest {
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> testSerialization(t: T, serializer: KSerializer<T> = module.serializer()) {
|
||||
val deserialized = t.serialize(serializer).deserialize(serializer)
|
||||
val deserialized = kotlin.runCatching {
|
||||
println("Testing ${t::class.simpleName} with serializer $serializer")
|
||||
val serialized = t.serialize(serializer)
|
||||
println("Result: ${serializer.descriptor.serialName} $serialized")
|
||||
serialized.deserialize(serializer)
|
||||
}.getOrElse {
|
||||
throw AssertionError("Failed to serialize $t", it)
|
||||
}
|
||||
assertEquals(
|
||||
t,
|
||||
deserialized,
|
||||
@ -78,7 +88,6 @@ internal class MessageSerializationTest {
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
private val testConstrainSingleMessageInstances: Array<out ConstrainSingle> = arrayOf(
|
||||
LongMessage("content", "resId"),
|
||||
Mirai.constructMessageSource(
|
||||
1L,
|
||||
MessageSourceKind.FRIEND,
|
||||
@ -100,7 +109,12 @@ internal class MessageSerializationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test serialize each message contents`() {
|
||||
fun `test polymorphic serialization`() {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test contextual serialization`() {
|
||||
for (message in testMessageContentInstances) {
|
||||
testSerialization(message, module.serializer(message.javaClass))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user