Message serialization, fix #767

This commit is contained in:
Him188 2021-01-06 13:13:39 +08:00
parent bfd21cbb92
commit ebc7d655e3
30 changed files with 452 additions and 394 deletions

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.*
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.PolymorphicModuleBuilder import kotlinx.serialization.modules.*
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.plus
import kotlinx.serialization.modules.polymorphic
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.MiraiExperimentalApi
@ -29,21 +26,44 @@ import kotlin.reflect.KClass
public interface MessageSerializer { public interface MessageSerializer {
public val serializersModule: SerializersModule 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 registerSerializers(serializersModule: SerializersModule)
public fun clearRegisteredSerializers() 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 @MiraiInternalApi
public open class MessageSourceSerializerImpl(serialName: String) : KSerializer<MessageSource> { public open class MessageSourceSerializerImpl(serialName: String) :
public companion object : MessageSourceSerializerImpl("net.mamoe.mirai.message.data.MessageSource") 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 @Serializable
internal class SerialData( internal class SerialData(
val kind: MessageSourceKind, val kind: MessageSourceKind,
val bot: Long, val botId: Long,
val ids: IntArray, val ids: IntArray,
val internalIds: IntArray, val internalIds: IntArray,
val time: Int, val time: Int,
@ -51,49 +71,6 @@ public open class MessageSourceSerializerImpl(serialName: String) : KSerializer<
val targetId: Long, val targetId: Long,
val originalMessage: MessageChain, 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(LightApp::class, LightApp.serializer())
contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer()) contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer()) contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer())
contextual(LongMessage::class, LongMessage.serializer())
contextual(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
contextual(PttMessage::class, PttMessage.serializer()) contextual(PttMessage::class, PttMessage.serializer())
contextual(Voice::class, Voice.serializer()) contextual(Voice::class, Voice.serializer())
@ -130,12 +105,7 @@ private val builtInSerializersModule by lazy {
contextual(VipFace::class, VipFace.serializer()) contextual(VipFace::class, VipFace.serializer())
contextual(FlashImage::class, FlashImage.serializer()) contextual(FlashImage::class, FlashImage.serializer())
fun PolymorphicModuleBuilder<SingleMessage>.singleMessageSubclasses() { contextual(MessageSource::class, MessageSource.serializer())
// subclass(MessageSource::class, MessageSource.serializer())
}
// contextual(MessageSource::class, MessageSource.serializer())
polymorphicDefault(MessageSource::class) { MessageSource.serializer() }
fun PolymorphicModuleBuilder<MessageMetadata>.messageMetadataSubclasses() { fun PolymorphicModuleBuilder<MessageMetadata>.messageMetadataSubclasses() {
subclass(MessageSource::class, MessageSource.serializer()) subclass(MessageSource::class, MessageSource.serializer())
@ -154,8 +124,6 @@ private val builtInSerializersModule by lazy {
subclass(LightApp::class, LightApp.serializer()) subclass(LightApp::class, LightApp.serializer())
subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer()) subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
subclass(LongMessage::class, LongMessage.serializer())
subclass(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
// subclass(PttMessage::class, PttMessage.serializer()) // subclass(PttMessage::class, PttMessage.serializer())
subclass(Voice::class, Voice.serializer()) subclass(Voice::class, Voice.serializer())
@ -166,21 +134,11 @@ private val builtInSerializersModule by lazy {
subclass(FlashImage::class, FlashImage.serializer()) subclass(FlashImage::class, FlashImage.serializer())
} }
@Suppress("DEPRECATION_ERROR") contextual(SingleMessage::class, SingleMessage.Serializer)
contextual(Message::class, Message.Serializer)
// contextual(SingleMessage::class, SingleMessage.Serializer)
contextual(MessageChain::class, MessageChain.Serializer) contextual(MessageChain::class, MessageChain.Serializer)
contextual(MessageChainImpl::class, MessageChainImpl.serializer()) contextual(MessageChainImpl::class, MessageChainImpl.serializer())
polymorphic(MessageChain::class) { // polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() }
subclass(MessageChainImpl::class, MessageChainImpl.serializer())
}
polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() }
polymorphic(AbstractServiceMessage::class) {
subclass(LongMessage::class, LongMessage.serializer())
subclass(ForwardMessageInternal::class, ForwardMessageInternal.serializer())
}
// polymorphic(SingleMessage::class) { // polymorphic(SingleMessage::class) {
// subclass(MessageSource::class, MessageSource.serializer()) // subclass(MessageSource::class, MessageSource.serializer())
@ -189,16 +147,12 @@ private val builtInSerializersModule by lazy {
// } // }
// } // }
polymorphicDefault(Image::class) { Image.Serializer }
// polymorphic(Message::class) { // polymorphic(Message::class) {
// subclass(PlainText::class, PlainText.serializer()) // subclass(PlainText::class, PlainText.serializer())
// } // }
polymorphic(Message::class) { polymorphic(SingleMessage::class) {
messageContentSubclasses() messageContentSubclasses()
messageMetadataSubclasses() messageMetadataSubclasses()
singleMessageSubclasses()
subclass(MessageChainImpl::class, MessageChainImpl.serializer())
} }
//contextual(SingleMessage::class, SingleMessage.Serializer) //contextual(SingleMessage::class, SingleMessage.Serializer)
@ -216,7 +170,7 @@ private val builtInSerializersModule by lazy {
// contextual(MessageMetadata::class, MessageMetadata.Serializer) // contextual(MessageMetadata::class, MessageMetadata.Serializer)
// polymorphic(MessageMetadata::class, MessageMetadata.Serializer) { // polymorphic(MessageMetadata::class, MessageMetadata.Serializer) {
// messageMetadataSubclasses() // messageMetadataSubclasses()
// } //
} }
} }
@ -226,18 +180,18 @@ internal object MessageSerializerImpl : MessageSerializer {
override val serializersModule: SerializersModule get() = serializersModuleField ?: builtInSerializersModule override val serializersModule: SerializersModule get() = serializersModuleField ?: builtInSerializersModule
@Synchronized @Synchronized
override fun <M : Message> registerSerializer(clazz: KClass<M>, serializer: KSerializer<M>) { override fun <M : SingleMessage> registerSerializer(baseClass: KClass<M>, serializer: KSerializer<M>) {
serializersModuleField = serializersModule.plus(SerializersModule { serializersModuleField = serializersModule.overwriteWith(SerializersModule {
contextual(clazz, serializer) contextual(baseClass, serializer)
polymorphic(Message::class) { polymorphic(SingleMessage::class) {
subclass(clazz, serializer) subclass(baseClass, serializer)
} }
}) })
} }
@Synchronized @Synchronized
override fun registerSerializers(serializersModule: SerializersModule) { override fun registerSerializers(serializersModule: SerializersModule) {
serializersModuleField = serializersModule serializersModuleField = serializersModule.overwriteWith(serializersModule)
} }
@Synchronized @Synchronized
@ -245,3 +199,32 @@ internal object MessageSerializerImpl : MessageSerializer {
serializersModuleField = builtInSerializersModule 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) })
}
}

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.Member
@ -30,6 +31,7 @@ import net.mamoe.mirai.message.code.CodableMessage
* *
* @see AtAll 全体成员 * @see AtAll 全体成员
*/ */
@SerialName(At.SERIAL_NAME)
@Serializable @Serializable
public data class At( public data class At(
public val target: Long, public val target: Long,
@ -51,7 +53,9 @@ public data class At(
builder.append("[mirai:at:").append(target).append(']') 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 { public override fun followedBy(tail: Message): MessageChain {

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.code.CodableMessage
@ -28,10 +29,12 @@ private const val displayA = "@全体成员"
* *
* @see At at 单个群成员 * @see At at 单个群成员
*/ */
@SerialName(AtAll.SERIAL_NAME)
@Serializable @Serializable
public object AtAll : public object AtAll :
MessageContent, CodableMessage { MessageContent, CodableMessage {
public const val display: String = displayA public const val display: String = displayA
public const val SERIAL_NAME: String = "AtAll"
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
public override fun toString(): String = "[mirai:atall]" public override fun toString(): String = "[mirai:atall]"

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.code.CodableMessage
@ -22,10 +23,11 @@ import net.mamoe.mirai.message.code.CodableMessage
* 格式: &#91;mirai:face:*[id]*&#93; * 格式: &#91;mirai:face:*[id]*&#93;
*/ */
@Serializable @Serializable
@SerialName(Face.SERIAL_NAME)
public data class Face(public val id: Int) : // used in delegation public data class Face(public val id: Int) : // used in delegation
MessageContent, CodableMessage { 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 val name: String get() = contentToString().let { it.substring(1, it.length - 1) }
public override fun contentToString(): String = names.getOrElse(id) { "[表情]" } 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 //Auto generated
@Suppress("NonAsciiCharacters", "unused", "SpellCheckingInspection", "all") @Suppress("NonAsciiCharacters", "unused", "SpellCheckingInspection", "all")
public companion object { public companion object {
public const val SERIAL_NAME: String = "Face"
public const val JING_YA: Int = 0 public const val JING_YA: Int = 0
public const val 惊讶: Int = JING_YA public const val 惊讶: Int = JING_YA
public const val PIE_ZUI: Int = 1 public const val PIE_ZUI: Int = 1

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.http.*
import io.ktor.util.* import io.ktor.util.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
@ -96,6 +97,7 @@ public data class RawForwardMessage(
* *
* @see buildForwardMessage * @see buildForwardMessage
*/ */
@SerialName(ForwardMessage.SERIAL_NAME)
@Serializable @Serializable
public data class ForwardMessage( public data class ForwardMessage(
val preview: List<String>, val preview: List<String>,
@ -136,7 +138,7 @@ public data class ForwardMessage(
* Java 用户: 使用 [sequenceOf] (`SequenceKt.sequenceOf`) [asSequence] (`SequenceKt.asSequence`) * Java 用户: 使用 [sequenceOf] (`SequenceKt.sequenceOf`) [asSequence] (`SequenceKt.asSequence`)
*/ */
public fun generatePreview(forward: RawForwardMessage): List<String> = 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 senderId: Long,
override val time: Int, override val time: Int,
override val senderName: String, override val senderName: String,
override val message: Message override val messageChain: MessageChain
) : INode ) : INode {
public constructor(
senderId: Long,
time: Int,
senderName: String,
message: Message
) : this(senderId, time, senderName, message.asMessageChain())
}
@MiraiExperimentalApi @MiraiExperimentalApi
public interface INode { public interface INode {
@ -175,11 +184,13 @@ public data class ForwardMessage(
/** /**
* 消息内容 * 消息内容
*/ */
public val message: Message public val messageChain: MessageChain
} }
public companion object Key : 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 @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 @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 @ForwardMessageDsl
public infix fun says(message: Message): ForwardMessageBuilder = this@ForwardMessageBuilder.apply { public infix fun says(message: Message): ForwardMessageBuilder = this@ForwardMessageBuilder.apply {
checkBuilt() checkBuilt()
this@BuilderNode.message = message this@BuilderNode.messageChain = message.asMessageChain()
add(this@BuilderNode) add(this@BuilderNode)
} }
@ -454,7 +467,7 @@ public class ForwardMessageBuilder private constructor(
checkBuilt() checkBuilt()
add(BuilderNode().apply { add(BuilderNode().apply {
senderId = this@says senderId = this@says
this.message = message this.messageChain = message.asMessageChain()
}) })
} }
@ -551,7 +564,7 @@ public class ForwardMessageBuilder private constructor(
it.senderId, it.senderId,
it.time, it.time,
it.senderName, it.senderName,
it.message it.messageChain
) )
}).render(this.displayStrategy) }).render(this.displayStrategy)
@ -565,5 +578,5 @@ public class ForwardMessageBuilder private constructor(
internal inline fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF) internal inline fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF)
private fun ForwardMessage.INode.toNode(): ForwardMessage.Node { private fun ForwardMessage.INode.toNode(): ForwardMessage.Node {
return ForwardMessage.Node(senderId, time, senderName, message) return ForwardMessage.Node(senderId, time, senderName, messageChain)
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.code.CodableMessage
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
@ -46,6 +46,7 @@ public interface HummerMessage : MessageContent, ConstrainSingle {
* *
* @see PokeMessage.Companion 使用伴生对象中的常量 * @see PokeMessage.Companion 使用伴生对象中的常量
*/ */
@SerialName(PokeMessage.SERIAL_NAME)
@Serializable @Serializable
public data class PokeMessage @MiraiInternalApi constructor( public data class PokeMessage @MiraiInternalApi constructor(
/** /**
@ -63,6 +64,8 @@ public data class PokeMessage @MiraiInternalApi constructor(
public companion object Key : public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, PokeMessage>(HummerMessage, { it.castOrNull() }) { AbstractPolymorphicMessageKey<HummerMessage, PokeMessage>(HummerMessage, { it.castOrNull() }) {
public const val SERIAL_NAME: String = "PokeMessage"
/** 戳一戳 */ /** 戳一戳 */
@JvmField @JvmField
public val ChuoYiChuo: PokeMessage = PokeMessage("戳一戳", 1, -1) public val ChuoYiChuo: PokeMessage = PokeMessage("戳一戳", 1, -1)
@ -195,7 +198,9 @@ public interface MarketFace : HummerMessage {
get() = Key get() = Key
public companion object 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 override fun contentToString(): String = name
} }
@ -215,6 +220,7 @@ public interface MarketFace : HummerMessage {
* *
* @see VipFace.Key 使用伴生对象中的常量 * @see VipFace.Key 使用伴生对象中的常量
*/ */
@SerialName(VipFace.SERIAL_NAME)
@Serializable @Serializable
public data class VipFace @MiraiInternalApi constructor( public data class VipFace @MiraiInternalApi constructor(
/** /**
@ -239,6 +245,8 @@ public data class VipFace @MiraiInternalApi constructor(
public companion object Key : public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, VipFace>(HummerMessage, { it.safeCast() }) { AbstractPolymorphicMessageKey<HummerMessage, VipFace>(HummerMessage, { it.safeCast() }) {
public const val SERIAL_NAME: String = "VipFace"
@JvmField @JvmField
public val LiuLian: Kind = 9 to "榴莲" public val LiuLian: Kind = 9 to "榴莲"
@ -310,12 +318,14 @@ public data class VipFace @MiraiInternalApi constructor(
* *
* @see Image 查看图片相关信息 * @see Image 查看图片相关信息
*/ */
@SerialName(FlashImage.SERIAL_NAME)
@Serializable @Serializable
public data class FlashImage( public data class FlashImage(
/** /**
* 闪照的内容图片, 即一个普通图片. * 闪照的内容图片, 即一个普通图片.
*/ */
@Contextual @SerialName("imageId")
@Serializable(Image.AsStringSerializer::class)
public val image: Image public val image: Image
) : MessageContent, HummerMessage, CodableMessage, ConstrainSingle { ) : MessageContent, HummerMessage, CodableMessage, ConstrainSingle {
override val key: MessageKey<FlashImage> override val key: MessageKey<FlashImage>
@ -323,6 +333,7 @@ public data class FlashImage(
public companion object Key : public companion object Key :
AbstractPolymorphicMessageKey<HummerMessage, FlashImage>(HummerMessage, { it.safeCast() }) { AbstractPolymorphicMessageKey<HummerMessage, FlashImage>(HummerMessage, { it.safeCast() }) {
public const val SERIAL_NAME: String = "FlashImage"
/** /**
* 将普通图片转换为闪照. * 将普通图片转换为闪照.

View File

@ -20,14 +20,10 @@
package net.mamoe.mirai.message.data package net.mamoe.mirai.message.data
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor 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.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.IMirai 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_1
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2 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.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
import net.mamoe.mirai.utils.ExternalResource.Companion.sendAsImageTo import net.mamoe.mirai.utils.ExternalResource.Companion.sendAsImageTo
import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage
@ -90,26 +88,32 @@ public interface Image : Message, MessageContent, CodableMessage {
*/ */
public val imageId: String public val imageId: String
public object Serializer : KSerializer<Image> { @kotlinx.serialization.Serializer(forClass = Image::class)
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("net.mamoe.mirai.message.data.Image") { public object AsStringSerializer : KSerializer<Image> by String.serializer().mapPrimitive(
element("imageId", String.serializer().descriptor) SERIAL_NAME,
} serialize = { imageId },
deserialize = { Image(it) },
)
override fun deserialize(decoder: Decoder): Image = decoder.decodeStructure(descriptor) { @kotlinx.serialization.Serializer(forClass = Image::class)
val imageId = if (decodeSequentially()) { public object Serializer : KSerializer<Image> by FallbackSerializer("Image")
decodeStringElement(descriptor, 0)
} else {
decodeStringElement(descriptor, decodeElementIndex(descriptor))
}
Image(imageId)
}
override fun serialize(encoder: Encoder, value: Image): Unit = encoder.encodeStructure(descriptor) { @MiraiInternalApi
encodeStringElement(descriptor, 0, value.imageId) 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 companion object Key : AbstractMessageKey<Image>({ it.safeCast() }) {
public const val SERIAL_NAME: String = "Image"
/** /**
* 通过 [Image.imageId] 构造一个 [Image] 以便发送. * 通过 [Image.imageId] 构造一个 [Image] 以便发送.
* 这个图片必须是服务器已经存在的图片. * 这个图片必须是服务器已经存在的图片.
@ -148,8 +152,9 @@ public interface Image : Message, MessageContent, CodableMessage {
@Suppress("RegExpRedundantEscape") // This is required on Android @Suppress("RegExpRedundantEscape") // This is required on Android
@JvmStatic @JvmStatic
@get:JvmName("getImageIdRegex") @get:JvmName("getImageIdRegex")
public val IMAGE_ID_REGEX: Regex = // inline because compilation error
Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""") 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 内部使用. * 图片资源 ID 正则表达式 1. mirai 内部使用.
@ -160,7 +165,9 @@ public interface Image : Message, MessageContent, CodableMessage {
@JvmStatic @JvmStatic
@MiraiInternalApi @MiraiInternalApi
@get:JvmName("getImageResourceIdRegex1") @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 内部使用. * 图片资源 ID 正则表达式 2. mirai 内部使用.
@ -171,7 +178,9 @@ public interface Image : Message, MessageContent, CodableMessage {
@JvmStatic @JvmStatic
@MiraiInternalApi @MiraiInternalApi
@get:JvmName("getImageResourceIdRegex2") @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}""")
} }
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.Flow
import kotlinx.coroutines.flow.fold import kotlinx.coroutines.flow.fold
import kotlinx.serialization.* import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.event.events.MessageEvent import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.message.MessageReceipt 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.MiraiExperimentalApi
import net.mamoe.mirai.utils.safeCast import net.mamoe.mirai.utils.safeCast
import kotlin.contracts.contract import kotlin.contracts.contract
@ -73,8 +70,6 @@ import kotlin.internal.LowPriorityInOverloadResolution
* *
* @see Contact.sendMessage 发送消息 * @see Contact.sendMessage 发送消息
*/ */
@Suppress("DEPRECATION_ERROR")
@Serializable(Message.Serializer::class)
public interface Message { // must be interface. Don't consider any changes. 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 = public operator fun plus(another: Sequence<Message>): MessageChain =
another.fold(this, Message::plus).asMessageChain() another.fold(this, Message::plus).asMessageChain()
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN) public companion object
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)
}
} }
@ -320,10 +272,11 @@ public inline operator fun Message.times(count: Int): MessageChain = this.repeat
/** /**
* 单个消息元素. 与之相对的是 [MessageChain], 是多个 [SingleMessage] 的集合. * 单个消息元素. 与之相对的是 [MessageChain], 是多个 [SingleMessage] 的集合.
*/ */
// @Serializable(SingleMessage.Serializer::class) @Serializable(SingleMessage.Serializer::class)
public interface SingleMessage : Message { public interface SingleMessage : Message {
// @kotlinx.serialization.Serializer(forClass = SingleMessage::class) @kotlinx.serialization.Serializer(forClass = SingleMessage::class)
// public object Serializer : KSerializer<SingleMessage> by PolymorphicSerializer(SingleMessage::class) public object Serializer :
KSerializer<SingleMessage> by PolymorphicSerializer(SingleMessage::class)
} }
/** /**
@ -339,14 +292,11 @@ public interface SingleMessage : Message {
* *
* @see ConstrainSingle 约束一个 [MessageChain] 中只存在这一种类型的元素 * @see ConstrainSingle 约束一个 [MessageChain] 中只存在这一种类型的元素
*/ */
@Serializable(MessageMetadata.Serializer::class)
public interface MessageMetadata : SingleMessage { public interface MessageMetadata : SingleMessage {
/** /**
* 返回空字符串 * 返回空字符串
*/ */
override fun contentToString(): String = "" override fun contentToString(): String = ""
public object Serializer : KSerializer<MessageMetadata> by PolymorphicSerializer(MessageMetadata::class)
} }
/** /**
@ -381,11 +331,8 @@ public interface ConstrainSingle : SingleMessage {
* @see ForwardMessage 合并转发 * @see ForwardMessage 合并转发
* @see Voice 语音 * @see Voice 语音
*/ */
@Serializable(MessageContent.Serializer::class)
public interface MessageContent : SingleMessage { public interface MessageContent : SingleMessage {
public companion object Key : AbstractMessageKey<MessageContent>({ it.safeCast() }) public companion object Key : AbstractMessageKey<MessageContent>({ it.safeCast() })
public object Serializer : KSerializer<MessageContent> by PolymorphicSerializer(MessageContent::class)
} }
/** /**

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.encoding.Encoder
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import net.mamoe.mirai.event.events.MessageEvent 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.code.CodableMessage
import net.mamoe.mirai.message.data.MessageSource.Key.quote import net.mamoe.mirai.message.data.MessageSource.Key.quote
import net.mamoe.mirai.message.data.MessageSource.Key.recall 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 = public operator fun <M : SingleMessage> contains(key: MessageKey<M>): Boolean =
asSequence().any { key.safeCast.invoke(it) != null } asSequence().any { key.safeCast.invoke(it) != null }
@kotlinx.serialization.Serializer(MessageChain::class)
public object Serializer : KSerializer<MessageChain> { public object Serializer : KSerializer<MessageChain> {
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
private val delegate = ListSerializer<Message>(Message.Serializer) private val delegate = ListSerializer(PolymorphicSerializer(SingleMessage::class))
override val descriptor: SerialDescriptor = delegate.descriptor override val descriptor: SerialDescriptor = delegate.descriptor
override fun deserialize(decoder: Decoder): MessageChain = delegate.deserialize(decoder).asMessageChain() override fun deserialize(decoder: Decoder): MessageChain = delegate.deserialize(decoder).asMessageChain()
override fun serialize(encoder: Encoder, value: MessageChain): Unit = delegate.serialize(encoder, value) 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] * JSON 字符串解析 [MessageChain]
* @see serializeToJsonString * @see serializeToJsonString
*/ */
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
@JvmOverloads @JvmOverloads
@JvmStatic @JvmStatic
public fun deserializeFromJsonString( public fun deserializeFromJsonString(
string: String, string: String,
json: Json = Json { serializersModule = Message.Serializer.serializersModule } json: Json = Json { serializersModule = MessageSerializerImpl.serializersModule }
): MessageChain { ): MessageChain {
return json.decodeFromString(Serializer, string) return json.decodeFromString(Serializer, string)
} }
@ -124,12 +125,11 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
* [MessageChain] 序列化为 JSON 字符串. * [MessageChain] 序列化为 JSON 字符串.
* @see deserializeFromJsonString * @see deserializeFromJsonString
*/ */
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
@JvmOverloads @JvmOverloads
@JvmStatic @JvmStatic
public fun MessageChain.serializeToJsonString( public fun MessageChain.serializeToJsonString(
json: Json = Json { serializersModule = Message.Serializer.serializersModule } json: Json = Json { serializersModule = MessageSerializerImpl.serializersModule }
): String = json.encodeToString(Message.Serializer, this) ): String = json.encodeToString(MessageChain.Serializer, this)
/** /**
* [MessageChain] 序列化为指定格式的字符串. * [MessageChain] 序列化为指定格式的字符串.
@ -137,7 +137,6 @@ public interface MessageChain : Message, List<SingleMessage>, RandomAccess, Coda
* @see serializeToJsonString * @see serializeToJsonString
* @see StringFormat.encodeToString * @see StringFormat.encodeToString
*/ */
@Deprecated("消息序列化仍未稳定,请在 2.0-RC 再使用", level = DeprecationLevel.HIDDEN)
@ExperimentalSerializationApi @ExperimentalSerializationApi
@JvmStatic @JvmStatic
public fun MessageChain.serializeToString(format: StringFormat): String = public fun MessageChain.serializeToString(format: StringFormat): String =

View File

@ -36,7 +36,6 @@ public interface MessageKey<out M : SingleMessage> {
* @see AbstractPolymorphicMessageKey * @see AbstractPolymorphicMessageKey
*/ */
public abstract class AbstractMessageKey<out M : SingleMessage>( public abstract class AbstractMessageKey<out M : SingleMessage>(
@JvmField
override val safeCast: (SingleMessage) -> M?, override val safeCast: (SingleMessage) -> M?,
) : MessageKey<M> ) : MessageKey<M>

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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] * @see buildMessageSource 构造一个 [OfflineMessageSource]
*/ */
@Serializable(MessageSourceSerializerImpl.Companion::class) @Serializable(MessageSource.Serializer::class)
public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle { public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
public final override val key: MessageKey<MessageSource> public final override val key: MessageKey<MessageSource>
get() = Key get() = Key
@ -150,7 +150,11 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle {
public final override fun toString(): String = public final override fun toString(): String =
"[mirai:source:${ids.contentToString()},${internalIds.contentToString()}]" "[mirai:source:${ids.contentToString()},${internalIds.contentToString()}]"
public object Serializer : MessageSourceSerializerImpl("MessageSource")
public companion object Key : AbstractMessageKey<MessageSource>({ it.safeCast() }) { public companion object Key : AbstractMessageKey<MessageSource>({ it.safeCast() }) {
public const val SERIAL_NAME: String = "MessageSource"
/** /**
* 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息. * 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
* *
@ -361,7 +365,8 @@ public sealed class OnlineMessageSource : MessageSource() {
} }
public abstract class ToStranger : Outgoing() { 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 abstract override val target: Stranger
public final override val subject: Stranger get() = target public final override val subject: Stranger get() = target

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.code.CodableMessage
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode 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] * 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [Message.plus]
*/ */
@Serializable @Serializable
@SerialName(PlainText.SERIAL_NAME)
public data class PlainText( public data class PlainText(
public val content: String public val content: String
) : MessageContent, CodableMessage { ) : MessageContent, CodableMessage {
@ -36,7 +38,9 @@ public data class PlainText(
builder.appendAsMiraiCode(content) builder.appendAsMiraiCode(content)
} }
public companion object public companion object {
public const val SERIAL_NAME: String = "PlainText"
}
} }
/** /**

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.data.MessageSource.Key.recall import net.mamoe.mirai.message.data.MessageSource.Key.recall
@ -40,8 +41,13 @@ import net.mamoe.mirai.utils.safeCast
* @see MessageSource 获取有关消息源的更多信息 * @see MessageSource 获取有关消息源的更多信息
*/ */
@Serializable @Serializable
public data class QuoteReply(public val source: MessageSource) : Message, MessageMetadata, ConstrainSingle { @SerialName(QuoteReply.SERIAL_NAME)
public companion object Key : AbstractMessageKey<QuoteReply>({ it.safeCast() }) 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 public override val key: MessageKey<QuoteReply> get() = Key

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.message.code.CodableMessage import net.mamoe.mirai.message.code.CodableMessage
import net.mamoe.mirai.message.code.internal.appendAsMiraiCode import net.mamoe.mirai.message.code.internal.appendAsMiraiCode
@ -95,8 +96,11 @@ public interface RichMessage : MessageContent, ConstrainSingle {
* @see ServiceMessage 服务消息 * @see ServiceMessage 服务消息
*/ */
@Serializable @Serializable
@SerialName(LightApp.SERIAL_NAME)
public data class LightApp(override val content: String) : RichMessage, CodableMessage { 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]" public override fun toString(): String = "[mirai:app:$content]"
@ -117,6 +121,7 @@ public data class LightApp(override val content: String) : RichMessage, CodableM
*/ */
@MiraiExperimentalApi @MiraiExperimentalApi
@Serializable @Serializable
@SerialName(SimpleServiceMessage.SERIAL_NAME)
public class SimpleServiceMessage( public class SimpleServiceMessage(
public override val serviceId: Int, public override val serviceId: Int,
public override val content: String public override val content: String
@ -136,6 +141,9 @@ public class SimpleServiceMessage(
return result return result
} }
public companion object {
public const val SERIAL_NAME: String = "SimpleServiceMessage"
}
} }
@ -257,8 +265,7 @@ public class XmlMessageBuilder(
} }
} }
@Serializable // internal runtime value, not serializable
@MiraiExperimentalApi
internal data class LongMessage internal constructor(override val content: String, val resId: String) : internal data class LongMessage internal constructor(override val content: String, val resId: String) :
AbstractServiceMessage() { AbstractServiceMessage() {
override val serviceId: Int get() = 35 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() }) companion object Key : AbstractPolymorphicMessageKey<ServiceMessage, LongMessage>(ServiceMessage, { it.safeCast() })
} }
@Serializable // internal runtime value, not serializable
internal data class ForwardMessageInternal(override val content: String) : AbstractServiceMessage() { internal data class ForwardMessageInternal(override val content: String) : AbstractServiceMessage() {
override val serviceId: Int get() = 35 override val serviceId: Int get() = 35
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.message.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.MiraiInternalApi import net.mamoe.mirai.utils.MiraiInternalApi
@ -40,6 +41,7 @@ public abstract class PttMessage : MessageContent {
* 语音消息, 目前只支持接收和转发 * 语音消息, 目前只支持接收和转发
*/ */
@Serializable // experimental @Serializable // experimental
@SerialName(Voice.SERIAL_NAME)
public class Voice @MiraiInternalApi constructor( public class Voice @MiraiInternalApi constructor(
@MiraiExperimentalApi public override val fileName: String, @MiraiExperimentalApi public override val fileName: String,
@MiraiExperimentalApi public override val md5: ByteArray, @MiraiExperimentalApi public override val md5: ByteArray,
@ -49,7 +51,9 @@ public class Voice @MiraiInternalApi constructor(
private val _url: String private val _url: String
) : PttMessage() { ) : 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? public val url: String?
get() = when { get() = when {

View File

@ -156,7 +156,7 @@ internal fun <M : SingleMessage> MessageChain.getImpl(key: MessageKey<M>): M? {
/** /**
* 使用 [Collection] 作为委托的 [MessageChain] * 使用 [Collection] 作为委托的 [MessageChain]
*/ */
@Serializable @Serializable(MessageChain.Serializer::class)
internal data class MessageChainImpl constructor( internal data class MessageChainImpl constructor(
@JvmField @JvmField
internal val delegate: List<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable internal val delegate: List<SingleMessage> // 必须 constrainSingleMessages, 且为 immutable

View File

@ -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.network.protocol.packet.login.StatSvc
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.MessageSerializer
import net.mamoe.mirai.message.action.Nudge import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX 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() { companion object INSTANCE : MiraiImpl() {
@Suppress("ObjectPropertyName", "unused", "DEPRECATION_ERROR") @Suppress("ObjectPropertyName", "unused", "DEPRECATION_ERROR")
private val _init = Mirai.let { private val _init = Mirai.let {
Message.Serializer.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer()) MessageSerializer.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer())
Message.Serializer.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer()) MessageSerializer.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer())
Message.Serializer.registerSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer()) MessageSerializer.registerSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer())
Message.Serializer.registerSerializer( 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::class,
OfflineMessageSourceImplData.serializer() OfflineMessageSourceImplData.serializer()
) )
MessageSerializer.registerSerializer(
Message.Serializer.registerSerializer( OfflineMessageSourceImplData::class,
MessageSourceFromGroupImpl::class, OfflineMessageSourceImplData.serializer()
MessageSourceFromGroupImpl.serializer()
) )
} }
} }
@ -305,12 +343,12 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
} }
val response: PbMessageSvc.PbMsgWithDraw.Response = when (source) { val response: PbMessageSvc.PbMsgWithDraw.Response = when (source) {
is MessageSourceToGroupImpl, is OnlineMessageSourceToGroupImpl,
is MessageSourceFromGroupImpl is OnlineMessageSourceFromGroupImpl
-> { -> {
val group = when (source) { val group = when (source) {
is MessageSourceToGroupImpl -> source.target is OnlineMessageSourceToGroupImpl -> source.target
is MessageSourceFromGroupImpl -> source.group is OnlineMessageSourceFromGroupImpl -> source.group
else -> error("stub") else -> error("stub")
} }
if (bot.id != source.fromId) { if (bot.id != source.fromId) {
@ -326,10 +364,10 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>() ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
} }
} }
is MessageSourceFromFriendImpl, is OnlineMessageSourceFromFriendImpl,
is MessageSourceToFriendImpl, is OnlineMessageSourceToFriendImpl,
is MessageSourceFromStrangerImpl, is OnlineMessageSourceFromStrangerImpl,
is MessageSourceToStrangerImpl, is OnlineMessageSourceToStrangerImpl,
-> network.run { -> network.run {
check(source.fromId == bot.id) { check(source.fromId == bot.id) {
"can only recall a message sent by bot" "can only recall a message sent by bot"
@ -342,13 +380,13 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
source.time source.time
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>() ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
} }
is MessageSourceFromTempImpl, is OnlineMessageSourceFromTempImpl,
is MessageSourceToTempImpl is OnlineMessageSourceToTempImpl
-> network.run { -> network.run {
check(source.fromId == bot.id) { check(source.fromId == bot.id) {
"can only recall a message sent by bot" "can only recall a message sent by bot"
} }
source as MessageSourceToTempImpl source as OnlineMessageSourceToTempImpl
PbMessageSvc.PbMsgWithDraw.createForTempMessage( PbMessageSvc.PbMsgWithDraw.createForTempMessage(
bot.client, bot.client,
(source.target.group as GroupImpl).uin, (source.target.group as GroupImpl).uin,
@ -592,7 +630,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
forwardMessage: ForwardMessage? forwardMessage: ForwardMessage?
): MessageReceipt<Group> = with(bot.asQQAndroidBot()) { ): MessageReceipt<Group> = with(bot.asQQAndroidBot()) {
message.forEach { message.forEach {
it.message.ensureSequenceIdAvailable() it.messageChain.ensureSequenceIdAvailable()
} }
val group = getGroupOrFail(groupCode) val group = getGroupOrFail(groupCode)
@ -655,7 +693,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
if (isLong) { if (isLong) {
group.sendMessage( group.sendMessage(
RichMessage.longMessage( RichMessage.longMessage(
brief = message.joinToString(limit = 27) { it.message.contentToString() }, brief = message.joinToString(limit = 27) { it.messageChain.contentToString() },
resId = resId, resId = resId,
timeSeconds = time timeSeconds = time
) )

View File

@ -170,7 +170,7 @@ internal class GroupImpl(
ForwardMessage.Node( ForwardMessage.Node(
senderId = bot.id, senderId = bot.id,
time = currentTimeSeconds().toInt(), time = currentTimeSeconds().toInt(),
message = chain, messageChain = chain,
senderName = bot.nick senderName = bot.nick
) )
), ),
@ -195,7 +195,7 @@ internal class GroupImpl(
} }
val result = bot.network.runCatching { val result = bot.network.runCatching {
val source: MessageSourceToGroupImpl val source: OnlineMessageSourceToGroupImpl
MessageSvcPbSendMsg.createToGroup( MessageSvcPbSendMsg.createToGroup(
bot.client, bot.client,
this@GroupImpl, this@GroupImpl,

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.data.MemberInfo
import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.* 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.ensureSequenceIdAvailable
import net.mamoe.mirai.internal.message.firstIsInstanceOrNull import net.mamoe.mirai.internal.message.firstIsInstanceOrNull
import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
@ -81,7 +81,7 @@ internal class NormalMemberImpl constructor(
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
val result = bot.network.runCatching { val result = bot.network.runCatching {
val source: MessageSourceToTempImpl val source: OnlineMessageSourceToTempImpl
MessageSvcPbSendMsg.createToTemp( MessageSvcPbSendMsg.createToTemp(
bot.client, bot.client,
this@NormalMemberImpl, this@NormalMemberImpl,

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.broadcast
import net.mamoe.mirai.event.events.* import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.internal.asQQAndroidBot import net.mamoe.mirai.internal.asQQAndroidBot
import net.mamoe.mirai.internal.message.MessageSourceToFriendImpl import net.mamoe.mirai.internal.message.OnlineMessageSourceToFriendImpl
import net.mamoe.mirai.internal.message.MessageSourceToStrangerImpl import net.mamoe.mirai.internal.message.OnlineMessageSourceToStrangerImpl
import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable 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.MessageSvcPbSendMsg
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToFriend 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( internal suspend fun <T : User> Friend.sendMessageImpl(
message: Message, message: Message,
friendReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<Friend>, friendReceiptConstructor: (OnlineMessageSourceToFriendImpl) -> MessageReceipt<Friend>,
tReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<T> tReceiptConstructor: (OnlineMessageSourceToFriendImpl) -> MessageReceipt<T>
): MessageReceipt<T> { ): MessageReceipt<T> {
contract { callsInPlace(friendReceiptConstructor, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(friendReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
val bot = bot.asQQAndroidBot() val bot = bot.asQQAndroidBot()
@ -56,7 +56,7 @@ internal suspend fun <T : User> Friend.sendMessageImpl(
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
lateinit var source: MessageSourceToFriendImpl lateinit var source: OnlineMessageSourceToFriendImpl
val result = bot.network.runCatching { val result = bot.network.runCatching {
MessageSvcPbSendMsg.createToFriend( MessageSvcPbSendMsg.createToFriend(
bot.client, bot.client,
@ -89,8 +89,8 @@ internal suspend fun <T : User> Friend.sendMessageImpl(
internal suspend fun <T : User> Stranger.sendMessageImpl( internal suspend fun <T : User> Stranger.sendMessageImpl(
message: Message, message: Message,
strangerReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<Stranger>, strangerReceiptConstructor: (OnlineMessageSourceToStrangerImpl) -> MessageReceipt<Stranger>,
tReceiptConstructor: (MessageSourceToStrangerImpl) -> MessageReceipt<T> tReceiptConstructor: (OnlineMessageSourceToStrangerImpl) -> MessageReceipt<T>
): MessageReceipt<T> { ): MessageReceipt<T> {
contract { callsInPlace(strangerReceiptConstructor, InvocationKind.EXACTLY_ONCE) } contract { callsInPlace(strangerReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
val bot = bot.asQQAndroidBot() val bot = bot.asQQAndroidBot()
@ -108,7 +108,7 @@ internal suspend fun <T : User> Stranger.sendMessageImpl(
chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable() chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
lateinit var source: MessageSourceToStrangerImpl lateinit var source: OnlineMessageSourceToStrangerImpl
val result = bot.network.runCatching { val result = bot.network.runCatching {
MessageSvcPbSendMsg.createToStranger( MessageSvcPbSendMsg.createToStranger(
bot.client, bot.client,

View File

@ -328,13 +328,13 @@ internal fun List<MsgComm.Msg>.toMessageChain(
checkNotNull(bot) { "bot is null" } checkNotNull(bot) { "bot is null" }
when (messageSourceKind) { when (messageSourceKind) {
MessageSourceKind.TEMP -> +MessageSourceFromTempImpl(bot, this@toMessageChain) MessageSourceKind.TEMP -> +OnlineMessageSourceFromTempImpl(bot, this@toMessageChain)
MessageSourceKind.GROUP -> +MessageSourceFromGroupImpl(bot, this@toMessageChain) MessageSourceKind.GROUP -> +OnlineMessageSourceFromGroupImpl(bot, this@toMessageChain)
MessageSourceKind.FRIEND -> +MessageSourceFromFriendImpl(bot, this@toMessageChain) MessageSourceKind.FRIEND -> +OnlineMessageSourceFromFriendImpl(bot, this@toMessageChain)
MessageSourceKind.STRANGER -> +MessageSourceFromStrangerImpl(bot, this@toMessageChain) MessageSourceKind.STRANGER -> +OnlineMessageSourceFromStrangerImpl(bot, this@toMessageChain)
} }
} else { } else {
+OfflineMessageSourceImplByMsg(bot, this@toMessageChain, botId) +OfflineMessageSourceImplData(bot, this@toMessageChain, botId)
} }
elements.joinToMessageChain(groupIdOrZero, botId, this) elements.joinToMessageChain(groupIdOrZero, botId, this)
addAll(ptts) addAll(ptts)
@ -348,7 +348,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(botId: Long, groupIdOrZero: Long
if (elements.isEmpty()) if (elements.isEmpty())
error("elements for SourceMsg is empty") error("elements for SourceMsg is empty")
return buildMessageChain(elements.size + 1) { return buildMessageChain(elements.size + 1) {
+OfflineMessageSourceImplBySourceMsg( +OfflineMessageSourceImplData(
delegate = this@toMessageChain, delegate = this@toMessageChain,
botId = botId, botId = botId,
groupIdOrZero = groupIdOrZero groupIdOrZero = groupIdOrZero
@ -422,7 +422,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(groupIdOrZero: Long, botId:
this.forEach { element -> this.forEach { element ->
when { when {
element.srcMsg != null -> { 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.notOnlineImage != null -> list.add(OnlineFriendImageImpl(element.notOnlineImage))
element.customFace != null -> list.add(OnlineGroupImageImpl(element.customFace)) element.customFace != null -> list.add(OnlineGroupImageImpl(element.customFace))

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 package net.mamoe.mirai.internal.message
import kotlinx.io.core.toByteArray import kotlinx.io.core.toByteArray
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem 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 @Serializable
internal data class MarketFaceImpl internal constructor( internal data class MarketFaceImpl internal constructor(
internal val delegate: ImMsgBody.MarketFace, internal val delegate: ImMsgBody.MarketFace,

View File

@ -30,10 +30,13 @@ import net.mamoe.mirai.utils.generateImageIdFromResourceId
import net.mamoe.mirai.utils.hexToBytes import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
@Serializable(with = OnlineGroupImageImpl.Serializer::class)
internal class OnlineGroupImageImpl( internal class OnlineGroupImageImpl(
internal val delegate: ImMsgBody.CustomFace internal val delegate: ImMsgBody.CustomFace
) : @Suppress("DEPRECATION") ) : OnlineGroupImage() {
OnlineGroupImage() { object Serializer : Image.FallbackSerializer("OnlineGroupImage")
override val imageId: String = generateImageId( override val imageId: String = generateImageId(
delegate.picMd5, delegate.picMd5,
delegate.filePath.substringAfterLast('.') delegate.filePath.substringAfterLast('.')
@ -58,10 +61,13 @@ OnlineGroupImage() {
} }
} }
@Serializable(with = OnlineFriendImageImpl.Serializer::class)
internal class OnlineFriendImageImpl( internal class OnlineFriendImageImpl(
internal val delegate: ImMsgBody.NotOnlineImage internal val delegate: ImMsgBody.NotOnlineImage
) : @Suppress("DEPRECATION") ) : @Suppress("DEPRECATION")
OnlineFriendImage() { OnlineFriendImage() {
object Serializer : Image.FallbackSerializer("OnlineFriendImage")
override val imageId: String = override val imageId: String =
generateImageIdFromResourceId(delegate.resId, getImageType(delegate.imgType)) ?: delegate.resId generateImageIdFromResourceId(delegate.resId, getImageType(delegate.imgType)) ?: delegate.resId
override val originUrl: String override val originUrl: String
@ -212,7 +218,6 @@ internal interface SuspendDeferredOriginUrlAware : Image {
suspend fun getUrl(bot: Bot): String suspend fun getUrl(bot: Bot): String
} }
@Suppress("EXPOSED_SUPER_INTERFACE")
internal interface OnlineImage : Image, ConstOriginUrlAware { internal interface OnlineImage : Image, ConstOriginUrlAware {
override val originUrl: String override val originUrl: String
} }
@ -228,11 +233,12 @@ internal interface OfflineImage : Image
/** /**
* @param imageId 参考 [Image.imageId] * @param imageId 参考 [Image.imageId]
*/ */
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") @Serializable(with = OfflineGroupImage.Serializer::class)
@Serializable
internal data class OfflineGroupImage( internal data class OfflineGroupImage(
override val imageId: String override val imageId: String
) : GroupImage(), OfflineImage, DeferredOriginUrlAware { ) : GroupImage(), OfflineImage, DeferredOriginUrlAware {
object Serializer : Image.FallbackSerializer("OfflineGroupImage")
override fun getUrl(bot: Bot): String { override fun getUrl(bot: Bot): String {
return "http://gchat.qpic.cn/gchatpic_new/${bot.id}/0-0-${ return "http://gchat.qpic.cn/gchatpic_new/${bot.id}/0-0-${
imageId.substring(1..36) imageId.substring(1..36)
@ -265,10 +271,12 @@ internal val Image.friendImageId: String
* *
* @param imageId 参考 [Image.imageId] * @param imageId 参考 [Image.imageId]
*/ */
@Serializable @Serializable(with = OfflineFriendImage.Serializer::class)
internal data class OfflineFriendImage( internal data class OfflineFriendImage(
override val imageId: String override val imageId: String
) : FriendImage(), OfflineImage, DeferredOriginUrlAware { ) : FriendImage(), OfflineImage, DeferredOriginUrlAware {
object Serializer : Image.FallbackSerializer("OfflineFriendImage")
override fun getUrl(bot: Bot): String { override fun getUrl(bot: Bot): String {
return "http://c2cpicdw.qpic.cn/offpic_new/${bot.id}${this.friendImageId}/0?term=2" return "http://c2cpicdw.qpic.cn/offpic_new/${bot.id}${this.friendImageId}/0?term=2"
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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, override val bot: Bot,
val msg: List<MsgComm.Msg> val msg: List<MsgComm.Msg>
) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal { ) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromFriend")
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
@ -99,10 +102,13 @@ internal class MessageSourceFromFriendImpl(
override fun toJceData(): ImMsgBody.SourceMsg = jceData override fun toJceData(): ImMsgBody.SourceMsg = jceData
} }
internal class MessageSourceFromStrangerImpl( @Serializable(OnlineMessageSourceFromStrangerImpl.Serializer::class)
internal class OnlineMessageSourceFromStrangerImpl(
override val bot: Bot, override val bot: Bot,
val msg: List<MsgComm.Msg> val msg: List<MsgComm.Msg>
) : OnlineMessageSource.Incoming.FromStranger(), MessageSourceInternal { ) : OnlineMessageSource.Incoming.FromStranger(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromStranger")
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random 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, override val bot: Bot,
private val msg: List<MsgComm.Msg> private val msg: List<MsgComm.Msg>
) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal { ) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromTemp")
override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq } override val sequenceIds: IntArray get() = msg.mapToIntArray { it.msgHead.msgSeq }
override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random } override val internalIds: IntArray get() = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
@ -190,12 +199,12 @@ internal class MessageSourceFromTempImpl(
override fun toJceData(): ImMsgBody.SourceMsg = jceData override fun toJceData(): ImMsgBody.SourceMsg = jceData
} }
@Serializable(MessageSourceFromGroupImpl.Serializer::class) @Serializable(OnlineMessageSourceFromGroupImpl.Serializer::class)
internal data class MessageSourceFromGroupImpl( internal data class OnlineMessageSourceFromGroupImpl(
override val bot: Bot, override val bot: Bot,
private val msg: List<MsgComm.Msg> private val msg: List<MsgComm.Msg>
) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal { ) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("net.mamoe.mirai.internal.message.MessageSourceFromGroupImpl") object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceFromGroupImpl")
@Transient @Transient
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm 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.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.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.message.MessageSourceSerializerImpl
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSourceKind import net.mamoe.mirai.message.data.MessageSourceKind
import net.mamoe.mirai.message.data.OfflineMessageSource import net.mamoe.mirai.message.data.OfflineMessageSource
import net.mamoe.mirai.utils.mapToIntArray import net.mamoe.mirai.utils.mapToIntArray
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@Serializable @Serializable(OfflineMessageSourceImplData.Serializer::class)
internal data class OfflineMessageSourceImplData( internal data class OfflineMessageSourceImplData(
override val kind: MessageSourceKind, override val kind: MessageSourceKind,
override val ids: IntArray, override val ids: IntArray,
@ -36,19 +36,30 @@ internal data class OfflineMessageSourceImplData(
override val originalMessage: MessageChain, override val originalMessage: MessageChain,
override val internalIds: IntArray, override val internalIds: IntArray,
) : OfflineMessageSource(), MessageSourceInternal { ) : OfflineMessageSource(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OfflineMessageSource")
override val sequenceIds: IntArray get() = ids 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 @Transient
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
override fun toJceData(): ImMsgBody.SourceMsg { override fun toJceData(): ImMsgBody.SourceMsg {
return ImMsgBody.SourceMsg( return jceData ?: ImMsgBody.SourceMsg(
origSeqs = sequenceIds, origSeqs = sequenceIds,
senderUin = fromId, senderUin = fromId,
toUin = 0, toUin = 0,
flag = 1, flag = 1,
elems = originalMessage.toRichTextElems( elems = originElems ?: originalMessage.toRichTextElems(
null, //forGroup = kind == MessageSourceKind.GROUP, null, //forGroup = kind == MessageSourceKind.GROUP,
withGeneralFlags = false withGeneralFlags = false
), ),
@ -56,7 +67,7 @@ internal data class OfflineMessageSourceImplData(
time = time, time = time,
pbReserve = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY, pbReserve = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY,
srcMsg = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY srcMsg = net.mamoe.mirai.internal.EMPTY_BYTE_ARRAY
) ).also { jceData = it }
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
@ -90,14 +101,12 @@ internal data class OfflineMessageSourceImplData(
} }
} }
internal class OfflineMessageSourceImplByMsg( internal fun OfflineMessageSourceImplData(
// from other sources' originalMessage
bot: Bot?, bot: Bot?,
val delegate: List<MsgComm.Msg>, delegate: List<MsgComm.Msg>,
override val botId: Long, botId: Long,
) : OfflineMessageSource(), MessageSourceInternal { ): OfflineMessageSourceImplData {
override val kind: MessageSourceKind = val kind = when {
when {
delegate.first().msgHead.groupInfo != null -> { delegate.first().msgHead.groupInfo != null -> {
MessageSourceKind.GROUP MessageSourceKind.GROUP
} }
@ -111,71 +120,41 @@ internal class OfflineMessageSourceImplByMsg(
MessageSourceKind.FRIEND MessageSourceKind.FRIEND
} }
} }
override val ids: IntArray get() = sequenceIds return OfflineMessageSourceImplData(
override val internalIds: IntArray = delegate.mapToIntArray { it.msgHead.msgUid.toInt() } kind = kind,
override val time: Int time = delegate.first().msgHead.msgTime,
get() = delegate.first().msgHead.msgTime fromId = delegate.first().msgHead.fromUin,
override val fromId: Long targetId = delegate.first().msgHead.groupInfo?.groupCode ?: delegate.first().msgHead.toUin,
get() = delegate.first().msgHead.fromUin originalMessage = delegate.toMessageChain(
override val targetId: Long
get() = delegate.first().msgHead.groupInfo?.groupCode ?: delegate.first().msgHead.toUin
override val originalMessage: MessageChain by lazy {
delegate.toMessageChain(
null, null,
botId, botId,
groupIdOrZero = delegate.first().msgHead.groupInfo?.groupCode ?: 0, groupIdOrZero = delegate.first().msgHead.groupInfo?.groupCode ?: 0,
onlineSource = false, onlineSource = false,
messageSourceKind = kind messageSourceKind = kind
) ),
} ids = delegate.mapToIntArray { it.msgHead.msgSeq },
override val sequenceIds: IntArray = delegate.mapToIntArray { it.msgHead.msgSeq } internalIds = delegate.mapToIntArray { it.msgHead.msgUid.toInt() },
botId = botId
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false) ).apply {
originElems = delegate.flatMap { it.msgBody.richText.elems }
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
)
} }
} }
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) internal fun OfflineMessageSourceImplData(
override val sequenceIds: IntArray = delegate.origSeqs delegate: ImMsgBody.SourceMsg,
override val internalIds: IntArray = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()) botId: Long,
.origUids?.mapToIntArray { it.toInt() } ?: intArrayOf() groupIdOrZero: Long,
override val time: Int get() = delegate.time ): OfflineMessageSourceImplData {
override val originalMessage: MessageChain by lazy { delegate.toMessageChain(botId, groupIdOrZero) } return OfflineMessageSourceImplData(
/* kind = if (delegate.srcMsg == null) MessageSourceKind.GROUP else MessageSourceKind.FRIEND,
override val ids: Long ids = delegate.origSeqs,
get() = (delegate.origSeqs?.firstOrNull() internalIds = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer())
?: error("cannot find sequenceId from ImMsgBody.SourceMsg")).toLong().shl(32) or .origUids?.mapToIntArray { it.toInt() } ?: intArrayOf(),
delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!!.and(0xFFFFFFFF) time = delegate.time,
*/ originalMessage = delegate.toMessageChain(botId, groupIdOrZero),
fromId = delegate.senderUin,
override val ids: IntArray get() = sequenceIds targetId = when {
// 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 {
groupIdOrZero != 0L -> groupIdOrZero groupIdOrZero != 0L -> groupIdOrZero
delegate.toUin != 0L -> delegate.toUin delegate.toUin != 0L -> delegate.toUin
delegate.srcMsg != null -> delegate.srcMsg.loadAs(MsgComm.Msg.serializer()).msgHead.toUin delegate.srcMsg != null -> delegate.srcMsg.loadAs(MsgComm.Msg.serializer()).msgHead.toUin
@ -187,10 +166,9 @@ internal class OfflineMessageSourceImplBySourceMsg(
) )
}" }"
)*/ )*/
} },
} botId = botId
).apply {
override fun toJceData(): ImMsgBody.SourceMsg { jceData = delegate
return delegate
} }
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.CoroutineScope
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.serialization.Serializable
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.* 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.receive.OnlinePushPbPushGroupMsg.SendGroupMessageReceipt
import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray 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.MessageChain
import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.message.data.OnlineMessageSource 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 sequenceIds: IntArray,
override val internalIds: IntArray, override val internalIds: IntArray,
override val time: Int, override val time: Int,
@ -80,6 +83,8 @@ internal class MessageSourceToFriendImpl(
override val sender: Bot, override val sender: Bot,
override val target: Friend override val target: Friend
) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal { ) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToFriend")
override val bot: Bot override val bot: Bot
get() = sender get() = sender
override val ids: IntArray override val ids: IntArray
@ -89,7 +94,8 @@ internal class MessageSourceToFriendImpl(
override fun toJceData(): ImMsgBody.SourceMsg = jceData override fun toJceData(): ImMsgBody.SourceMsg = jceData
} }
internal class MessageSourceToStrangerImpl( @Serializable(OnlineMessageSourceToStrangerImpl.Serializer::class)
internal class OnlineMessageSourceToStrangerImpl(
override val sequenceIds: IntArray, override val sequenceIds: IntArray,
override val internalIds: IntArray, override val internalIds: IntArray,
override val time: Int, override val time: Int,
@ -97,6 +103,8 @@ internal class MessageSourceToStrangerImpl(
override val sender: Bot, override val sender: Bot,
override val target: Stranger override val target: Stranger
) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal { ) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToStranger")
override val bot: Bot override val bot: Bot
get() = sender get() = sender
override val ids: IntArray override val ids: IntArray
@ -106,7 +114,8 @@ internal class MessageSourceToStrangerImpl(
override fun toJceData(): ImMsgBody.SourceMsg = jceData override fun toJceData(): ImMsgBody.SourceMsg = jceData
} }
internal class MessageSourceToTempImpl( @Serializable(OnlineMessageSourceToTempImpl.Serializer::class)
internal class OnlineMessageSourceToTempImpl(
override val sequenceIds: IntArray, override val sequenceIds: IntArray,
override val internalIds: IntArray, override val internalIds: IntArray,
override val time: Int, override val time: Int,
@ -114,6 +123,8 @@ internal class MessageSourceToTempImpl(
override val sender: Bot, override val sender: Bot,
override val target: Member override val target: Member
) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal { ) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToTemp")
override val bot: Bot override val bot: Bot
get() = sender get() = sender
override val ids: IntArray override val ids: IntArray
@ -123,7 +134,8 @@ internal class MessageSourceToTempImpl(
override fun toJceData(): ImMsgBody.SourceMsg = jceData override fun toJceData(): ImMsgBody.SourceMsg = jceData
} }
internal class MessageSourceToGroupImpl( @Serializable(OnlineMessageSourceToGroupImpl.Serializer::class)
internal class OnlineMessageSourceToGroupImpl(
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
override val internalIds: IntArray, override val internalIds: IntArray,
override val time: Int, override val time: Int,
@ -131,6 +143,8 @@ internal class MessageSourceToGroupImpl(
override val sender: Bot, override val sender: Bot,
override val target: Group override val target: Group
) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal { ) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToGroup")
override val ids: IntArray override val ids: IntArray
get() = sequenceIds get() = sequenceIds
override val bot: Bot override val bot: Bot
@ -141,7 +155,7 @@ internal class MessageSourceToGroupImpl(
coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>( coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>(
timeoutMillis = 3000 timeoutMillis = 3000
) { ) {
if (it.messageRandom in this@MessageSourceToGroupImpl.internalIds) { if (it.messageRandom in this@OnlineMessageSourceToGroupImpl.internalIds) {
it.sequenceId it.sequenceId
} else null } else null
} }

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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( msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText( richText = ImMsgBody.RichText(
elems = chain.message.asMessageChain() elems = chain.messageChain.asMessageChain()
.toRichTextElems(targetGroup, withGeneralFlags = false).toMutableList() .toRichTextElems(targetGroup, withGeneralFlags = false).toMutableList()
) )
) )

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withLock 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 kotlinx.io.core.*
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Group 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.event.events.*
import net.mamoe.mirai.internal.QQAndroidBot import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.contact.* 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.message.toMessageChain
import net.mamoe.mirai.internal.network.MultiPacket import net.mamoe.mirai.internal.network.MultiPacket
import net.mamoe.mirai.internal.network.Packet 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. ?: return null// don't compare with dstAppId. diff.
val chain = buildMessageChain { val chain = buildMessageChain {
+MessageSourceFromFriendImpl(bot, listOf(this@transform)) +OnlineMessageSourceFromFriendImpl(bot, listOf(this@transform))
for (msgItem in textMsg.msgItems) { for (msgItem in textMsg.msgItems) {
when (msgItem.type) { when (msgItem.type) {
1 -> +PlainText(msgItem.text) 1 -> +PlainText(msgItem.text)

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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, client: QQAndroidClient,
target: Stranger, target: Stranger,
message: MessageChain, message: MessageChain,
source: MessageSourceToStrangerImpl source: OnlineMessageSourceToStrangerImpl
): OutgoingPacket = buildOutgoingUniPacket(client) { ): 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()) ///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, client: QQAndroidClient,
targetFriend: Friend, targetFriend: Friend,
message: MessageChain, message: MessageChain,
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit
): List<OutgoingPacket> { ): List<OutgoingPacket> {
contract { contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE) callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
@ -209,7 +209,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
}, },
postInit = { postInit = {
sourceCallback( sourceCallback(
MessageSourceToFriendImpl( OnlineMessageSourceToFriendImpl(
internalIds = randIds.get(), internalIds = randIds.get(),
sender = client.bot, sender = client.bot,
target = targetFriend, target = targetFriend,
@ -262,7 +262,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
client: QQAndroidClient, client: QQAndroidClient,
targetMember: Member, targetMember: Member,
message: MessageChain, message: MessageChain,
source: MessageSourceToTempImpl source: OnlineMessageSourceToTempImpl
): OutgoingPacket = buildOutgoingUniPacket(client) { ): OutgoingPacket = buildOutgoingUniPacket(client) {
writeProtoBuf( writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq( MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
@ -292,7 +292,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
targetGroup: Group, targetGroup: Group,
message: MessageChain, message: MessageChain,
isForward: Boolean, isForward: Boolean,
source: MessageSourceToGroupImpl source: OnlineMessageSourceToGroupImpl
): OutgoingPacket = buildOutgoingUniPacket(client) { ): 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()) ///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, client: QQAndroidClient,
member: Member, member: Member,
message: MessageChain, message: MessageChain,
crossinline sourceCallback: (MessageSourceToTempImpl) -> Unit crossinline sourceCallback: (OnlineMessageSourceToTempImpl) -> Unit
): OutgoingPacket { ): OutgoingPacket {
contract { contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE) callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
} }
val source = MessageSourceToTempImpl( val source = OnlineMessageSourceToTempImpl(
internalIds = intArrayOf(Random.nextInt().absoluteValue), internalIds = intArrayOf(Random.nextInt().absoluteValue),
sender = client.bot, sender = client.bot,
target = member, target = member,
@ -380,12 +380,12 @@ internal inline fun MessageSvcPbSendMsg.createToStranger(
client: QQAndroidClient, client: QQAndroidClient,
stranger: Stranger, stranger: Stranger,
message: MessageChain, message: MessageChain,
crossinline sourceCallback: (MessageSourceToStrangerImpl) -> Unit crossinline sourceCallback: (OnlineMessageSourceToStrangerImpl) -> Unit
): OutgoingPacket { ): OutgoingPacket {
contract { contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE) callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
} }
val source = MessageSourceToStrangerImpl( val source = OnlineMessageSourceToStrangerImpl(
internalIds = intArrayOf(Random.nextInt().absoluteValue), internalIds = intArrayOf(Random.nextInt().absoluteValue),
sender = client.bot, sender = client.bot,
target = stranger, target = stranger,
@ -406,7 +406,7 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
client: QQAndroidClient, client: QQAndroidClient,
qq: Friend, qq: Friend,
message: MessageChain, message: MessageChain,
crossinline sourceCallback: (MessageSourceToFriendImpl) -> Unit crossinline sourceCallback: (OnlineMessageSourceToFriendImpl) -> Unit
): List<OutgoingPacket> { ): List<OutgoingPacket> {
contract { contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE) callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
@ -425,13 +425,13 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
group: Group, group: Group,
message: MessageChain, message: MessageChain,
isForward: Boolean, isForward: Boolean,
crossinline sourceCallback: (MessageSourceToGroupImpl) -> Unit crossinline sourceCallback: (OnlineMessageSourceToGroupImpl) -> Unit
): OutgoingPacket { ): OutgoingPacket {
contract { contract {
callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE) callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
} }
val messageRandom = Random.nextInt().absoluteValue val messageRandom = Random.nextInt().absoluteValue
val source = MessageSourceToGroupImpl( val source = OnlineMessageSourceToGroupImpl(
group, group,
internalIds = intArrayOf(messageRandom), internalIds = intArrayOf(messageRandom),
sender = client.bot, sender = client.bot,

View File

@ -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 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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.Mirai
import net.mamoe.mirai.internal.message.MarketFaceImpl import net.mamoe.mirai.internal.message.MarketFaceImpl
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.MessageSerializer
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -22,11 +23,13 @@ import kotlin.test.assertEquals
internal class MessageSerializationTest { internal class MessageSerializationTest {
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
private val module get() = Message.Serializer.serializersModule private val module
get() = MessageSerializer.serializersModule
private val format private val format
get() = Json { get() = Json {
serializersModule = module serializersModule = module
useArrayPolymorphism = false // ? useArrayPolymorphism = false // ?
ignoreUnknownKeys = true
} }
private inline fun <reified T : Any> T.serialize(serializer: KSerializer<T> = module.serializer()): String { 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()) { 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( assertEquals(
t, t,
deserialized, deserialized,
@ -78,7 +88,6 @@ internal class MessageSerializationTest {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
private val testConstrainSingleMessageInstances: Array<out ConstrainSingle> = arrayOf( private val testConstrainSingleMessageInstances: Array<out ConstrainSingle> = arrayOf(
LongMessage("content", "resId"),
Mirai.constructMessageSource( Mirai.constructMessageSource(
1L, 1L,
MessageSourceKind.FRIEND, MessageSourceKind.FRIEND,
@ -100,7 +109,12 @@ internal class MessageSerializationTest {
} }
@Test @Test
fun `test serialize each message contents`() { fun `test polymorphic serialization`() {
}
@Test
fun `test contextual serialization`() {
for (message in testMessageContentInstances) { for (message in testMessageContentInstances) {
testSerialization(message, module.serializer(message.javaClass)) testSerialization(message, module.serializer(message.javaClass))
} }