-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from simple-robot/dev/support-unknown-segment
增加 OneBotUnknownSegment 类型支持
- Loading branch information
Showing
6 changed files
with
234 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
...ain/kotlin/love/forte/simbot/component/onebot/v11/message/segment/OneBotUnknownSegment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
* Copyright (c) 2024. ForteScarlet. | ||
* | ||
* This file is part of simbot-component-onebot. | ||
* | ||
* simbot-component-onebot is free software: you can redistribute it and/or modify it under the terms | ||
* of the GNU Lesser General Public License as published by the Free Software Foundation, | ||
* either version 3 of the License, or (at your option) any later version. | ||
* | ||
* simbot-component-onebot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | ||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
* See the GNU Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public License along with simbot-component-onebot. | ||
* If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package love.forte.simbot.component.onebot.v11.message.segment | ||
|
||
import kotlinx.serialization.DeserializationStrategy | ||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.SerializationException | ||
import kotlinx.serialization.SerializationStrategy | ||
import kotlinx.serialization.descriptors.SerialDescriptor | ||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor | ||
import kotlinx.serialization.descriptors.element | ||
import kotlinx.serialization.encoding.* | ||
import kotlinx.serialization.json.JsonObject | ||
import love.forte.simbot.annotations.FragileSimbotAPI | ||
import love.forte.simbot.component.onebot.common.annotations.ExperimentalOneBotAPI | ||
import love.forte.simbot.component.onebot.common.annotations.InternalOneBotAPI | ||
|
||
|
||
/** | ||
* 一个未知类型的 [OneBotMessageSegment]。 | ||
* | ||
* 当所有已知的 [OneBotMessageSegment] | ||
* 子类型均无法直接通过多态序列化器反序列化时, | ||
* 将会直接被解析为 [OneBotUnknownSegment]。 | ||
* | ||
* [OneBotUnknownSegment] 本身不可序列化, | ||
* 需要向 [OneBotUnknownSegmentDeserializer] 提供一个多态类型后进行序列化, | ||
* 且 [data] 的类型为 [JsonObject],因此仅支持 JSON 格式。 | ||
Check warning on line 43 in simbot-component-onebot-v11/simbot-component-onebot-v11-message/src/commonMain/kotlin/love/forte/simbot/component/onebot/v11/message/segment/OneBotUnknownSegment.kt GitHub Actions / Qodana Community for JVMUnresolved reference in KDoc
|
||
* | ||
* 实验性:[OneBotUnknownSegment] 的应用(包括序列化与反序列化)尚在实验中, | ||
* 可能不稳定,且未来可能会随时删除、更改。 | ||
* | ||
* @see OneBotUnknownSegmentDeserializer | ||
* | ||
* @author ForteScarlet | ||
*/ | ||
@FragileSimbotAPI | ||
@ExperimentalOneBotAPI | ||
public data class OneBotUnknownSegment | ||
@InternalOneBotAPI | ||
constructor( | ||
val type: String, | ||
override val data: JsonObject? = null | ||
) : OneBotMessageSegment | ||
|
||
/** | ||
* [OneBotUnknownSegment] 的反序列化器, | ||
* 将任意未知的segment内容解析为 [OneBotUnknownSegment] | ||
* | ||
*/ | ||
@OptIn(FragileSimbotAPI::class) | ||
@InternalOneBotAPI | ||
@ExperimentalOneBotAPI | ||
public object OneBotUnknownSegmentDeserializer : | ||
DeserializationStrategy<OneBotUnknownSegment> { | ||
|
||
override val descriptor: SerialDescriptor = | ||
buildClassSerialDescriptor("OneBotUnknownSegment") { | ||
element<String>("type") | ||
element<JsonObject?>("data", isOptional = true) | ||
} | ||
|
||
@OptIn(ExperimentalSerializationApi::class) | ||
override fun deserialize(decoder: Decoder): OneBotUnknownSegment { | ||
return decoder.decodeStructure(descriptor) { | ||
if (decodeSequentially()) { | ||
val type = decodeStringElement(descriptor, 0) | ||
val data = decodeNullableSerializableElement(descriptor, 1, JsonObject.serializer()) | ||
|
||
return@decodeStructure OneBotUnknownSegment(type, data) | ||
} | ||
|
||
var type: String? = null | ||
var data: JsonObject? = null | ||
|
||
while (true) { | ||
when (val index = decodeElementIndex(descriptor)) { | ||
CompositeDecoder.DECODE_DONE -> break | ||
0 -> type = decodeStringElement(descriptor, 0) | ||
1 -> data = decodeSerializableElement(descriptor, 1, JsonObject.serializer()) | ||
else -> error("Unexpected index: $index") | ||
} | ||
} | ||
|
||
if (type == null) throw SerializationException("Required property 'type' is null or miss") | ||
|
||
OneBotUnknownSegment(type, data) | ||
} | ||
|
||
} | ||
} | ||
|
||
/** | ||
* [OneBotUnknownSegment] 的多态序列化器, | ||
* 提供类型 `type` 后进行序列化。 | ||
*/ | ||
@OptIn(FragileSimbotAPI::class) | ||
@InternalOneBotAPI | ||
@ExperimentalOneBotAPI | ||
public class OneBotUnknownSegmentPolymorphicSerializer(type: String) : | ||
SerializationStrategy<OneBotMessageSegment> { | ||
override val descriptor: SerialDescriptor = | ||
buildClassSerialDescriptor(type) { | ||
element<JsonObject?>("data", isOptional = true) | ||
} | ||
|
||
@OptIn(ExperimentalSerializationApi::class) | ||
override fun serialize(encoder: Encoder, value: OneBotMessageSegment) { | ||
if (value is OneBotUnknownSegment) { | ||
encoder.encodeStructure(descriptor) { | ||
this.encodeNullableSerializableElement(descriptor, 0, JsonObject.serializer(), value.data) | ||
} | ||
} | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
...c/commonTest/kotlin/love/forte/simbot/component/onebot/v11/message/UnknownSegmentTests.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package love.forte.simbot.component.onebot.v11.message | ||
|
||
import kotlinx.serialization.ExperimentalSerializationApi | ||
import kotlinx.serialization.PolymorphicSerializer | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.jsonObject | ||
import kotlinx.serialization.json.jsonPrimitive | ||
import kotlinx.serialization.modules.SerializersModule | ||
import kotlinx.serialization.modules.polymorphic | ||
import love.forte.simbot.annotations.FragileSimbotAPI | ||
import love.forte.simbot.component.onebot.v11.message.segment.* | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertIs | ||
|
||
|
||
/** | ||
* | ||
* @author ForteScarlet | ||
*/ | ||
class UnknownSegmentTests { | ||
@OptIn(ExperimentalSerializationApi::class, FragileSimbotAPI::class) | ||
val json = Json { | ||
isLenient = true | ||
ignoreUnknownKeys = true | ||
serializersModule = SerializersModule { | ||
polymorphic(OneBotMessageSegment::class) { | ||
includeAllOneBotSegmentImpls() | ||
defaultDeserializer { OneBotUnknownSegmentDeserializer } | ||
} | ||
polymorphicDefaultSerializer(OneBotMessageSegment::class) { base -> | ||
if (base is OneBotUnknownSegment) { | ||
OneBotUnknownSegmentPolymorphicSerializer(base.type) | ||
} else { | ||
null | ||
} | ||
} | ||
} | ||
prettyPrint = true | ||
prettyPrintIndent = "\t" | ||
} | ||
|
||
|
||
@OptIn(FragileSimbotAPI::class) | ||
@Test | ||
fun decodeTest() { | ||
val segment = json.decodeFromString( | ||
PolymorphicSerializer(OneBotMessageSegment::class), | ||
""" | ||
{ | ||
"data": { | ||
"file": "1718187789891.mp4", | ||
"path": "", | ||
"file_id": "/d5e14a94-86be-49fd-abe3-c03817b5ac27", | ||
"file_size": "2808485" | ||
}, | ||
"type": "file" | ||
} | ||
""".trimIndent() | ||
) | ||
|
||
assertIs<OneBotUnknownSegment>(segment) | ||
|
||
val obj = json.encodeToJsonElement(PolymorphicSerializer(OneBotMessageSegment::class), segment) | ||
val objType = obj.jsonObject["type"]?.jsonPrimitive?.content | ||
assertEquals("file", objType) | ||
} | ||
|
||
|
||
} |