From ce5ddbcf7ad2d127c2b6fe26dda8694794dc0ed0 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 14 Jul 2025 12:43:46 +0200 Subject: [PATCH 1/3] KRPC-113 Support gRPC: Ktor Integration --- .../kotlin/kotlinx/rpc/grpc/GrpcClient.kt | 19 ++++- .../kotlin/kotlinx/rpc/grpc/GrpcServer.kt | 9 +- .../kotlin/kotlinx/rpc/grpc/ManagedChannel.kt | 2 +- .../kotlinx/rpc/grpc/ManagedChannel.js.kt | 2 +- .../kotlinx/rpc/grpc/ManagedChannel.jvm.kt | 4 +- .../kotlinx/rpc/grpc/ManagedChannel.native.kt | 2 +- .../kotlinx/rpc/grpc/ManagedChannel.wasmJs.kt | 2 +- grpc/grpc-ktor-server-test/build.gradle.kts | 41 +++++++++ grpc/grpc-ktor-server-test/gradle.properties | 5 ++ .../rpc/grpc/ktor/server/test/TestServer.kt | 45 ++++++++++ .../src/test/proto/ktor-test-service.proto | 11 +++ .../src/test/resources/logback.xml | 16 ++++ grpc/grpc-ktor-server/build.gradle.kts | 19 +++++ grpc/grpc-ktor-server/gradle.properties | 5 ++ .../kotlinx/rpc/grpc/ktor/server/Server.kt | 85 +++++++++++++++++++ settings.gradle.kts | 3 + 16 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 grpc/grpc-ktor-server-test/build.gradle.kts create mode 100644 grpc/grpc-ktor-server-test/gradle.properties create mode 100644 grpc/grpc-ktor-server-test/src/test/kotlin/kotlinx/rpc/grpc/ktor/server/test/TestServer.kt create mode 100644 grpc/grpc-ktor-server-test/src/test/proto/ktor-test-service.proto create mode 100644 grpc/grpc-ktor-server-test/src/test/resources/logback.xml create mode 100644 grpc/grpc-ktor-server/build.gradle.kts create mode 100644 grpc/grpc-ktor-server/gradle.properties create mode 100644 grpc/grpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/grpc/ktor/server/Server.kt diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt index 8d10243a2..7ba5c588e 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt @@ -10,6 +10,7 @@ import kotlinx.rpc.RpcClient import kotlinx.rpc.grpc.descriptor.GrpcClientDelegate import kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor import kotlinx.rpc.internal.utils.map.RpcInternalConcurrentHashMap +import kotlin.time.Duration /** * GrpcClient manages gRPC communication by providing implementation for making asynchronous RPC calls. @@ -19,6 +20,20 @@ import kotlinx.rpc.internal.utils.map.RpcInternalConcurrentHashMap public class GrpcClient internal constructor(private val channel: ManagedChannel) : RpcClient { private val stubs = RpcInternalConcurrentHashMap() + public fun shutdown() { + stubs.clear() + channel.shutdown() + } + + public fun shutdownNow() { + stubs.clear() + channel.shutdownNow() + } + + public suspend fun awaitTermination(duration: Duration) { + channel.awaitTermination(duration) + } + override suspend fun call(call: RpcCall): T { return call.delegate().call(call) } @@ -39,11 +54,11 @@ public class GrpcClient internal constructor(private val channel: ManagedChannel * Constructor function for the [GrpcClient] class. */ public fun GrpcClient( - name: String, + hostname: String, port: Int, configure: ManagedChannelBuilder<*>.() -> Unit = {}, ): GrpcClient { - val channel = ManagedChannelBuilder(name, port).apply(configure).buildChannel() + val channel = ManagedChannelBuilder(hostname, port).apply(configure).buildChannel() return GrpcClient(channel) } diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt index 4600ea17c..f69865b9b 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt @@ -4,6 +4,7 @@ package kotlinx.rpc.grpc +import kotlinx.atomicfu.atomic import kotlinx.rpc.RpcServer import kotlinx.rpc.descriptor.serviceDescriptorOf import kotlinx.rpc.grpc.annotations.Grpc @@ -65,9 +66,13 @@ public class GrpcServer internal constructor( return grpc.delegate.definitionFor(service) } + private val buildLock = atomic(false) + internal fun build() { - internalServer = Server(serverBuilder) - isBuilt = true + if (buildLock.compareAndSet(expect = false, update = true)) { + internalServer = Server(serverBuilder) + isBuilt = true + } } override val isShutdown: Boolean diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.kt index 5368b683b..c7ea10b53 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.kt @@ -68,7 +68,7 @@ public interface ManagedChannel { */ public expect abstract class ManagedChannelBuilder> -internal expect fun ManagedChannelBuilder(name: String, port: Int): ManagedChannelBuilder<*> +internal expect fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> internal expect fun ManagedChannelBuilder(target: String): ManagedChannelBuilder<*> internal expect fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel diff --git a/grpc/grpc-core/src/jsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.js.kt b/grpc/grpc-core/src/jsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.js.kt index b7330da46..2218a5078 100644 --- a/grpc/grpc-core/src/jsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.js.kt +++ b/grpc/grpc-core/src/jsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.js.kt @@ -20,7 +20,7 @@ internal actual fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel { error("JS target is not supported in gRPC") } -internal actual fun ManagedChannelBuilder(name: String, port: Int): ManagedChannelBuilder<*> { +internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> { error("JS target is not supported in gRPC") } diff --git a/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.jvm.kt b/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.jvm.kt index 602f57c82..559007568 100644 --- a/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.jvm.kt +++ b/grpc/grpc-core/src/jvmMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.jvm.kt @@ -24,8 +24,8 @@ internal actual fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel { return build().toKotlin() } -internal actual fun ManagedChannelBuilder(name: String, port: Int): ManagedChannelBuilder<*> { - return io.grpc.ManagedChannelBuilder.forAddress(name, port) +internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> { + return io.grpc.ManagedChannelBuilder.forAddress(hostname, port) } internal actual fun ManagedChannelBuilder(target: String): ManagedChannelBuilder<*> { diff --git a/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.native.kt b/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.native.kt index 69d4d7c93..41c05518d 100644 --- a/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.native.kt +++ b/grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.native.kt @@ -20,7 +20,7 @@ internal actual fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel { error("Native target is not supported in gRPC") } -internal actual fun ManagedChannelBuilder(name: String, port: Int): ManagedChannelBuilder<*> { +internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> { error("Native target is not supported in gRPC") } diff --git a/grpc/grpc-core/src/wasmJsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.wasmJs.kt b/grpc/grpc-core/src/wasmJsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.wasmJs.kt index 0fbd98458..8e9101a03 100644 --- a/grpc/grpc-core/src/wasmJsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.wasmJs.kt +++ b/grpc/grpc-core/src/wasmJsMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.wasmJs.kt @@ -20,7 +20,7 @@ internal actual fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel { error("WasmJS target is not supported in gRPC") } -internal actual fun ManagedChannelBuilder(name: String, port: Int): ManagedChannelBuilder<*> { +internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> { error("WasmJS target is not supported in gRPC") } diff --git a/grpc/grpc-ktor-server-test/build.gradle.kts b/grpc/grpc-ktor-server-test/build.gradle.kts new file mode 100644 index 000000000..c2d5de339 --- /dev/null +++ b/grpc/grpc-ktor-server-test/build.gradle.kts @@ -0,0 +1,41 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +plugins { + alias(libs.plugins.conventions.jvm) + alias(libs.plugins.kotlinx.rpc) + alias(libs.plugins.protobuf) +} + +dependencies { + // for the jar dependency + testImplementation(kotlin("test")) + testImplementation(projects.grpc.grpcCore) + testImplementation(projects.grpc.grpcKtorServer) + + testImplementation(libs.grpc.kotlin.stub) + testImplementation(libs.grpc.netty) + + testImplementation(libs.ktor.server.core) + testImplementation(libs.ktor.server.test.host) + testRuntimeOnly(libs.logback.classic) +} + +rpc { + grpc { + enabled = true + + val globalRootDir: String by extra + + plugin { + locator { + path = "$globalRootDir/protobuf-plugin/build/libs/protobuf-plugin-$version-all.jar" + } + } + + tasksMatching { it.isTest }.all { + dependsOn(project(":protobuf-plugin").tasks.jar) + } + } +} diff --git a/grpc/grpc-ktor-server-test/gradle.properties b/grpc/grpc-ktor-server-test/gradle.properties new file mode 100644 index 000000000..b68c20f8d --- /dev/null +++ b/grpc/grpc-ktor-server-test/gradle.properties @@ -0,0 +1,5 @@ +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +kotlinx.rpc.exclude.wasmWasi=true diff --git a/grpc/grpc-ktor-server-test/src/test/kotlin/kotlinx/rpc/grpc/ktor/server/test/TestServer.kt b/grpc/grpc-ktor-server-test/src/test/kotlin/kotlinx/rpc/grpc/ktor/server/test/TestServer.kt new file mode 100644 index 000000000..f299fd649 --- /dev/null +++ b/grpc/grpc-ktor-server-test/src/test/kotlin/kotlinx/rpc/grpc/ktor/server/test/TestServer.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.ktor.server.test + +import io.ktor.server.testing.testApplication +import kotlinx.rpc.grpc.GrpcClient +import kotlin.test.Test +import kotlinx.rpc.grpc.ktor.server.grpc +import kotlinx.rpc.registerService +import kotlinx.rpc.withService +import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.minutes + +class KtorTestServiceImpl : KtorTestService { + override suspend fun sayHello(message: Hello): Hello { + return message + } +} + +const val PORT = 8085 + +class TestServer { + @Test + fun testPlainRequests() = testApplication { + application { + grpc(PORT) { + registerService { KtorTestServiceImpl() } + } + } + + startApplication() + + val client = GrpcClient("localhost", PORT) { + usePlaintext() + } + + val response = client.withService().sayHello(Hello { message = "Hello" }) + assertEquals("Hello", response.message, "Wrong response message") + + client.shutdown() + client.awaitTermination(1.minutes) + } +} diff --git a/grpc/grpc-ktor-server-test/src/test/proto/ktor-test-service.proto b/grpc/grpc-ktor-server-test/src/test/proto/ktor-test-service.proto new file mode 100644 index 000000000..2dfd01e0b --- /dev/null +++ b/grpc/grpc-ktor-server-test/src/test/proto/ktor-test-service.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package kotlinx.rpc.grpc.ktor.server.test; + +message Hello { + string message = 1; +} + +service KtorTestService { + rpc sayHello(Hello) returns (Hello); +} diff --git a/grpc/grpc-ktor-server-test/src/test/resources/logback.xml b/grpc/grpc-ktor-server-test/src/test/resources/logback.xml new file mode 100644 index 000000000..85ffa5cfa --- /dev/null +++ b/grpc/grpc-ktor-server-test/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/grpc/grpc-ktor-server/build.gradle.kts b/grpc/grpc-ktor-server/build.gradle.kts new file mode 100644 index 000000000..e71d8343e --- /dev/null +++ b/grpc/grpc-ktor-server/build.gradle.kts @@ -0,0 +1,19 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +plugins { + alias(libs.plugins.conventions.kmp) + alias(libs.plugins.kotlinx.rpc) +} + +kotlin { + sourceSets { + commonMain { + dependencies { + api(projects.grpc.grpcCore) + implementation(libs.ktor.server.core) + } + } + } +} diff --git a/grpc/grpc-ktor-server/gradle.properties b/grpc/grpc-ktor-server/gradle.properties new file mode 100644 index 000000000..b68c20f8d --- /dev/null +++ b/grpc/grpc-ktor-server/gradle.properties @@ -0,0 +1,5 @@ +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +kotlinx.rpc.exclude.wasmWasi=true diff --git a/grpc/grpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/grpc/ktor/server/Server.kt b/grpc/grpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/grpc/ktor/server/Server.kt new file mode 100644 index 000000000..c14155668 --- /dev/null +++ b/grpc/grpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/grpc/ktor/server/Server.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.ktor.server + +import io.ktor.server.application.Application +import io.ktor.server.application.ApplicationStopped +import io.ktor.server.application.ApplicationStopping +import io.ktor.server.application.log +import io.ktor.server.config.getAs +import io.ktor.util.AttributeKey +import kotlinx.rpc.RpcServer +import kotlinx.rpc.grpc.GrpcServer +import kotlinx.rpc.grpc.ServerBuilder + +@Suppress("ConstPropertyName") +public object GrpcConfigKeys { + public const val grpcHostPortPath: String = "ktor.deployment.grpcPort" +} + +/** + * Key used to store and retrieve the [GrpcServer] instance within the application's attributes. + */ +public val GrpcServerKey: AttributeKey = AttributeKey("GrpcServerPluginAttributesKey") + +/** + * Configures and starts a gRPC server within the Ktor application. + * This function integrates with the Ktor lifecycle and manages the lifecycle of the gRPC server + * by subscribing to [ApplicationStopping] and [ApplicationStopped] events. + * It ensures that a gRPC server is properly initialized, started, and shutdown when the application stops. + * + * Usage: + * ```kotlin + * fun Application.module() { + * grpc(port = PORT, configure= { /* ... */ }) { + * registerService { MyServiceImpl() } + * } + * } + * ``` + * + * @param port The port on which the gRPC server will listen for incoming connections. + * Defaults to the value specified in the `ktor.deployment.grpcPort` configuration, or 8001 if not configured. + * @param configure Allows additional configuration of the gRPC server using a platform-specific [ServerBuilder]. + * @param builder A block used to define and register gRPC services for the gRPC server. + * @return The instance of the initialized and running [GrpcServer]. + * @throws IllegalStateException if a gRPC server is already installed or the specified port conflicts with + * an existing HTTP/HTTPS server port. + */ +public fun Application.grpc( + port: Int = environment.config.propertyOrNull(GrpcConfigKeys.grpcHostPortPath)?.getAs() ?: 8001, + configure: ServerBuilder<*>.() -> Unit = {}, + builder: RpcServer.() -> Unit, +): GrpcServer { + if (attributes.contains(GrpcServerKey)) { + error("gRPC Server is already installed, second call to grpc() is not allowed") + } + + var newServer = false + val server = attributes.computeIfAbsent(GrpcServerKey) { + newServer = true + GrpcServer(port, configure, builder) + } + + if (!newServer) { + error("A race detected while installing gRPC Server, second call to grpc() is not allowed") + } + + server.start() + log.debug("Started gRPC server on port $port") + + val stoppingHandle = monitor.subscribe(ApplicationStopping) { + log.debug("Stopping gRPC server") + attributes.getOrNull(GrpcServerKey)?.shutdown() + } + + monitor.subscribe(ApplicationStopped) { + log.debug("gRPC server complete shutdown") + attributes.getOrNull(GrpcServerKey)?.shutdownNow() + + stoppingHandle.dispose() + } + + return server +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 2f84c7fa7..255cff875 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,6 +31,9 @@ includePublic(":protobuf-plugin") include(":grpc") includePublic(":grpc:grpc-core") +includePublic(":grpc:grpc-ktor-server") +// temporary module until KMP project structure support in Protobuf plugin +include(":grpc:grpc-ktor-server-test") includePublic(":bom") From 5b37b6e49882e5ac2be3dc754087e93a5ed4138d Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 14 Jul 2025 12:48:11 +0200 Subject: [PATCH 2/3] Update platforms table --- docs/pages/kotlinx-rpc/topics/platforms.topic | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/pages/kotlinx-rpc/topics/platforms.topic b/docs/pages/kotlinx-rpc/topics/platforms.topic index f846b1dfe..e04453ca3 100644 --- a/docs/pages/kotlinx-rpc/topics/platforms.topic +++ b/docs/pages/kotlinx-rpc/topics/platforms.topic @@ -96,6 +96,14 @@
  • apple
  • ios
  • iosArm64
  • iosSimulatorArm64
  • iosX64
  • macos
  • macosArm64
  • macosX64
  • watchos
  • watchosArm32
  • watchosArm64
  • watchosDeviceArm64
  • watchosSimulatorArm64
  • watchosX64
  • tvos
  • tvosArm64
  • tvosSimulatorArm64
  • tvosX64
  • linux
  • linuxArm64
  • linuxX64
  • windows
  • mingwX64
  • + +grpc-ktor-server +jvm +
  • browser
  • node
  • +
  • wasmJs
  • browser
  • d8
  • node
  • +
  • apple
  • ios
  • iosArm64
  • iosSimulatorArm64
  • iosX64
  • macos
  • macosArm64
  • macosX64
  • watchos
  • watchosArm32
  • watchosArm64
  • watchosDeviceArm64
  • watchosSimulatorArm64
  • watchosX64
  • tvos
  • tvosArm64
  • tvosSimulatorArm64
  • tvosX64
  • linux
  • linuxArm64
  • linuxX64
  • windows
  • mingwX64
  • + + krpc-client jvm From 94dedb45ce57e5d202b42cb7d7fdae49bd37ca96 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 14 Jul 2025 16:35:32 +0200 Subject: [PATCH 3/3] apiDump --- grpc/grpc-core/api/grpc-core.api | 14 +- grpc/grpc-core/api/grpc-core.klib.api | 145 ++++++++++++++++++ .../api/grpc-ktor-server-test.api | 0 .../grpc-ktor-server/api/grpc-ktor-server.api | 11 ++ .../api/grpc-ktor-server.klib.api | 17 ++ 5 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 grpc/grpc-core/api/grpc-core.klib.api create mode 100644 grpc/grpc-ktor-server-test/api/grpc-ktor-server-test.api create mode 100644 grpc/grpc-ktor-server/api/grpc-ktor-server.api create mode 100644 grpc/grpc-ktor-server/api/grpc-ktor-server.klib.api diff --git a/grpc/grpc-core/api/grpc-core.api b/grpc/grpc-core/api/grpc-core.api index 59d28f2b5..52775a07c 100644 --- a/grpc/grpc-core/api/grpc-core.api +++ b/grpc/grpc-core/api/grpc-core.api @@ -1,8 +1,9 @@ public final class kotlinx/rpc/grpc/GrpcClient : kotlinx/rpc/RpcClient { + public final fun awaitTermination-VtjQ1oo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun call (Lkotlinx/rpc/RpcCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun callAsync (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/rpc/RpcCall;)Lkotlinx/coroutines/Deferred; - public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; - public fun provideStubContext (J)Lkotlin/coroutines/CoroutineContext; + public fun callServerStreaming (Lkotlinx/rpc/RpcCall;)Lkotlinx/coroutines/flow/Flow; + public final fun shutdown ()V + public final fun shutdownNow ()V } public final class kotlinx/rpc/grpc/GrpcClientKt { @@ -14,11 +15,11 @@ public final class kotlinx/rpc/grpc/GrpcClientKt { public final class kotlinx/rpc/grpc/GrpcServer : kotlinx/rpc/RpcServer, kotlinx/rpc/grpc/Server { public fun awaitTermination-VtjQ1oo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; - public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; + public fun deregisterService (Lkotlin/reflect/KClass;)V public fun getPort ()I public fun isShutdown ()Z public fun isTerminated ()Z - public fun registerService (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V + public fun registerService (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;)V public fun shutdown ()Lkotlinx/rpc/grpc/GrpcServer; public synthetic fun shutdown ()Lkotlinx/rpc/grpc/Server; public fun shutdownNow ()Lkotlinx/rpc/grpc/GrpcServer; @@ -47,6 +48,7 @@ public final class kotlinx/rpc/grpc/ManagedChannel_jvmKt { public abstract interface class kotlinx/rpc/grpc/Server { public abstract fun awaitTermination-VtjQ1oo (JLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static synthetic fun awaitTermination-VtjQ1oo$default (Lkotlinx/rpc/grpc/Server;JLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public abstract fun getPort ()I public abstract fun isShutdown ()Z public abstract fun isTerminated ()Z @@ -102,7 +104,7 @@ public final class kotlinx/rpc/grpc/StatusRuntimeException_jvmKt { public abstract interface class kotlinx/rpc/grpc/descriptor/GrpcClientDelegate { public abstract fun call (Lkotlinx/rpc/RpcCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public abstract fun callAsync (Lkotlinx/rpc/RpcCall;)Lkotlinx/coroutines/Deferred; + public abstract fun callServerStreaming (Lkotlinx/rpc/RpcCall;)Lkotlinx/coroutines/flow/Flow; } public abstract interface class kotlinx/rpc/grpc/descriptor/GrpcDelegate { diff --git a/grpc/grpc-core/api/grpc-core.klib.api b/grpc/grpc-core/api/grpc-core.klib.api new file mode 100644 index 000000000..730a3f7d5 --- /dev/null +++ b/grpc/grpc-core/api/grpc-core.klib.api @@ -0,0 +1,145 @@ +// Klib ABI Dump +// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +abstract interface <#A: kotlin/Any> kotlinx.rpc.grpc.descriptor/GrpcDelegate { // kotlinx.rpc.grpc.descriptor/GrpcDelegate|null[0] + abstract fun clientProvider(kotlinx.rpc.grpc/ManagedChannel): kotlinx.rpc.grpc.descriptor/GrpcClientDelegate // kotlinx.rpc.grpc.descriptor/GrpcDelegate.clientProvider|clientProvider(kotlinx.rpc.grpc.ManagedChannel){}[0] + abstract fun definitionFor(#A): kotlinx.rpc.grpc/ServerServiceDefinition // kotlinx.rpc.grpc.descriptor/GrpcDelegate.definitionFor|definitionFor(1:0){}[0] +} + +abstract interface <#A: kotlin/Any> kotlinx.rpc.grpc.descriptor/GrpcServiceDescriptor : kotlinx.rpc.descriptor/RpcServiceDescriptor<#A> { // kotlinx.rpc.grpc.descriptor/GrpcServiceDescriptor|null[0] + abstract val delegate // kotlinx.rpc.grpc.descriptor/GrpcServiceDescriptor.delegate|{}delegate[0] + abstract fun (): kotlinx.rpc.grpc.descriptor/GrpcDelegate<#A> // kotlinx.rpc.grpc.descriptor/GrpcServiceDescriptor.delegate.|(){}[0] +} + +abstract interface kotlinx.rpc.grpc.descriptor/GrpcClientDelegate { // kotlinx.rpc.grpc.descriptor/GrpcClientDelegate|null[0] + abstract fun <#A1: kotlin/Any?> callServerStreaming(kotlinx.rpc/RpcCall): kotlinx.coroutines.flow/Flow<#A1> // kotlinx.rpc.grpc.descriptor/GrpcClientDelegate.callServerStreaming|callServerStreaming(kotlinx.rpc.RpcCall){0§}[0] + abstract suspend fun <#A1: kotlin/Any?> call(kotlinx.rpc/RpcCall): #A1 // kotlinx.rpc.grpc.descriptor/GrpcClientDelegate.call|call(kotlinx.rpc.RpcCall){0§}[0] +} + +abstract interface kotlinx.rpc.grpc/ManagedChannel { // kotlinx.rpc.grpc/ManagedChannel|null[0] + abstract val isShutdown // kotlinx.rpc.grpc/ManagedChannel.isShutdown|{}isShutdown[0] + abstract fun (): kotlin/Boolean // kotlinx.rpc.grpc/ManagedChannel.isShutdown.|(){}[0] + abstract val isTerminated // kotlinx.rpc.grpc/ManagedChannel.isTerminated|{}isTerminated[0] + abstract fun (): kotlin/Boolean // kotlinx.rpc.grpc/ManagedChannel.isTerminated.|(){}[0] + abstract val platformApi // kotlinx.rpc.grpc/ManagedChannel.platformApi|{}platformApi[0] + abstract fun (): kotlinx.rpc.grpc/ManagedChannelPlatform // kotlinx.rpc.grpc/ManagedChannel.platformApi.|(){}[0] + + abstract fun shutdown(): kotlinx.rpc.grpc/ManagedChannel // kotlinx.rpc.grpc/ManagedChannel.shutdown|shutdown(){}[0] + abstract fun shutdownNow(): kotlinx.rpc.grpc/ManagedChannel // kotlinx.rpc.grpc/ManagedChannel.shutdownNow|shutdownNow(){}[0] + abstract suspend fun awaitTermination(kotlin.time/Duration): kotlin/Boolean // kotlinx.rpc.grpc/ManagedChannel.awaitTermination|awaitTermination(kotlin.time.Duration){}[0] +} + +abstract interface kotlinx.rpc.grpc/Server { // kotlinx.rpc.grpc/Server|null[0] + abstract val isShutdown // kotlinx.rpc.grpc/Server.isShutdown|{}isShutdown[0] + abstract fun (): kotlin/Boolean // kotlinx.rpc.grpc/Server.isShutdown.|(){}[0] + abstract val isTerminated // kotlinx.rpc.grpc/Server.isTerminated|{}isTerminated[0] + abstract fun (): kotlin/Boolean // kotlinx.rpc.grpc/Server.isTerminated.|(){}[0] + abstract val port // kotlinx.rpc.grpc/Server.port|{}port[0] + abstract fun (): kotlin/Int // kotlinx.rpc.grpc/Server.port.|(){}[0] + + abstract fun shutdown(): kotlinx.rpc.grpc/Server // kotlinx.rpc.grpc/Server.shutdown|shutdown(){}[0] + abstract fun shutdownNow(): kotlinx.rpc.grpc/Server // kotlinx.rpc.grpc/Server.shutdownNow|shutdownNow(){}[0] + abstract fun start(): kotlinx.rpc.grpc/Server // kotlinx.rpc.grpc/Server.start|start(){}[0] + abstract suspend fun awaitTermination(kotlin.time/Duration = ...): kotlinx.rpc.grpc/Server // kotlinx.rpc.grpc/Server.awaitTermination|awaitTermination(kotlin.time.Duration){}[0] +} + +abstract interface kotlinx.rpc.grpc/Status { // kotlinx.rpc.grpc/Status|null[0] + abstract val cause // kotlinx.rpc.grpc/Status.cause|{}cause[0] + abstract fun (): kotlin/Throwable? // kotlinx.rpc.grpc/Status.cause.|(){}[0] + abstract val code // kotlinx.rpc.grpc/Status.code|{}code[0] + abstract fun (): kotlinx.rpc.grpc/Status.Code // kotlinx.rpc.grpc/Status.code.|(){}[0] + abstract val description // kotlinx.rpc.grpc/Status.description|{}description[0] + abstract fun (): kotlin/String? // kotlinx.rpc.grpc/Status.description.|(){}[0] + + final enum class Code : kotlin/Enum { // kotlinx.rpc.grpc/Status.Code|null[0] + enum entry ABORTED // kotlinx.rpc.grpc/Status.Code.ABORTED|null[0] + enum entry ALREADY_EXISTS // kotlinx.rpc.grpc/Status.Code.ALREADY_EXISTS|null[0] + enum entry CANCELLED // kotlinx.rpc.grpc/Status.Code.CANCELLED|null[0] + enum entry DATA_LOSS // kotlinx.rpc.grpc/Status.Code.DATA_LOSS|null[0] + enum entry DEADLINE_EXCEEDED // kotlinx.rpc.grpc/Status.Code.DEADLINE_EXCEEDED|null[0] + enum entry FAILED_PRECONDITION // kotlinx.rpc.grpc/Status.Code.FAILED_PRECONDITION|null[0] + enum entry INTERNAL // kotlinx.rpc.grpc/Status.Code.INTERNAL|null[0] + enum entry INVALID_ARGUMENT // kotlinx.rpc.grpc/Status.Code.INVALID_ARGUMENT|null[0] + enum entry NOT_FOUND // kotlinx.rpc.grpc/Status.Code.NOT_FOUND|null[0] + enum entry OK // kotlinx.rpc.grpc/Status.Code.OK|null[0] + enum entry OUT_OF_RANGE // kotlinx.rpc.grpc/Status.Code.OUT_OF_RANGE|null[0] + enum entry PERMISSION_DENIED // kotlinx.rpc.grpc/Status.Code.PERMISSION_DENIED|null[0] + enum entry RESOURCE_EXHAUSTED // kotlinx.rpc.grpc/Status.Code.RESOURCE_EXHAUSTED|null[0] + enum entry UNAUTHENTICATED // kotlinx.rpc.grpc/Status.Code.UNAUTHENTICATED|null[0] + enum entry UNAVAILABLE // kotlinx.rpc.grpc/Status.Code.UNAVAILABLE|null[0] + enum entry UNIMPLEMENTED // kotlinx.rpc.grpc/Status.Code.UNIMPLEMENTED|null[0] + enum entry UNKNOWN // kotlinx.rpc.grpc/Status.Code.UNKNOWN|null[0] + + final val entries // kotlinx.rpc.grpc/Status.Code.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // kotlinx.rpc.grpc/Status.Code.entries.|#static(){}[0] + final val value // kotlinx.rpc.grpc/Status.Code.value|{}value[0] + final fun (): kotlin/Int // kotlinx.rpc.grpc/Status.Code.value.|(){}[0] + final val valueAscii // kotlinx.rpc.grpc/Status.Code.valueAscii|{}valueAscii[0] + final fun (): kotlin/ByteArray // kotlinx.rpc.grpc/Status.Code.valueAscii.|(){}[0] + + final fun valueOf(kotlin/String): kotlinx.rpc.grpc/Status.Code // kotlinx.rpc.grpc/Status.Code.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // kotlinx.rpc.grpc/Status.Code.values|values#static(){}[0] + } +} + +abstract interface kotlinx.rpc.grpc/StatusRuntimeException { // kotlinx.rpc.grpc/StatusRuntimeException|null[0] + abstract val status // kotlinx.rpc.grpc/StatusRuntimeException.status|{}status[0] + abstract fun (): kotlinx.rpc.grpc/Status // kotlinx.rpc.grpc/StatusRuntimeException.status.|(){}[0] +} + +abstract class <#A: kotlinx.rpc.grpc/ManagedChannelBuilder<#A>> kotlinx.rpc.grpc/ManagedChannelBuilder { // kotlinx.rpc.grpc/ManagedChannelBuilder|null[0] + constructor () // kotlinx.rpc.grpc/ManagedChannelBuilder.|(){}[0] +} + +abstract class <#A: kotlinx.rpc.grpc/ServerBuilder<#A>> kotlinx.rpc.grpc/ServerBuilder { // kotlinx.rpc.grpc/ServerBuilder|null[0] + constructor () // kotlinx.rpc.grpc/ServerBuilder.|(){}[0] + + abstract fun addService(kotlinx.rpc.grpc/ServerServiceDefinition): #A // kotlinx.rpc.grpc/ServerBuilder.addService|addService(kotlinx.rpc.grpc.ServerServiceDefinition){}[0] + abstract fun fallbackHandlerRegistry(kotlinx.rpc.grpc/HandlerRegistry?): #A // kotlinx.rpc.grpc/ServerBuilder.fallbackHandlerRegistry|fallbackHandlerRegistry(kotlinx.rpc.grpc.HandlerRegistry?){}[0] +} + +abstract class kotlinx.rpc.grpc/HandlerRegistry { // kotlinx.rpc.grpc/HandlerRegistry|null[0] + constructor () // kotlinx.rpc.grpc/HandlerRegistry.|(){}[0] +} + +abstract class kotlinx.rpc.grpc/ManagedChannelPlatform { // kotlinx.rpc.grpc/ManagedChannelPlatform|null[0] + constructor () // kotlinx.rpc.grpc/ManagedChannelPlatform.|(){}[0] +} + +final class kotlinx.rpc.grpc/GrpcClient : kotlinx.rpc/RpcClient { // kotlinx.rpc.grpc/GrpcClient|null[0] + final fun <#A1: kotlin/Any?> callServerStreaming(kotlinx.rpc/RpcCall): kotlinx.coroutines.flow/Flow<#A1> // kotlinx.rpc.grpc/GrpcClient.callServerStreaming|callServerStreaming(kotlinx.rpc.RpcCall){0§}[0] + final fun shutdown() // kotlinx.rpc.grpc/GrpcClient.shutdown|shutdown(){}[0] + final fun shutdownNow() // kotlinx.rpc.grpc/GrpcClient.shutdownNow|shutdownNow(){}[0] + final suspend fun <#A1: kotlin/Any?> call(kotlinx.rpc/RpcCall): #A1 // kotlinx.rpc.grpc/GrpcClient.call|call(kotlinx.rpc.RpcCall){0§}[0] + final suspend fun awaitTermination(kotlin.time/Duration) // kotlinx.rpc.grpc/GrpcClient.awaitTermination|awaitTermination(kotlin.time.Duration){}[0] +} + +final class kotlinx.rpc.grpc/GrpcServer : kotlinx.rpc.grpc/Server, kotlinx.rpc/RpcServer { // kotlinx.rpc.grpc/GrpcServer|null[0] + final val isShutdown // kotlinx.rpc.grpc/GrpcServer.isShutdown|{}isShutdown[0] + final fun (): kotlin/Boolean // kotlinx.rpc.grpc/GrpcServer.isShutdown.|(){}[0] + final val isTerminated // kotlinx.rpc.grpc/GrpcServer.isTerminated|{}isTerminated[0] + final fun (): kotlin/Boolean // kotlinx.rpc.grpc/GrpcServer.isTerminated.|(){}[0] + final val port // kotlinx.rpc.grpc/GrpcServer.port|{}port[0] + final fun (): kotlin/Int // kotlinx.rpc.grpc/GrpcServer.port.|(){}[0] + + final fun <#A1: kotlin/Any> deregisterService(kotlin.reflect/KClass<#A1>) // kotlinx.rpc.grpc/GrpcServer.deregisterService|deregisterService(kotlin.reflect.KClass<0:0>){0§}[0] + final fun <#A1: kotlin/Any> registerService(kotlin.reflect/KClass<#A1>, kotlin/Function0<#A1>) // kotlinx.rpc.grpc/GrpcServer.registerService|registerService(kotlin.reflect.KClass<0:0>;kotlin.Function0<0:0>){0§}[0] + final fun shutdown(): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc/GrpcServer.shutdown|shutdown(){}[0] + final fun shutdownNow(): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc/GrpcServer.shutdownNow|shutdownNow(){}[0] + final fun start(): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc/GrpcServer.start|start(){}[0] + final suspend fun awaitTermination(kotlin.time/Duration): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc/GrpcServer.awaitTermination|awaitTermination(kotlin.time.Duration){}[0] +} + +final class kotlinx.rpc.grpc/ServerServiceDefinition { // kotlinx.rpc.grpc/ServerServiceDefinition|null[0] + constructor () // kotlinx.rpc.grpc/ServerServiceDefinition.|(){}[0] +} + +final fun kotlinx.rpc.grpc/GrpcClient(kotlin/String, kotlin/Function1, kotlin/Unit> = ...): kotlinx.rpc.grpc/GrpcClient // kotlinx.rpc.grpc/GrpcClient|GrpcClient(kotlin.String;kotlin.Function1,kotlin.Unit>){}[0] +final fun kotlinx.rpc.grpc/GrpcClient(kotlin/String, kotlin/Int, kotlin/Function1, kotlin/Unit> = ...): kotlinx.rpc.grpc/GrpcClient // kotlinx.rpc.grpc/GrpcClient|GrpcClient(kotlin.String;kotlin.Int;kotlin.Function1,kotlin.Unit>){}[0] +final fun kotlinx.rpc.grpc/GrpcServer(kotlin/Int, kotlin/Function1, kotlin/Unit> = ..., kotlin/Function1 = ...): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc/GrpcServer|GrpcServer(kotlin.Int;kotlin.Function1,kotlin.Unit>;kotlin.Function1){}[0] +final fun kotlinx.rpc.grpc/StatusRuntimeException(kotlinx.rpc.grpc/Status): kotlinx.rpc.grpc/StatusRuntimeException // kotlinx.rpc.grpc/StatusRuntimeException|StatusRuntimeException(kotlinx.rpc.grpc.Status){}[0] diff --git a/grpc/grpc-ktor-server-test/api/grpc-ktor-server-test.api b/grpc/grpc-ktor-server-test/api/grpc-ktor-server-test.api new file mode 100644 index 000000000..e69de29bb diff --git a/grpc/grpc-ktor-server/api/grpc-ktor-server.api b/grpc/grpc-ktor-server/api/grpc-ktor-server.api new file mode 100644 index 000000000..6c4a53d5d --- /dev/null +++ b/grpc/grpc-ktor-server/api/grpc-ktor-server.api @@ -0,0 +1,11 @@ +public final class kotlinx/rpc/grpc/ktor/server/GrpcConfigKeys { + public static final field INSTANCE Lkotlinx/rpc/grpc/ktor/server/GrpcConfigKeys; + public static final field grpcHostPortPath Ljava/lang/String; +} + +public final class kotlinx/rpc/grpc/ktor/server/ServerKt { + public static final fun getGrpcServerKey ()Lio/ktor/util/AttributeKey; + public static final fun grpc (Lio/ktor/server/application/Application;ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlinx/rpc/grpc/GrpcServer; + public static synthetic fun grpc$default (Lio/ktor/server/application/Application;ILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/rpc/grpc/GrpcServer; +} + diff --git a/grpc/grpc-ktor-server/api/grpc-ktor-server.klib.api b/grpc/grpc-ktor-server/api/grpc-ktor-server.klib.api new file mode 100644 index 000000000..03c79bc15 --- /dev/null +++ b/grpc/grpc-ktor-server/api/grpc-ktor-server.klib.api @@ -0,0 +1,17 @@ +// Klib ABI Dump +// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, wasmJs, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +final object kotlinx.rpc.grpc.ktor.server/GrpcConfigKeys { // kotlinx.rpc.grpc.ktor.server/GrpcConfigKeys|null[0] + final const val grpcHostPortPath // kotlinx.rpc.grpc.ktor.server/GrpcConfigKeys.grpcHostPortPath|{}grpcHostPortPath[0] + final fun (): kotlin/String // kotlinx.rpc.grpc.ktor.server/GrpcConfigKeys.grpcHostPortPath.|(){}[0] +} + +final val kotlinx.rpc.grpc.ktor.server/GrpcServerKey // kotlinx.rpc.grpc.ktor.server/GrpcServerKey|{}GrpcServerKey[0] + final fun (): io.ktor.util/AttributeKey // kotlinx.rpc.grpc.ktor.server/GrpcServerKey.|(){}[0] + +final fun (io.ktor.server.application/Application).kotlinx.rpc.grpc.ktor.server/grpc(kotlin/Int = ..., kotlin/Function1, kotlin/Unit> = ..., kotlin/Function1): kotlinx.rpc.grpc/GrpcServer // kotlinx.rpc.grpc.ktor.server/grpc|grpc@io.ktor.server.application.Application(kotlin.Int;kotlin.Function1,kotlin.Unit>;kotlin.Function1){}[0]