Rewrite MessageSerializers, register serializers in each MessageProtocol, implement for native targets

This commit is contained in:
Him188 2022-06-01 15:17:18 +01:00
parent 13dadd5a95
commit d27228c8c8
37 changed files with 479 additions and 290 deletions

View File

@ -13,10 +13,8 @@ import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.modules.PolymorphicModuleBuilder
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.overwriteWith
import kotlinx.serialization.modules.polymorphic
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.data.*
@ -55,142 +53,11 @@ public open class MessageSourceSerializerImpl(serialName: String) :
}
private val builtInSerializersModule by lazy {
SerializersModule {
// NOTE: contextual serializers disabled because of https://github.com/mamoe/mirai/issues/951
// // non-Message classes
// contextual(RawForwardMessage::class, RawForwardMessage.serializer())
// contextual(ForwardMessage.Node::class, ForwardMessage.Node.serializer())
// contextual(VipFace.Kind::class, VipFace.Kind.serializer())
//
//
// // In case Proguard or something else obfuscated the Kotlin metadata, providing the serializers explicitly will help.
// contextual(At::class, At.serializer())
// contextual(AtAll::class, AtAll.serializer())
// contextual(CustomMessage::class, CustomMessage.serializer())
// contextual(CustomMessageMetadata::class, CustomMessageMetadata.serializer())
// contextual(Face::class, Face.serializer())
// contextual(Image::class, Image.Serializer)
// contextual(PlainText::class, PlainText.serializer())
// contextual(QuoteReply::class, QuoteReply.serializer())
//
// contextual(ForwardMessage::class, ForwardMessage.serializer())
//
//
// contextual(LightApp::class, LightApp.serializer())
// contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
// contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer())
//
// contextual(PttMessage::class, PttMessage.serializer())
// contextual(Voice::class, Voice.serializer())
// contextual(PokeMessage::class, PokeMessage.serializer())
// contextual(VipFace::class, VipFace.serializer())
// contextual(FlashImage::class, FlashImage.serializer())
//
// contextual(MusicShare::class, MusicShare.serializer())
//
// contextual(MessageSource::class, MessageSource.serializer())
// contextual(SingleMessage::class, SingleMessage.Serializer)
contextual(MessageChain::class, MessageChain.Serializer)
contextual(LinearMessageChainImpl::class, LinearMessageChainImpl.serializer())
contextual(ShowImageFlag::class, ShowImageFlag.Serializer)
contextual(MessageOriginKind::class, MessageOriginKind.serializer())
fun PolymorphicModuleBuilder<MessageMetadata>.messageMetadataSubclasses() {
subclass(MessageSource::class, MessageSource.serializer())
subclass(QuoteReply::class, QuoteReply.serializer())
subclass(ShowImageFlag::class, ShowImageFlag.Serializer)
subclass(MessageOrigin::class, MessageOrigin.serializer())
}
fun PolymorphicModuleBuilder<MessageContent>.messageContentSubclasses() {
subclass(At::class, At.serializer())
subclass(AtAll::class, AtAll.serializer())
subclass(Face::class, Face.serializer())
subclass(Image::class, Image.Serializer)
subclass(PlainText::class, PlainText.serializer())
subclass(ForwardMessage::class, ForwardMessage.serializer())
subclass(LightApp::class, LightApp.serializer())
subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
// subclass(PttMessage::class, PttMessage.serializer())
@Suppress("DEPRECATION_ERROR")
subclass(net.mamoe.mirai.message.data.Voice::class, net.mamoe.mirai.message.data.Voice.serializer())
// subclass(HummerMessage::class, HummerMessage.serializer())
subclass(PokeMessage::class, PokeMessage.serializer())
subclass(VipFace::class, VipFace.serializer())
subclass(FlashImage::class, FlashImage.serializer())
subclass(MusicShare::class, MusicShare.serializer())
subclass(Dice::class, Dice.serializer())
}
// polymorphic(SingleMessage::class) {
// subclass(MessageSource::class, MessageSource.serializer())
// default {
// Message.Serializer.serializersModule.getPolymorphic(Message::class, it)
// }
// }
// polymorphic(Message::class) {
// subclass(PlainText::class, PlainText.serializer())
// }
polymorphic(SingleMessage::class) {
messageContentSubclasses()
messageMetadataSubclasses()
}
polymorphic(MessageContent::class) {
messageContentSubclasses()
}
polymorphic(MessageMetadata::class) {
messageMetadataSubclasses()
}
polymorphic(RichMessage::class) {
subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
subclass(LightApp::class, LightApp.serializer())
}
polymorphic(ServiceMessage::class) {
subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
}
//contextual(SingleMessage::class, SingleMessage.Serializer)
// polymorphic(SingleMessage::class, SingleMessage.Serializer) {
// messageContentSubclasses()
// messageMetadataSubclasses()
// singleMessageSubclasses()
// }
// contextual(MessageContent::class, MessageContent.Serializer)
// polymorphic(MessageContent::class, MessageContent.Serializer) {
// messageContentSubclasses()
// }
// contextual(MessageMetadata::class, MessageMetadata.Serializer)
// polymorphic(MessageMetadata::class, MessageMetadata.Serializer) {
// messageMetadataSubclasses()
//
}
}
// Tests:
// net.mamoe.mirai.internal.message.data.MessageSerializationTest
internal object MessageSerializersImpl : MessageSerializers {
private var serializersModuleField: SerializersModule by lateinitMutableProperty {
builtInSerializersModule
SerializersModule { }
}
override val serializersModule: SerializersModule
@ -206,7 +73,7 @@ internal object MessageSerializersImpl : MessageSerializers {
@Synchronized
override fun registerSerializers(serializersModule: SerializersModule) {
serializersModuleField = serializersModule.overwriteWith(serializersModule)
serializersModuleField = this.serializersModule.overwriteWith(serializersModule)
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -73,13 +73,16 @@ public interface MessageSerializers {
* @since 2.0, revised 2.3
*/
@MiraiExperimentalApi
public fun <M : SingleMessage> registerSerializer(type: KClass<M>, serializer: KSerializer<M>)
public fun <M : SingleMessage> registerSerializer(
type: KClass<M>,
serializer: KSerializer<M>
) // not supported on native.
/**
* 合并 [serializersModule] [MessageSerializers.serializersModule] 并覆盖.
*/
@MiraiExperimentalApi
public fun registerSerializers(serializersModule: SerializersModule)
public fun registerSerializers(serializersModule: SerializersModule) // supported on all platforms.
public companion object INSTANCE : MessageSerializers by MessageSerializersImpl
}

View File

@ -17,5 +17,5 @@ internal actual fun <M : Any> SerializersModule.overwritePolymorphicWith(
type: KClass<M>,
serializer: KSerializer<M>
): SerializersModule {
TODO("Not yet implemented")
throw UnsupportedOperationException("overwritePolymorphicWith is not supported on native.")
}

View File

@ -12,8 +12,6 @@
package net.mamoe.mirai.internal
import io.ktor.client.*
import io.ktor.client.engine.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.utils.io.core.*
@ -65,7 +63,6 @@ import net.mamoe.mirai.internal.network.sKey
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal
import net.mamoe.mirai.internal.utils.crypto.TEA
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.*
@ -81,71 +78,13 @@ internal expect fun _MiraiImpl_static_init()
@OptIn(LowLevelApi::class)
// not object for ServiceLoader.
internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
init {
_MiraiImpl_static_init() // companion object is lazily initialized on native
}
companion object {
init {
_MiraiImpl_static_init()
MessageSerializers.registerSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer())
MessageSerializers.registerSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer())
MessageSerializers.registerSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer())
MessageSerializers.registerSerializer(OnlineGroupImageImpl::class, OnlineGroupImageImpl.serializer())
MessageSerializers.registerSerializer(MarketFaceImpl::class, MarketFaceImpl.serializer())
MessageSerializers.registerSerializer(FileMessageImpl::class, FileMessageImpl.serializer())
// MessageSource
MessageSerializers.registerSerializer(
OnlineMessageSourceFromGroupImpl::class,
OnlineMessageSourceFromGroupImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceFromFriendImpl::class,
OnlineMessageSourceFromFriendImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceFromTempImpl::class,
OnlineMessageSourceFromTempImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceFromStrangerImpl::class,
OnlineMessageSourceFromStrangerImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceToGroupImpl::class,
OnlineMessageSourceToGroupImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceToFriendImpl::class,
OnlineMessageSourceToFriendImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceToTempImpl::class,
OnlineMessageSourceToTempImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineMessageSourceToStrangerImpl::class,
OnlineMessageSourceToStrangerImpl.serializer()
)
MessageSerializers.registerSerializer(
OfflineMessageSourceImplData::class,
OfflineMessageSourceImplData.serializer()
)
MessageSerializers.registerSerializer(
OfflineMessageSourceImplData::class,
OfflineMessageSourceImplData.serializer()
)
MessageSerializers.registerSerializer(
UnsupportedMessageImpl::class,
UnsupportedMessageImpl.serializer()
)
MessageSerializers.registerSerializer(
OnlineAudioImpl::class,
OnlineAudioImpl.serializer()
)
MessageSerializers.registerSerializer(
OfflineAudioImpl::class,
OfflineAudioImpl.serializer()
)
}
}

