diff --git a/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt b/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt index 0aaaf0365..3dd36c720 100644 --- a/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt +++ b/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt @@ -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.messageMetadataSubclasses() { - subclass(MessageSource::class, MessageSource.serializer()) - subclass(QuoteReply::class, QuoteReply.serializer()) - subclass(ShowImageFlag::class, ShowImageFlag.Serializer) - subclass(MessageOrigin::class, MessageOrigin.serializer()) - } - - fun PolymorphicModuleBuilder.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) } } diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt index 29423fcf9..83a8df0bc 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt @@ -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 registerSerializer(type: KClass, serializer: KSerializer) + public fun registerSerializer( + type: KClass, + serializer: KSerializer + ) // 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 } \ No newline at end of file diff --git a/mirai-core-api/src/nativeMain/kotlin/internal/message/overwritePolymorphicWith.kt b/mirai-core-api/src/nativeMain/kotlin/internal/message/overwritePolymorphicWith.kt index 867753bdb..a530e025a 100644 --- a/mirai-core-api/src/nativeMain/kotlin/internal/message/overwritePolymorphicWith.kt +++ b/mirai-core-api/src/nativeMain/kotlin/internal/message/overwritePolymorphicWith.kt @@ -17,5 +17,5 @@ internal actual fun SerializersModule.overwritePolymorphicWith( type: KClass, serializer: KSerializer ): SerializersModule { - TODO("Not yet implemented") + throw UnsupportedOperationException("overwritePolymorphicWith is not supported on native.") } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index c4c719265..aed9103cd 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -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() - ) } } diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocol.kt index cf3111f08..d28831683 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocol.kt @@ -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 add(serializer: MessageSerializer) } diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocolFacade.kt b/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocolFacade.kt index 4ffa003e0..cc7e7823e 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocolFacade.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/MessageProtocolFacade.kt @@ -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> val loaded: List @@ -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 + 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 + ComponentKey { + 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> = ArrayList(10) override val loaded: List = kotlin.run { val instances = protocols @@ -201,6 +228,10 @@ internal class MessageProtocolFacadeImpl( override fun add(postprocessor: OutgoingMessagePostprocessor) { outgoingPipeline.registerProcessor(OutgoingMessageProcessorAdapter(postprocessor)) } + + override fun add(serializer: MessageSerializer) { + serializers.add(serializer) + } }) } instances.toList() diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/AudioProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/AudioProtocol.kt new file mode 100644 index 000000000..e18698de3 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/AudioProtocol.kt @@ -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() + ) + ) + } + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FaceProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FaceProtocol.kt index 92bca0147..b78b1cf1a 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FaceProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FaceProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FileMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FileMessageProtocol.kt index 5c87fb1d4..cac90926c 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FileMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FileMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FlashImageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FlashImageProtocol.kt index eb62154eb..d8123b450 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/FlashImageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/FlashImageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/ForwardMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/ForwardMessageProtocol.kt index 07a3acdfb..025c93057 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/ForwardMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/ForwardMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/GeneralMessageSenderProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/GeneralMessageSenderProtocol.kt index b19fdf8e2..4ffe8fcdc 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/GeneralMessageSenderProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/GeneralMessageSenderProtocol.kt @@ -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())) } diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/IgnoredMessagesProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/IgnoredMessagesProtocol.kt index 1e21c7b6e..2a92e4c8e 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/IgnoredMessagesProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/IgnoredMessagesProtocol.kt @@ -45,7 +45,7 @@ internal class IgnoredMessagesProtocol : MessageProtocol(PRIORITY_IGNORE) { private class Encoder : MessageEncoder { 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() diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/ImageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/ImageProtocol.kt index 465120710..929a73dfe 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/ImageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/ImageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt index 52cb429cc..99c01e273 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MarketFaceProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MusicShareProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MusicShareProtocol.kt index cd6e16180..0198abec1 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/MusicShareProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/MusicShareProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/PokeMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/PokeMessageProtocol.kt index 70720c38c..75762662f 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/PokeMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/PokeMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/PttMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/PttMessageProtocol.kt index a25f1b443..fea8ac1d3 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/PttMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/PttMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/QuoteReplyProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/QuoteReplyProtocol.kt index 1b8c06608..dbe99708e 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/QuoteReplyProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/QuoteReplyProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt index 6e46357e3..b55ae7a48 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/RichMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/TextProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/TextProtocol.kt index 20abf8ee2..b22b19292 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/TextProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/TextProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/UnsupportedMessageProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/UnsupportedMessageProtocol.kt index 13f0aae10..95f551fa2 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/UnsupportedMessageProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/UnsupportedMessageProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/impl/VipFaceProtocol.kt b/mirai-core/src/commonMain/kotlin/message/protocol/impl/VipFaceProtocol.kt index 57fe9cc71..c9d624b7e 100644 --- a/mirai-core/src/commonMain/kotlin/message/protocol/impl/VipFaceProtocol.kt +++ b/mirai-core/src/commonMain/kotlin/message/protocol/impl/VipFaceProtocol.kt @@ -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 { diff --git a/mirai-core/src/commonMain/kotlin/message/protocol/serialization/MessageSerializer.kt b/mirai-core/src/commonMain/kotlin/message/protocol/serialization/MessageSerializer.kt new file mode 100644 index 000000000..02a8788d0 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/message/protocol/serialization/MessageSerializer.kt @@ -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( + /** + * The exact class the [serializer] is for + */ + val forClass: KClass, + val serializer: KSerializer, + /** + * Polymorphic base + */ + val superclasses: Array>, + /** + * Register also this as contextual + */ + val registerAlsoContextual: Boolean = superclasses.isEmpty(), +) { + // This can help native targets, which has no reflection support. + + companion object { + fun superclassesScope( + vararg superclasses: KClass, + block: SuperclassesScope.() -> R + ): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return block(SuperclassesScope(superclasses)) + } + } +} + +@JvmInline +internal value class SuperclassesScope( + val superclasses: Array>, +) + +@Suppress("FunctionName") +internal fun SuperclassesScope.MessageSerializer( + forClass: KClass, + serializer: KSerializer, + registerAlsoContextual: Boolean = true, +): MessageSerializer = MessageSerializer(forClass, serializer, superclasses, registerAlsoContextual) \ No newline at end of file diff --git a/mirai-core/src/commonMain/resources/META-INF/services/net.mamoe.mirai.internal.message.protocol.MessageProtocol b/mirai-core/src/commonMain/resources/META-INF/services/net.mamoe.mirai.internal.message.protocol.MessageProtocol index d6be10ef0..8cabda9dc 100644 --- a/mirai-core/src/commonMain/resources/META-INF/services/net.mamoe.mirai.internal.message.protocol.MessageProtocol +++ b/mirai-core/src/commonMain/resources/META-INF/services/net.mamoe.mirai.internal.message.protocol.MessageProtocol @@ -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 diff --git a/mirai-core/src/jvmTest/kotlin/AbstractTestWithMiraiImpl.kt b/mirai-core/src/commonTest/kotlin/AbstractTestWithMiraiImpl.kt similarity index 94% rename from mirai-core/src/jvmTest/kotlin/AbstractTestWithMiraiImpl.kt rename to mirai-core/src/commonTest/kotlin/AbstractTestWithMiraiImpl.kt index 7667a7fe6..e2e3c084d 100644 --- a/mirai-core/src/jvmTest/kotlin/AbstractTestWithMiraiImpl.kt +++ b/mirai-core/src/commonTest/kotlin/AbstractTestWithMiraiImpl.kt @@ -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) diff --git a/mirai-core/src/commonTest/kotlin/BotFactoryTest.kt b/mirai-core/src/commonTest/kotlin/BotFactoryTest.kt new file mode 100644 index 000000000..9a2bd8716 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/BotFactoryTest.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/mirai-core/src/jvmTest/kotlin/ContentEqualsTest.kt b/mirai-core/src/commonTest/kotlin/message/data/ContentEqualsTest.kt similarity index 87% rename from mirai-core/src/jvmTest/kotlin/ContentEqualsTest.kt rename to mirai-core/src/commonTest/kotlin/message/data/ContentEqualsTest.kt index 929769b76..f93073202 100644 --- a/mirai-core/src/jvmTest/kotlin/ContentEqualsTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/data/ContentEqualsTest.kt @@ -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 diff --git a/mirai-core/src/jvmTest/kotlin/message/data/ForwardRefineTest.kt b/mirai-core/src/commonTest/kotlin/message/data/ForwardRefineTest.kt similarity index 100% rename from mirai-core/src/jvmTest/kotlin/message/data/ForwardRefineTest.kt rename to mirai-core/src/commonTest/kotlin/message/data/ForwardRefineTest.kt diff --git a/mirai-core/src/jvmTest/kotlin/message/data/MessageReceiptTest.kt b/mirai-core/src/commonTest/kotlin/message/data/MessageReceiptTest.kt similarity index 96% rename from mirai-core/src/jvmTest/kotlin/message/data/MessageReceiptTest.kt rename to mirai-core/src/commonTest/kotlin/message/data/MessageReceiptTest.kt index b16485c5e..97abe3dc3 100644 --- a/mirai-core/src/jvmTest/kotlin/message/data/MessageReceiptTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/data/MessageReceiptTest.kt @@ -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() diff --git a/mirai-core/src/jvmTest/kotlin/message/data/MessageRefineTest.kt b/mirai-core/src/commonTest/kotlin/message/data/MessageRefineTest.kt similarity index 95% rename from mirai-core/src/jvmTest/kotlin/message/data/MessageRefineTest.kt rename to mirai-core/src/commonTest/kotlin/message/data/MessageRefineTest.kt index 3fb9d1140..8db22b2c4 100644 --- a/mirai-core/src/jvmTest/kotlin/message/data/MessageRefineTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/data/MessageRefineTest.kt @@ -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, expected: Me } private fun assertNodesEquals(excepted: List, actual: List) { - 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, 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 { diff --git a/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt b/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt similarity index 94% rename from mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt rename to mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt index 7fb2cae34..2af56e562 100644 --- a/mirai-core/src/jvmTest/kotlin/message/data/MessageSerializationTest.kt +++ b/mirai-core/src/commonTest/kotlin/message/data/MessageSerializationTest.kt @@ -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 = """ diff --git a/mirai-core/src/commonTest/kotlin/message/protocol/impl/EqualityAsserter.kt b/mirai-core/src/commonTest/kotlin/message/protocol/impl/EqualityAsserter.kt index 119af8934..ea5107bc1 100644 --- a/mirai-core/src/commonTest/kotlin/message/protocol/impl/EqualityAsserter.kt +++ b/mirai-core/src/commonTest/kotlin/message/protocol/impl/EqualityAsserter.kt @@ -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 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 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, valueNotNull + ) + } + } } object OrdinaryThenStructural : EqualityAsserter { diff --git a/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt b/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt index 286f18881..f46c0686b 100644 --- a/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/jvmBaseMain/kotlin/MiraiImpl.kt @@ -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 { diff --git a/mirai-core/src/jvmTest/kotlin/BotFactoryTest.kt b/mirai-core/src/jvmTest/kotlin/BotFactoryTest.kt deleted file mode 100644 index bb08b7894..000000000 --- a/mirai-core/src/jvmTest/kotlin/BotFactoryTest.kt +++ /dev/null @@ -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() - } - } -} \ No newline at end of file diff --git a/mirai-core/src/nativeMain/kotlin/MiraiImpl.kt b/mirai-core/src/nativeMain/kotlin/MiraiImpl.kt index 52f44d2e0..5718a515c 100644 --- a/mirai-core/src/nativeMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/nativeMain/kotlin/MiraiImpl.kt @@ -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 } diff --git a/mirai-core/src/nativeMain/kotlin/utils/MiraiCoreServices.kt b/mirai-core/src/nativeMain/kotlin/utils/MiraiCoreServices.kt index 0535107a9..f74557f9e 100644 --- a/mirai-core/src/nativeMain/kotlin/utils/MiraiCoreServices.kt +++ b/mirai-core/src/nativeMain/kotlin/utils/MiraiCoreServices.kt @@ -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"