server: convert :server from kotlin-jvm to KMP with all 9 targets
Punkt 6 of NATIVE-COMPATIBILITY.md. Mirrors :proto's target set:
jvm + macosX64 + macosArm64 + iosX64 + iosArm64 + iosSimulatorArm64
+ linuxX64 + linuxArm64 + mingwX64.
All 9 targets compile via './gradlew :server:assemble'.
No blockers: the only deps (ktor-server-core, ktor-server-content-
negotiation, ktor-serialization-kotlinx-json, kotlinx-coroutines-core,
kotlinx-serialization-json) ship native variants for every target.
kotlin.time.Instant was already in use (not the deprecated
kotlinx.datetime.Instant), so no proto-side work needed.
Only API change vs the JVM version: respondTextWriter (JVM-only) ->
respondBytesWriter + writeStringUtf8 (KMP, ByteWriteChannel API).
SSE behaviour is identical ('data: <json>\n\n' chunks flushed as
they arrive).
Verification: :standalone:jvmTest 44/44 green after the migration
(ChatAgent 15, LlmConfig 6, McpConfig 8, McpRegistry 4, Persistence 11).
No call-site changes needed; :standalone picks up the new :server
jvm artifact automatically.
This commit is contained in:
+12
-10
@@ -40,16 +40,18 @@
|
||||
|
||||
## Блок 3. Наш `:server` модуль
|
||||
|
||||
- 6. [ ] **Переписать `:server` с `kotlin("jvm")` на `kotlin("multiplatform")` с
|
||||
`jvm() + linuxX64()`.** Текущий контракт `Route.agentikAgent(agent, path)` —
|
||||
чистый Ktor Route, не зависит от engine. commonMain: Ktor core + SSE +
|
||||
ContentNegotiation + kotlinx-serialization-json. jvmMain: текущее
|
||||
содержимое. linuxX64Main: тот же commonMain + ktor-server-cio engine для
|
||||
embedded-сервера, если `Main.kt` на linuxX64 будет поднимать сервер сам
|
||||
(иначе — оставить сервер только в jvmMain/:standalone, а `:server`-маршруты
|
||||
вызывать из native-обёртки). Объём: ~30 строк gradle + перенос imports.
|
||||
*Решение: на linuxX64 `:server`-роуты вызываются тем же `Main.kt`-ом через
|
||||
`embeddedServer(CIO, ...)` — engine-нейтральность уже заложена.*
|
||||
- 6. [x] **Переписать `:server` с `kotlin("jvm")` на `kotlin("multiplatform")`.**
|
||||
Все 9 целей сборки (jvm + macosX64 + macosArm64 + iosX64 + iosArm64 +
|
||||
iosSimulatorArm64 + linuxX64 + linuxArm64 + mingwX64) собираются
|
||||
`./gradlew :server:assemble` без ошибок. Блокеров нет: Ktor
|
||||
`ktor-server-{core,sse,cio,content-negotiation}` и `ktor-io` (для
|
||||
`ByteWriteChannel.writeStringUtf8`) есть в KMP-вариантах под все
|
||||
цели; `kotlin.time.Instant` уже использовался. Единственное
|
||||
изменение по сравнению с JVM-версией: `respondTextWriter` (JVM-only)
|
||||
→ `respondBytesWriter` + `writeStringUtf8` (KMP, тот же
|
||||
`ByteWriteChannel` API).
|
||||
Источники переехали `src/main/kotlin/...` → `src/commonMain/kotlin/...`.
|
||||
`:standalone:jvmTest` 44/44 зелёные после миграции.
|
||||
|
||||
## Блок 4. Наш `:proto` модуль
|
||||
|
||||
|
||||
+34
-16
@@ -1,23 +1,41 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
jvmToolchain(21)
|
||||
|
||||
// "Все возможные цели сборки": jvm + весь натив. Зеркалит набор :proto.
|
||||
// Никаких блокеров нет: ktor-server-{core,sse,cio,content-negotiation} имеет
|
||||
// опубликованные linuxX64/macosX64/macosArm64/iosX64/iosArm64/iosSimulatorArm64/
|
||||
// linuxArm64/mingwX64 варианты; :proto уже собирается под все эти таргеты.
|
||||
jvm()
|
||||
macosX64()
|
||||
macosArm64()
|
||||
iosX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
mingwX64()
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(project(":proto"))
|
||||
|
||||
// Ktor (без engine — engine подключает потребитель, см. :standalone).
|
||||
implementation(libs.ktor.server.core)
|
||||
implementation(libs.ktor.server.content.negotiation)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
|
||||
// Commons
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
}
|
||||
commonTest.dependencies {
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":proto"))
|
||||
|
||||
implementation(libs.ktor.server.core)
|
||||
implementation(libs.ktor.server.content.negotiation)
|
||||
implementation(libs.ktor.serialization.kotlinx.json)
|
||||
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
}
|
||||
|
||||
+6
-5
@@ -6,13 +6,14 @@ import io.ktor.server.application.ApplicationCall
|
||||
import io.ktor.server.application.call
|
||||
import io.ktor.server.request.receive
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondBytesWriter
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.response.respondTextWriter
|
||||
import io.ktor.server.routing.Route
|
||||
import io.ktor.server.routing.delete
|
||||
import io.ktor.server.routing.get
|
||||
import io.ktor.server.routing.patch
|
||||
import io.ktor.server.routing.post
|
||||
import io.ktor.utils.io.writeStringUtf8
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.serialization.KSerializer
|
||||
@@ -147,13 +148,13 @@ private suspend fun <T> ApplicationCall.streamJsonSse(
|
||||
serializer: KSerializer<T>,
|
||||
json: Json = agentikJson,
|
||||
) {
|
||||
respondTextWriter(contentType = ContentType.Text.EventStream) {
|
||||
respondBytesWriter(contentType = ContentType.Text.EventStream) {
|
||||
flow.catch { /* клиент отвалился — глушим */ }
|
||||
.collect { value ->
|
||||
val s = json.encodeToString(serializer, value)
|
||||
write("data: ")
|
||||
write(s)
|
||||
write("\n\n")
|
||||
writeStringUtf8("data: ")
|
||||
writeStringUtf8(s)
|
||||
writeStringUtf8("\n\n")
|
||||
flush()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user