View File

@ -15,6 +15,7 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePostpro
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageSender
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.systemProp
@ -30,7 +31,6 @@ internal abstract class MessageProtocol(
}
fun collectProcessors(processorCollector: ProcessorCollector) {
println("collectProcessors, this=$this, class=${this::class}")
processorCollector.collectProcessorsImpl()
}
@ -74,6 +74,8 @@ internal abstract class ProcessorCollector {
abstract fun add(transformer: OutgoingMessageTransformer)
abstract fun add(sender: OutgoingMessageSender)
abstract fun add(postprocessor: OutgoingMessagePostprocessor)
abstract fun <T : Any> add(serializer: MessageSerializer<T>)
}

View File

@ -9,6 +9,8 @@
package net.mamoe.mirai.internal.message.protocol
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.ContactOrBot
import net.mamoe.mirai.internal.contact.AbstractContact
@ -28,6 +30,7 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE_AS_CHAIN
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.component.ComponentKey
import net.mamoe.mirai.internal.network.component.ComponentStorage
import net.mamoe.mirai.internal.network.component.buildComponentStorage
@ -38,6 +41,7 @@ import net.mamoe.mirai.internal.pipeline.ProcessResult
import net.mamoe.mirai.internal.utils.runCoroutineInPlace
import net.mamoe.mirai.internal.utils.structureToString
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.visitor.RecursiveMessageVisitor
import net.mamoe.mirai.message.data.visitor.accept
@ -51,6 +55,7 @@ internal interface MessageProtocolFacade {
val decoderPipeline: MessageDecoderPipeline
val preprocessorPipeline: OutgoingMessagePipeline
val outgoingPipeline: OutgoingMessagePipeline
val serializers: Collection<MessageSerializer<*>>
val loaded: List<MessageProtocol>
@ -133,13 +138,34 @@ internal interface MessageProtocolFacade {
bot: Bot,
): MessageChain = buildMessageChain { decode(elements, groupIdOrZero, messageSourceKind, bot, this, null) }
fun createSerializersModule(): SerializersModule = SerializersModule {
serializers.forEach { ms ->
@Suppress("UNCHECKED_CAST")
ms as MessageSerializer<SingleMessage>
for (superclass in ms.superclasses) {
polymorphic(superclass) {
subclass(ms.forClass, ms.serializer)
}
}
if (ms.registerAlsoContextual) {
contextual(ms.forClass, ms.serializer)
}
// contextual(ms.forClass, ms.serializer)
}
}
fun copy(): MessageProtocolFacade
/**
* The default global instance.
*/
companion object INSTANCE : MessageProtocolFacade by MessageProtocolFacadeImpl(),
ComponentKey<MessageProtocolFacade>
ComponentKey<MessageProtocolFacade> {
init {
MessageSerializers.registerSerializers(createSerializersModule())
}
}
}
internal fun MessageProtocolFacade.decodeAndRefineLight(
@ -167,6 +193,7 @@ internal class MessageProtocolFacadeImpl(
override val decoderPipeline: MessageDecoderPipeline = MessageDecoderPipelineImpl()
override val preprocessorPipeline: OutgoingMessagePipeline = OutgoingMessagePipelineImpl()
override val outgoingPipeline: OutgoingMessagePipeline = OutgoingMessagePipelineImpl()
override val serializers: MutableCollection<MessageSerializer<*>> = ArrayList(10)
override val loaded: List<MessageProtocol> = kotlin.run {
val instances = protocols
@ -201,6 +228,10 @@ internal class MessageProtocolFacadeImpl(
override fun add(postprocessor: OutgoingMessagePostprocessor) {
outgoingPipeline.registerProcessor(OutgoingMessageProcessorAdapter(postprocessor))
}
override fun <T : Any> add(serializer: MessageSerializer<T>) {
serializers.add(serializer)
}
})
}
instances.toList()

View File

@ -0,0 +1,47 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal.message.protocol.impl
import net.mamoe.mirai.internal.message.data.OfflineAudioImpl
import net.mamoe.mirai.internal.message.data.OnlineAudioImpl
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.message.data.*
internal class AudioProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
MessageSerializer.superclassesScope(
OnlineAudio::class,
Audio::class,
MessageContent::class,
SingleMessage::class
) {
add(MessageSerializer(OnlineAudioImpl::class, OnlineAudioImpl.serializer()))
}
MessageSerializer.superclassesScope(
OfflineAudio::class,
Audio::class,
MessageContent::class,
SingleMessage::class
) {
add(MessageSerializer(OfflineAudioImpl::class, OfflineAudioImpl.serializer()))
}
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
@Suppress("DEPRECATION_ERROR")
add(
MessageSerializer(
net.mamoe.mirai.message.data.Voice::class,
net.mamoe.mirai.message.data.Voice.serializer()
)
)
}
}
}

