Skip to content

Commit

Permalink
feature: cqcode serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
sgpublic committed Nov 9, 2023
1 parent 70f8108 commit 836e7ce
Show file tree
Hide file tree
Showing 36 changed files with 841 additions and 73 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## 介绍

Mystere 是一个纯 Kotlin、对接 [QQ 开放平台](https://q.qq.com) 的机器人无头客户端。
Mystere 是一个基于 Kotlin/Native、实现了 OneBot 协议、对接 [QQ 开放平台](https://q.qq.com) 的机器人无头客户端。

项目名称取自[《Synduality Noir》](https://synduality-noir.com/)中的 [诺瓦尔(Noir)](https://zh.moegirl.org.cn/%E8%AF%BA%E7%93%A6%E5%B0%94) 里人格 米丝缇(Mystere),希望此项目能如米丝媂一样强大。

Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ plugins {
alias(mystere.plugins.ktor) apply false
alias(mystere.plugins.ktorfit) apply false
alias(mystere.plugins.ksp) apply false
alias(mystere.plugins.buildkonfig) apply false
}
10 changes: 9 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
kotlin.code.style=official
kotlin.native.ignoreDisabledTargets=true

mystere.version=1.0.0-alpha01
mystere.app.version=1.0.0-alpha01
mystere.app.pkgName=io.github.mystere.app

mystere.lib.version=1.0.0-alpha01
mystere.lib.core.pkgName=io.github.mystere.core
mystere.lib.qq.pkgName=io.github.mystere.qq
mystere.lib.onebot.api.pkgName=io.github.mystere.onebot
mystere.lib.onebot.v11.pkgName=io.github.mystere.onebot.v11
mystere.lib.serialization.cqcode.pkgName=io.github.mystere.serialization.cqhttp
3 changes: 3 additions & 0 deletions gradle/mystere.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ kotlin = "1.9.20"
ktor = "2.3.5"
ktorfit = "1.9.1"
ksp = "1.9.20-1.0.14"
buildkonfig = "0.14.0"

kotlinx-coroutines = "1.7.3"
kotlinx-serialization-json = "1.6.0"
Expand Down Expand Up @@ -37,6 +38,7 @@ ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref =
ktor-plugin-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }

kotlinx-serialization-message-pack = { group = "com.wunderbee.kompack", name = "kompack-kotlin-serialization", version.ref = "ktor" }
kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinx-serialization-json" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
yamlkt = { group = "net.mamoe.yamlkt", name = "yamlkt", version.ref = "yamlkt" }

Expand All @@ -56,6 +58,7 @@ kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization"
ktor = { id = "io.ktor.plugin", version.ref = "ktor" }
ktorfit = { id = "de.jensklingenberg.ktorfit", version.ref = "ktorfit" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfig" }

[bundles]

Empty file modified gradlew
100644 → 100755
Empty file.
91 changes: 91 additions & 0 deletions kotlin-serialization-cqcode/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
plugins {
alias(mystere.plugins.kotlin.multiplatform)
alias(mystere.plugins.kotlin.plugin.serialization)
alias(mystere.plugins.buildkonfig)
}

kotlin {
jvm {
jvmToolchain(17)
testRuns.named("test") {
executionTask.configure {
useJUnitPlatform()
}
}
}
macosArm64()
macosX64()
linuxArm64()
linuxX64()
mingwX64()

applyDefaultHierarchyTemplate()

sourceSets {
// common
val commonMain by getting {
dependencies {
implementation(mystere.kotlin.reflect)
implementation(mystere.kotlin.stdlib)
implementation(mystere.kotlinx.serialization.core)
implementation(mystere.kotlinx.serialization.json)
}
}

// jvm
val jvmMain by getting {
dependencies {

}
}

// macos
val macosArm64Main by getting {
dependencies {

}
}
val macosX64Main by getting {
dependencies {

}
}
val macosMain by getting {
dependencies {

}
}

// linux
val linuxX64Main by getting {
dependencies {

}
}
val linuxArm64Main by getting {
dependencies {

}
}
val linuxMain by getting {
dependencies {

}
}

// windows
val mingwX64Main by getting {
dependencies {

}
}
}
}

buildkonfig {
packageName = findProperty("mystere.lib.serialization.cqcode.pkgName")!!.toString()

defaultConfigs {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.github.mystere.serialization.cqcode

import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.StringFormat
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.EmptySerializersModule
import kotlinx.serialization.modules.SerializersModule

sealed class CQCode(
override val serializersModule: SerializersModule
): StringFormat {
override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T {
TODO()
}
override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String {
TODO()
}

companion object: CQCode(
serializersModule = EmptySerializersModule(),
) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package io.github.mystere.serialization.cqcode

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encodeToString
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*

@Serializable(with = CQCodeMessageSerializer::class)
data class CQCodeMessage internal constructor(
internal val chain: ArrayDeque<CQCodeMessageItem> = ArrayDeque()
): List<CQCodeMessageItem> by chain {
operator fun plus(next: CQCodeMessage): CQCodeMessage {
return CQCodeMessage(ArrayDeque(chain).also {
it.addAll(next.chain)
})
}
operator fun plus(next: CQCodeMessageItem): CQCodeMessage {
return CQCodeMessage(ArrayDeque(chain).also {
it.add(next)
})
}

override fun toString(): String {
return with(StringBuilder()) {
for (item in chain) {
append(item.toString())
}
}.toString()
}
}

object CQCodeMessageSerializer: KSerializer<CQCodeMessage> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(
"io.github.mystere.serializer.cqcode.CQCodeMessage"
) {
}

override fun deserialize(decoder: Decoder): CQCodeMessage {
try {
when (decoder) {
is JsonDecoder -> {
val jsonObj = decoder.decodeJsonElement().jsonObject
return CQCodeJson.decodeFromJsonElement(
jsonObj["type"]!!.jsonPrimitive.content.cqCodeSerializer(),
jsonObj["data"]!!.jsonObject,
)
}
is CQCodeMessageItemDecoder -> {
val string = decoder.decodeString()
if (string.contains("[(.*?)]".toRegex())) {
if (!string.startsWith("[CQ:") || !string.endsWith("]")) {
throw SerializationException("Not a valid CQCode: $string")
}
val typeEndIndex = if (string.contains(",")) {
string.indexOf(",")
} else {
string.length - 4
}
return CQCode.decodeFromString(
string.substring(4, typeEndIndex).cqCodeSerializer(),
string,
)
} else {
return CQCodeMessageItem.RawText(string)
}
}
else -> throw SerializationException("Unsupported decoder type: ${decoder::class}")
}
} catch (e: Exception) {
throw SerializationException("Failed to decoder content", e)
}
}

override fun serialize(encoder: Encoder, value: CQCodeMessage) {
try {
when (encoder) {
is JsonEncoder -> {
encoder.encodeJsonElement(buildJsonArray {
for (item in value.chain) {
buildJsonObject {
put("type", JsonPrimitive(item.type))
put("data", CQCodeJson.encodeToJsonElement(value))
}
}
})
}
is CQCodeMessageItemEncoder -> {
encoder.encodeString(with(StringBuilder()) {
for (item in value.chain) {
append(CQCode.encodeToString(item.type.cqCodeSerializer(), item))
}
}.toString())
}
else -> throw SerializationException("Unsupported encoder type: ${encoder::class}")
}
} catch (e: Exception) {
throw SerializationException("Failed to encoder content: $value", e)
}
}
}
Loading

0 comments on commit 836e7ce

Please sign in to comment.