package dev.inmo.tgbotapi.types.chat import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.business_connection.BusinessConnectionId import dev.inmo.tgbotapi.utils.RiskFeature import dev.inmo.tgbotapi.utils.nonstrictJsonFormat import kotlinx.serialization.* import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.* private val formatter get() = nonstrictJsonFormat @Serializable(ChatTypeSerializer::class) sealed class ChatType { abstract val stringified: String @Serializable(ChatTypeSerializer::class) object Sender : ChatType() { override val stringified = "sender" } @Serializable(ChatTypeSerializer::class) object Private : ChatType() { override val stringified = "private" } @Serializable(ChatTypeSerializer::class) object Group : ChatType() { override val stringified = "group" } @Serializable(ChatTypeSerializer::class) object Supergroup : ChatType() { override val stringified = "supergroup" } @Serializable(ChatTypeSerializer::class) object Channel : ChatType() { override val stringified = "channel" } @Serializable(ChatTypeSerializer::class) class Unknown(override val stringified: String) : ChatType() } val String.asChatType get() = when (this) { ChatType.Sender.stringified -> ChatType.Sender ChatType.Private.stringified -> ChatType.Private ChatType.Group.stringified -> ChatType.Group ChatType.Supergroup.stringified -> ChatType.Supergroup ChatType.Channel.stringified -> ChatType.Channel else -> ChatType.Unknown(this) } @RiskFeature object ChatTypeSerializer : KSerializer { override val descriptor: SerialDescriptor = String.serializer().descriptor override fun deserialize(decoder: Decoder): ChatType { return decoder.decodeString().asChatType } override fun serialize(encoder: Encoder, value: ChatType) { encoder.encodeString(value.stringified) } } @RiskFeature object ChatSerializer : KSerializer { @OptIn(InternalSerializationApi::class) override val descriptor: SerialDescriptor = buildSerialDescriptor("PreviewChatSerializer", PolymorphicKind.OPEN) override fun deserialize(decoder: Decoder): Chat { val decodedJson = JsonObject.serializer().deserialize(decoder) return try { formatter.decodeFromJsonElement(ExtendedChatSerializer, decodedJson) } catch (e: SerializationException) { val type = decodedJson[typeField] ?.jsonPrimitive ?.content ?.asChatType ?: error("Field $typeField must be presented, but absent in $decodedJson") val isForum = decodedJson[isForumField] ?.jsonPrimitive ?.booleanOrNull == true when (type) { ChatType.Sender -> formatter.decodeFromJsonElement(PrivateChatImpl.serializer(), decodedJson) ChatType.Private -> formatter.decodeFromJsonElement(PrivateChatImpl.serializer(), decodedJson) ChatType.Group -> formatter.decodeFromJsonElement(GroupChatImpl.serializer(), decodedJson) ChatType.Supergroup -> if (isForum) { formatter.decodeFromJsonElement(ForumChatImpl.serializer(), decodedJson) } else { formatter.decodeFromJsonElement(SupergroupChatImpl.serializer(), decodedJson) } ChatType.Channel -> formatter.decodeFromJsonElement(ChannelChatImpl.serializer(), decodedJson) is ChatType.Unknown -> UnknownChatType( formatter.decodeFromJsonElement(Long.serializer(), decodedJson[chatIdField] ?: JsonPrimitive(-1)).toChatId(), decodedJson.toString(), decodedJson ) } } } override fun serialize(encoder: Encoder, value: Chat) { when (value) { is ExtendedChat -> ExtendedChatSerializer.serialize(encoder, value) is PreviewChat -> PreviewChatSerializer.serialize(encoder, value) is ExtendedBot -> ExtendedBot.serializer().serialize(encoder, value) } } } @RiskFeature object PreviewChatSerializer : KSerializer { @OptIn(InternalSerializationApi::class) override val descriptor: SerialDescriptor = buildSerialDescriptor("PreviewChatSerializer", PolymorphicKind.OPEN) override fun deserialize(decoder: Decoder): PreviewChat { val decodedJson = JsonObject.serializer().deserialize(decoder) val type = decodedJson[typeField] ?.jsonPrimitive ?.content ?.asChatType ?: error("Field $typeField must be presented, but absent in $decodedJson") val isForum = decodedJson[isForumField] ?.jsonPrimitive ?.booleanOrNull == true val isBusiness = decodedJson[chatIdField] ?.jsonPrimitive ?.contentOrNull ?.contains("//") == true return when (type) { ChatType.Sender -> formatter.decodeFromJsonElement(PrivateChatImpl.serializer(), decodedJson) ChatType.Private -> { if (isBusiness) { formatter.decodeFromJsonElement(BusinessChatImpl.serializer(), decodedJson) } else { formatter.decodeFromJsonElement(PrivateChatImpl.serializer(), decodedJson) } } ChatType.Group -> formatter.decodeFromJsonElement(GroupChatImpl.serializer(), decodedJson) ChatType.Supergroup -> if (isForum) { formatter.decodeFromJsonElement(ForumChatImpl.serializer(), decodedJson) } else { formatter.decodeFromJsonElement(SupergroupChatImpl.serializer(), decodedJson) } ChatType.Channel -> formatter.decodeFromJsonElement(ChannelChatImpl.serializer(), decodedJson) is ChatType.Unknown -> UnknownChatType( formatter.decodeFromJsonElement(Long.serializer(), decodedJson[chatIdField] ?: JsonPrimitive(-1)).toChatId(), decodedJson.toString(), decodedJson ) } } override fun serialize(encoder: Encoder, value: PreviewChat) { when (value) { is PrivateChatImpl -> PrivateChatImpl.serializer().serialize(encoder, value) is BusinessChatImpl -> BusinessChatImpl.serializer().serialize(encoder, value) is GroupChatImpl -> GroupChatImpl.serializer().serialize(encoder, value) is SupergroupChatImpl -> SupergroupChatImpl.serializer().serialize(encoder, value) is ForumChatImpl -> ForumChatImpl.serializer().serialize(encoder, value) is ChannelChatImpl -> ChannelChatImpl.serializer().serialize(encoder, value) is CommonBot -> CommonBot.serializer().serialize(encoder, value) is CommonUser -> CommonUser.serializer().serialize(encoder, value) is UnknownChatType -> JsonObject.serializer().serialize(encoder, value.rawJson) } } } @RiskFeature sealed class ExtendedChatSerializer : KSerializer { @OptIn(InternalSerializationApi::class) override val descriptor: SerialDescriptor = buildSerialDescriptor("ExtendedChatSerializer", PolymorphicKind.OPEN) override fun deserialize(decoder: Decoder): ExtendedChat { val decodedJson = JsonObject.serializer().deserialize(decoder) val type = decodedJson[typeField] ?.jsonPrimitive ?.content ?.asChatType ?: error("Field $typeField must be presented, but absent in $decodedJson") val isForum = decodedJson[isForumField] ?.jsonPrimitive ?.booleanOrNull == true return when (type) { ChatType.Sender -> formatter.decodeFromJsonElement(ExtendedPrivateChatImpl.serializer(), decodedJson) ChatType.Private -> formatter.decodeFromJsonElement(ExtendedPrivateChatImpl.serializer(), decodedJson) ChatType.Group -> formatter.decodeFromJsonElement(ExtendedGroupChatImpl.serializer(), decodedJson) ChatType.Supergroup -> if (isForum) { formatter.decodeFromJsonElement(ExtendedForumChatImpl.serializer(), decodedJson) } else { formatter.decodeFromJsonElement(ExtendedSupergroupChatImpl.serializer(), decodedJson) } ChatType.Channel -> formatter.decodeFromJsonElement(ExtendedChannelChatImpl.serializer(), decodedJson) is ChatType.Unknown -> UnknownExtendedChat( formatter.decodeFromJsonElement(Long.serializer(), decodedJson[chatIdField] ?: JsonPrimitive(-1)).toChatId(), decodedJson.toString(), decodedJson ) } } override fun serialize(encoder: Encoder, value: ExtendedChat) { when (value) { is ExtendedPrivateChatImpl -> ExtendedPrivateChatImpl.serializer().serialize(encoder, value) is ExtendedGroupChatImpl -> ExtendedGroupChatImpl.serializer().serialize(encoder, value) is ExtendedSupergroupChatImpl -> ExtendedSupergroupChatImpl.serializer().serialize(encoder, value) is ExtendedForumChatImpl -> ExtendedForumChatImpl.serializer().serialize(encoder, value) is ExtendedChannelChatImpl -> ExtendedChannelChatImpl.serializer().serialize(encoder, value) is ExtendedBot -> ExtendedBot.serializer().serialize(encoder, value) is UnknownExtendedChat -> JsonObject.serializer().serialize(encoder, value.rawJson) } } class BasedOnForumThread(private val threadId: MessageThreadId) : ExtendedChatSerializer() { override fun deserialize(decoder: Decoder): ExtendedChat { return super.deserialize(decoder).let { if (it is ExtendedForumChatImpl) { it.copy( id = (it.id as? ChatIdWithThreadId) ?: ChatIdWithThreadId(it.id.chatId, threadId) ) } else { it } } } } class BasedOnBusinessConnection(private val businessConnectionId: BusinessConnectionId) : ExtendedChatSerializer() { override fun deserialize(decoder: Decoder): ExtendedChat { return super.deserialize(decoder).let { if (it is ExtendedPrivateChatImpl) { it.copy( id = (it.id as? BusinessChatId) ?: BusinessChatId(it.id.chatId, businessConnectionId) ) } else { it } } } } companion object : ExtendedChatSerializer() } @RiskFeature object UserSerializer : KSerializer { private val internalSerializer = JsonObject.serializer() override val descriptor: SerialDescriptor = internalSerializer.descriptor override fun deserialize(decoder: Decoder): User { val asJson = internalSerializer.deserialize(decoder) return when { asJson[isBotField] ?.jsonPrimitive ?.booleanOrNull != true -> nonstrictJsonFormat.decodeFromJsonElement( CommonUser.serializer(), asJson ) else -> { if ((asJson[canJoinGroupsField] ?: asJson[canReadAllGroupMessagesField] ?: asJson[supportInlineQueriesField]) != null ) { nonstrictJsonFormat.decodeFromJsonElement( ExtendedBot.serializer(), asJson ) } else { nonstrictJsonFormat.decodeFromJsonElement( CommonBot.serializer(), asJson ) } } } } override fun serialize(encoder: Encoder, value: User) { when (value) { is CommonUser -> CommonUser.serializer().serialize(encoder, value) is CommonBot -> CommonBot.serializer().serialize(encoder, value) is ExtendedBot -> ExtendedBot.serializer().serialize(encoder, value) } } }