View File

@ -16,11 +16,14 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.data.Face
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.toByteArray
@ -29,6 +32,15 @@ internal class FaceProtocol : MessageProtocol() {
add(Encoder())
add(Type1Decoder())
add(Type2Decoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(
MessageSerializer(
Face::class,
Face.serializer()
)
)
}
}
private class Encoder : MessageEncoder<Face> {

View File

@ -26,6 +26,7 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageSender
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageTransformer
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.message.source.createMessageReceipt
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.ObjMsg
@ -33,6 +34,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.chat.FileManagement
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
import net.mamoe.mirai.message.data.FileMessage
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.message.data.visitor.RecursiveMessageVisitor
import net.mamoe.mirai.message.data.visitor.acceptChildren
import net.mamoe.mirai.utils.read
@ -51,6 +54,15 @@ internal class FileMessageProtocol : MessageProtocol() {
})
add(FileMessageSender())
MessageSerializer.superclassesScope(FileMessage::class, MessageContent::class, SingleMessage::class) {
add(
MessageSerializer(
FileMessageImpl::class,
FileMessageImpl.serializer()
)
)
}
}
companion object {

View File

@ -22,18 +22,25 @@ import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.collectGeneralFlags
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.contact
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.data.FlashImage
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.utils.hexToBytes
internal class FlashImageProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
add(Decoder())
add(Encoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(FlashImage::class, FlashImage.serializer()))
}
}
private class Decoder : MessageDecoder {

View File

@ -19,14 +19,17 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.components.ClockHolder
import net.mamoe.mirai.message.data.ForwardMessage
import net.mamoe.mirai.message.data.RichMessage
import net.mamoe.mirai.message.data.toMessageChain
import net.mamoe.mirai.message.data.*
internal class ForwardMessageProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
add(ForwardMessageUploader())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(ForwardMessage::class, ForwardMessage.serializer()))
}
}
class ForwardMessageUploader : OutgoingMessagePreprocessor {

View File

@ -26,10 +26,12 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.STEP
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageSender
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.message.source.createMessageReceipt
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
import net.mamoe.mirai.message.data.AtAll
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.message.data.content
import net.mamoe.mirai.utils.MiraiLogger
@ -40,6 +42,8 @@ import net.mamoe.mirai.utils.truncated
internal class GeneralMessageSenderProtocol : MessageProtocol(PRIORITY_GENERAL_SENDER) {
override fun ProcessorCollector.collectProcessorsImpl() {
add(GeneralMessageSender(logger))
add(MessageSerializer(MessageChain::class, MessageChain.serializer(), emptyArray()))
}

View File

@ -45,7 +45,7 @@ internal class IgnoredMessagesProtocol : MessageProtocol(PRIORITY_IGNORE) {
private class Encoder : MessageEncoder<SingleMessage> {
override suspend fun MessageEncoderContext.process(data: SingleMessage) {
when (data) {
is ForwardMessage, // TODO: 2022/4/27 check this
is ForwardMessage,
is MessageSource, // mirai metadata only
-> {
markAsConsumed()

View File

@ -23,12 +23,12 @@ import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Co
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.CONTACT
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.CustomFace
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.ImagePatcher
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.message.data.ImageType
import net.mamoe.mirai.message.data.ShowImageFlag
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.generateImageId
import net.mamoe.mirai.utils.toUHexString
@ -38,6 +38,18 @@ internal class ImageProtocol : MessageProtocol() {
add(ImageDecoder())
add(ImagePatcherForGroup())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(Image::class, Image.Serializer, registerAlsoContextual = true))
}
MessageSerializer.superclassesScope(Image::class, MessageContent::class, SingleMessage::class) {
add(MessageSerializer(Image::class, Image.Serializer))
add(MessageSerializer(OfflineGroupImage::class, OfflineGroupImage.serializer()))
add(MessageSerializer(OfflineFriendImage::class, OfflineFriendImage.serializer()))
add(MessageSerializer(OnlineFriendImageImpl::class, OnlineFriendImageImpl.serializer()))
add(MessageSerializer(OnlineGroupImageImpl::class, OnlineGroupImageImpl.serializer()))
}
}
private class ImagePatcherForGroup : OutgoingMessagePreprocessor {

View File

@ -17,9 +17,9 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.collectGeneralFlags
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.Dice
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.hexToBytes
@ -29,6 +29,19 @@ internal class MarketFaceProtocol : MessageProtocol() {
add(MarketFaceImplEncoder())
add(MarketFaceDecoder())
MessageSerializer.superclassesScope(MarketFace::class, MessageContent::class, SingleMessage::class) {
add(
MessageSerializer(
MarketFaceImpl::class,
MarketFaceImpl.serializer()
)
)
}
MessageSerializer.superclassesScope(MarketFace::class, MessageContent::class, SingleMessage::class) {
add(MessageSerializer(Dice::class, Dice.serializer()))
}
}
private class MarketFaceImplEncoder : MessageEncoder<MarketFaceImpl> {

View File

@ -22,12 +22,10 @@ import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelin
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.ORIGINAL_MESSAGE_AS_CHAIN
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePipelineContext.Companion.components
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessageSender
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.message.source.createMessageReceipt
import net.mamoe.mirai.internal.network.protocol.packet.chat.MusicSharePacket
import net.mamoe.mirai.message.data.MessageSourceKind
import net.mamoe.mirai.message.data.MusicShare
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.content
import net.mamoe.mirai.message.data.*
internal class MusicShareProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
@ -36,6 +34,10 @@ internal class MusicShareProtocol : MessageProtocol() {
// add(Decoder())
add(Sender())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(MusicShare::class, MusicShare.serializer()))
}
}
private class Encoder : MessageEncoder<MusicShare> {

View File

@ -15,12 +15,15 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.PokeMessage
import net.mamoe.mirai.message.data.SingleMessage
internal class PokeMessageProtocol : MessageProtocol() {
companion object {
@ -30,6 +33,10 @@ internal class PokeMessageProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
add(Encoder())
add(Decoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(PokeMessage::class, PokeMessage.serializer()))
}
}
private class Encoder : MessageEncoder<PokeMessage> {

View File

@ -14,14 +14,21 @@ import net.mamoe.mirai.internal.message.protocol.ProcessorCollector
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.collectGeneralFlags
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.PttMessage
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.hexToBytes
internal class PttMessageProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
add(Encoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(At::class, At.serializer()))
add(MessageSerializer(AtAll::class, AtAll.serializer()))
add(MessageSerializer(PlainText::class, PlainText.serializer()))
}
}
private class Encoder : MessageEncoder<PttMessage> {

View File

@ -22,13 +22,10 @@ import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.contact
import net.mamoe.mirai.internal.message.protocol.outgoing.OutgoingMessagePreprocessor
import net.mamoe.mirai.internal.message.source.MessageSourceInternal
import net.mamoe.mirai.internal.message.source.OfflineMessageSourceImplData
import net.mamoe.mirai.internal.message.source.ensureSequenceIdAvailable
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.message.source.*
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.At
import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.message.data.QuoteReply
import net.mamoe.mirai.message.data.*
internal class QuoteReplyProtocol : MessageProtocol(PRIORITY_METADATA) {
override fun ProcessorCollector.collectProcessorsImpl() {
@ -38,6 +35,72 @@ internal class QuoteReplyProtocol : MessageProtocol(PRIORITY_METADATA) {
add(OutgoingMessagePreprocessor {
currentMessageChain[QuoteReply]?.source?.ensureSequenceIdAvailable()
})
MessageSerializer.superclassesScope(MessageSource::class, MessageMetadata::class, SingleMessage::class) {
add(
MessageSerializer(
OnlineMessageSourceFromGroupImpl::class,
OnlineMessageSourceFromGroupImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceFromFriendImpl::class,
OnlineMessageSourceFromFriendImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceFromTempImpl::class,
OnlineMessageSourceFromTempImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceFromStrangerImpl::class,
OnlineMessageSourceFromStrangerImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceToGroupImpl::class,
OnlineMessageSourceToGroupImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceToFriendImpl::class,
OnlineMessageSourceToFriendImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceToTempImpl::class,
OnlineMessageSourceToTempImpl.serializer()
)
)
add(
MessageSerializer(
OnlineMessageSourceToStrangerImpl::class,
OnlineMessageSourceToStrangerImpl.serializer()
)
)
add(
MessageSerializer(
OfflineMessageSourceImplData::class,
OfflineMessageSourceImplData.serializer()
)
)
add(MessageSerializer(MessageSource::class, MessageSource.serializer()))
}
MessageSerializer.superclassesScope(MessageMetadata::class, SingleMessage::class) {
add(MessageSerializer(QuoteReply::class, QuoteReply.serializer()))
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
add(MessageSerializer(ShowImageFlag::class, ShowImageFlag.Serializer))
add(MessageSerializer(MessageOrigin::class, MessageOrigin.serializer()))
}
}
private class Decoder : MessageDecoder {

View File

@ -20,6 +20,7 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.collectGeneralFlags
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.message.runWithBugReport
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.*
@ -45,6 +46,21 @@ internal class RichMessageProtocol : MessageProtocol() {
add(LightAppDecoder())
add(Encoder())
MessageSerializer.superclassesScope(
ServiceMessage::class,
RichMessage::class,
MessageContent::class,
SingleMessage::class
) {
add(MessageSerializer(SimpleServiceMessage::class, SimpleServiceMessage.serializer()))
}
MessageSerializer.superclassesScope(RichMessage::class, MessageContent::class, SingleMessage::class) {
add(MessageSerializer(LightApp::class, LightApp.serializer()))
}
add(MessageSerializer(MessageOriginKind::class, MessageOriginKind.serializer(), emptyArray()))
}
private class Encoder : MessageEncoder<RichMessage> {

View File

@ -23,6 +23,7 @@ import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.CONTACT
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.isForward
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext.Companion.originalMessage
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.read
@ -39,6 +40,13 @@ internal class TextProtocol : MessageProtocol() {
add(AtAllEncoder())
add(Decoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(PlainText::class, PlainText.serializer(), registerAlsoContextual = true))
add(MessageSerializer(At::class, At.serializer(), registerAlsoContextual = true))
add(MessageSerializer(AtAll::class, AtAll.serializer(), registerAlsoContextual = true))
add(MessageSerializer(Face::class, Face.serializer(), registerAlsoContextual = true))
}
}
private class Decoder : MessageDecoder {

View File

@ -16,12 +16,25 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.message.data.UnsupportedMessage
internal class UnsupportedMessageProtocol : MessageProtocol(priority = PRIORITY_UNSUPPORTED) {
override fun ProcessorCollector.collectProcessorsImpl() {
add(Decoder())
add(Encoder())
MessageSerializer.superclassesScope(UnsupportedMessage::class, MessageContent::class, SingleMessage::class) {
add(
MessageSerializer(
UnsupportedMessageImpl::class,
UnsupportedMessageImpl.serializer()
)
)
}
}
private class Decoder : MessageDecoder {

View File

@ -15,16 +15,23 @@ import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoder
import net.mamoe.mirai.internal.message.protocol.decode.MessageDecoderContext
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoder
import net.mamoe.mirai.internal.message.protocol.encode.MessageEncoderContext
import net.mamoe.mirai.internal.message.protocol.serialization.MessageSerializer
import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.message.data.VipFace
internal class VipFaceProtocol : MessageProtocol() {
override fun ProcessorCollector.collectProcessorsImpl() {
add(Encoder())
add(Decoder())
MessageSerializer.superclassesScope(MessageContent::class, SingleMessage::class) {
add(MessageSerializer(VipFace::class, VipFace.serializer()))
}
}
private class Encoder : MessageEncoder<VipFace> {

View File

@ -0,0 +1,61 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal.message.protocol.serialization
import kotlinx.serialization.KSerializer
import net.mamoe.mirai.internal.message.protocol.MessageProtocol
import net.mamoe.mirai.message.data.SingleMessage
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmInline
import kotlin.reflect.KClass
/**
* Collectd in [MessageProtocol.collectProcessors]
*/
internal class MessageSerializer<T : Any>(
/**
* The exact class the [serializer] is for
*/
val forClass: KClass<T>,
val serializer: KSerializer<T>,
/**
* Polymorphic base
*/
val superclasses: Array<out KClass<in T>>,
/**
* Register also this as contextual
*/
val registerAlsoContextual: Boolean = superclasses.isEmpty(),
) {
// This can help native targets, which has no reflection support.
companion object {
fun <T : SingleMessage, R> superclassesScope(
vararg superclasses: KClass<in T>,
block: SuperclassesScope<T>.() -> R
): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return block(SuperclassesScope(superclasses))
}
}
}
@JvmInline
internal value class SuperclassesScope<T : SingleMessage>(
val superclasses: Array<out KClass<in T>>,
)
@Suppress("FunctionName")
internal fun <T : SingleMessage> SuperclassesScope<in T>.MessageSerializer(
forClass: KClass<T>,
serializer: KSerializer<T>,
registerAlsoContextual: Boolean = true,
): MessageSerializer<T> = MessageSerializer(forClass, serializer, superclasses, registerAlsoContextual)

View File

@ -7,6 +7,7 @@
# https://github.com/mamoe/mirai/blob/dev/LICENSE
#
net.mamoe.mirai.internal.message.protocol.impl.AudioProtocol
net.mamoe.mirai.internal.message.protocol.impl.CustomMessageProtocol
net.mamoe.mirai.internal.message.protocol.impl.FaceProtocol
net.mamoe.mirai.internal.message.protocol.impl.FileMessageProtocol

View File

@ -11,7 +11,7 @@
package net.mamoe.mirai.internal
import net.mamoe.mirai.Mirai
import org.junit.jupiter.api.AfterEach
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
internal abstract class AbstractTestWithMiraiImpl : MiraiImpl() {
@ -23,7 +23,7 @@ internal abstract class AbstractTestWithMiraiImpl : MiraiImpl() {
net.mamoe.mirai._MiraiInstance.set(this)
}
@AfterEach
@AfterTest
fun restoreMiraiImpl() {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
net.mamoe.mirai._MiraiInstance.set(originalImpl)

View File

@ -0,0 +1,27 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.BotFactory
import net.mamoe.mirai.internal.test.AbstractTest
import kotlin.test.Test
internal class BotFactoryTest : AbstractTest() {
@Test
fun `inlined newBot in Kotlin`() {
runBlocking {
BotFactory.newBot(123, "") {
inheritCoroutineContext()
}.close()
}
}
}

View File

@ -1,13 +1,13 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.internal
package net.mamoe.mirai.internal.message.data
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.safeCast

View File

@ -28,11 +28,7 @@ import net.mamoe.mirai.message.data.buildForwardMessage
import net.mamoe.mirai.message.data.toMessageChain
import net.mamoe.mirai.utils.Clock
import net.mamoe.mirai.utils.currentTimeSeconds
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertSame
import kotlin.test.assertTrue
import kotlin.test.*
internal class MessageReceiptTest : AbstractTest(), GroupExtensions {
private val bot = MockBot()

View File

@ -29,8 +29,8 @@ import net.mamoe.mirai.internal.test.runBlockingUnit
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.MessageChain.Companion.serializeToJsonString
import net.mamoe.mirai.utils.PlatformLogger
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.isSameType
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
@ -41,7 +41,7 @@ open class TM(private val name: String = Random.nextInt().toString()) : SingleMe
override fun contentToString(): String = name
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
if (!isSameType(this, other)) return false
other as TM
@ -338,7 +338,7 @@ private suspend fun testRecursiveRefine(list: List<ImMsgBody.Elem>, expected: Me
}
private fun assertNodesEquals(excepted: List<ForwardMessage.Node>, actual: List<ForwardMessage.Node>) {
assert(excepted.size == actual.size) { "Length not match" }
assertEquals(excepted.size, actual.size, "Length not match")
for (i in excepted.indices) {
val en = excepted[i]
val an = actual[i]
@ -349,11 +349,30 @@ private fun assertNodesEquals(excepted: List<ForwardMessage.Node>, actual: List<
}
}
@Suppress("unused")
private object Color {
const val RESET = "\u001b[0m"
const val WHITE = "\u001b[97m"
const val RED = "\u001b[31m"
const val EMERALD_GREEN = "\u001b[32m"
const val GOLD = "\u001b[33m"
const val BLUE = "\u001b[34m"
const val PURPLE = "\u001b[35m"
const val GREEN = "\u001b[36m"
const val GRAY = "\u001b[90m"
const val LIGHT_RED = "\u001b[91m"
const val LIGHT_GREEN = "\u001b[92m"
const val LIGHT_YELLOW = "\u001b[93m"
const val LIGHT_BLUE = "\u001b[94m"
const val LIGHT_PURPLE = "\u001b[95m"
const val LIGHT_CYAN = "\u001b[96m"
}
private fun assertMessageChainEquals(expected: MessageChain, actual: MessageChain) {
val color = object : PlatformLogger("") {
val yellow get() = Color.LIGHT_YELLOW.toString()
val green get() = Color.LIGHT_GREEN.toString()
val reset get() = Color.RESET.toString()
val color = object {
val yellow get() = Color.LIGHT_YELLOW
val green get() = Color.LIGHT_GREEN
val reset get() = Color.RESET
}
fun compare(expected: MessageChain, actual: MessageChain): Boolean {

View File

@ -16,16 +16,16 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.serializer
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.test.AbstractTest
import net.mamoe.mirai.internal.utils.structureToString
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.cast
import org.junit.jupiter.api.BeforeAll
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
internal class MessageSerializationTest {
internal class MessageSerializationTest : AbstractTest() {
@Suppress("DEPRECATION_ERROR")
private val module
get() = MessageSerializers.serializersModule
@ -51,7 +51,7 @@ internal class MessageSerializationTest {
println("Result: ${serializer.descriptor.serialName} $serialized")
serialized.deserialize(serializer)
}.getOrElse {
throw AssertionError("Failed to serialize $t", it)
throw IllegalStateException("Failed to serialize $t", it)
}
assertEquals(
t,
@ -113,14 +113,6 @@ internal class MessageSerializationTest {
FileMessageImpl("id", 2, "name", 1)
)
companion object {
@BeforeAll
@JvmStatic
fun init() {
Mirai
}
}
@Serializable
data class W(
val m: FileMessage
@ -170,10 +162,18 @@ internal class MessageSerializationTest {
@Test
fun `test contextual serialization`() {
for (message in testMessageContentInstances) {
testSerialization(message, module.serializer(message.javaClass))
testSerialization(
message,
module.getContextual(message::class)?.cast()
?: error("No contextual serializer found for ${message::class}")
)
}
for (message in testConstrainSingleMessageInstances) {
testSerialization(message, module.serializer(message.javaClass))
testSerialization(
message,
module.getContextual(message::class)?.cast()
?: error("No contextual serializer found for ${message::class}")
)
}
}
@ -186,7 +186,7 @@ internal class MessageSerializationTest {
}
@Test
fun `test MessageSource serializable from #1273`() {
fun `test MessageSource serializable from issue 1273`() {
// #1273
val a = """

View File

@ -9,8 +9,14 @@
package net.mamoe.mirai.internal.message.protocol.impl
import net.mamoe.mirai.internal.utils.structureToString
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.utils.structureToStringIfAvailable
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.data.MessageChain.Companion.serializeToJsonString
import net.mamoe.mirai.message.data.SingleMessage
import net.mamoe.mirai.message.data.messageChainOf
import kotlin.test.assertNotNull
import kotlin.test.asserter
@ -74,10 +80,29 @@ internal interface EqualityAsserter {
}
}
private fun <T> structureToStringOrOrdinaryString(it: T): String =
it.structureToString().ifBlank {
it.structureToStringIfAvailable() ?: error("structureToString is not available")
}
private val json = Json {
isLenient = true
prettyPrint = true
serializersModule = MessageSerializers.serializersModule
}
private fun <T> structureToStringOrOrdinaryString(value: T): String {
if (value == null) return "null"
val valueNotNull: T & Any = value
@Suppress("UNCHECKED_CAST")
return valueNotNull.structureToStringIfAvailable()
// fallback for native
?: kotlin.run {
if (valueNotNull is SingleMessage) {
messageChainOf(valueNotNull).serializeToJsonString(json) // use the stable serialization approach
} else json.encodeToString(
when (valueNotNull) {
is ImMsgBody.Elem -> ImMsgBody.Elem.serializer()
else -> error("Unsupported type: $valueNotNull")
} as KSerializer<Any>, valueNotNull
)
}
}
}
object OrdinaryThenStructural : EqualityAsserter {

View File

@ -14,10 +14,15 @@ package net.mamoe.mirai.internal
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.features.*
import kotlinx.atomicfu.atomic
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
private val initialized = atomic(false)
@Suppress("FunctionName")
internal actual fun _MiraiImpl_static_init() {
// nop
if (!initialized.compareAndSet(expect = false, update = true)) return
MessageProtocolFacade.INSTANCE // register serializers
}
internal actual fun createDefaultHttpClient(): HttpClient {

View File

@ -1,26 +0,0 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.internal
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.BotFactory
import kotlin.test.Test
internal class BotFactoryTest {
@Test
fun `inlined newBot in Kotlin`() {
runBlocking {
BotFactory.newBot(123, "") {
inheritCoroutineContext()
}.close()
}
}
}

View File

@ -10,6 +10,7 @@
package net.mamoe.mirai.internal
import kotlinx.atomicfu.atomic
import net.mamoe.mirai.internal.message.protocol.MessageProtocolFacade
import net.mamoe.mirai.internal.utils.MiraiCoreServices
@ -24,4 +25,5 @@ private val initialized = atomic(false)
internal actual fun _MiraiImpl_static_init() {
if (!initialized.compareAndSet(expect = false, update = true)) return
MiraiCoreServices.registerAll()
MessageProtocolFacade.INSTANCE // register serializers
}

View File

@ -36,6 +36,10 @@ internal object MiraiCoreServices {
msgProtocol,
"net.mamoe.mirai.internal.message.protocol.impl.CustomMessageProtocol"
) { net.mamoe.mirai.internal.message.protocol.impl.CustomMessageProtocol() }
Services.register(
msgProtocol,
"net.mamoe.mirai.internal.message.protocol.impl.AudioProtocol"
) { net.mamoe.mirai.internal.message.protocol.impl.AudioProtocol() }
Services.register(
msgProtocol,
"net.mamoe.mirai.internal.message.protocol.impl.FaceProtocol"