diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8a3e63011..e933ca248 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,7 +14,7 @@ permissions: env: INSTANCE: 'kotlinx-rpc/rpc' ARTIFACT: 'webHelpRPC2-all.zip' - DOCKER_VERSION: '241.15989' + DOCKER_VERSION: '243.22562' ALGOLIA_ARTIFACT: 'algolia-indexes-RPC.zip' ALGOLIA_APP_NAME: 'MMA5Z3JT91' ALGOLIA_INDEX_NAME: 'prod_kotlin_rpc' diff --git a/README.md b/README.md index ad7a96be6..eafc64d71 100644 --- a/README.md +++ b/README.md @@ -156,9 +156,18 @@ When using kRPC you only need to provide a transport or choose from the official Besides that, one can even provide their own protocol or integration with one to use with services and `kotlinx.rpc` API with it. Though possible, it is much more complicated way to use the library and generally not needed. -`kotlinx.rpc` aims to provide most common protocols integrations as well as the in-house one called kRPC. -Integrations in progress: -- Integration with [gRPC](https://grpc.io/) (in prototype) +`kotlinx.rpc` aims to provide support for the most common protocol integrations, as well as the in-house protocol called kRPC. + +## gRPC integration +The library provides experimental support for the [gRPC](https://grop.io) protocol. +The artifacts are published separately in our [Space repository](https://public.jetbrains.space/p/krpc/packages/maven/grpc). +Current latest version: + +![Dynamic XML Badge](https://img.shields.io/badge/dynamic/xml?url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fpublic%2Fp%2Fkrpc%2Fgrpc%2Forg%2Fjetbrains%2Fkotlinx%2Fkotlinx-rpc-core%2Fmaven-metadata.xml&query=%2F%2Fmetadata%2Fversioning%2Flatest&label=Latest%20dev%20version&color=forest-green&cacheSeconds=60) + +For more information on gRPC usage, +see the [official documentation](https://kotlin.github.io/kotlinx-rpc/grpc-configuration.html). +For a working example, see the [sample gRPC project](/samples/grpc-app). ## Kotlin compatibility We support all stable Kotlin versions starting from 2.0.0: diff --git a/docs/pages/kotlinx-rpc/rpc.tree b/docs/pages/kotlinx-rpc/rpc.tree index 0d5f9bc64..e671d020f 100644 --- a/docs/pages/kotlinx-rpc/rpc.tree +++ b/docs/pages/kotlinx-rpc/rpc.tree @@ -25,6 +25,12 @@ + + + + + + diff --git a/docs/pages/kotlinx-rpc/topics/grpc-client.topic b/docs/pages/kotlinx-rpc/topics/grpc-client.topic new file mode 100644 index 000000000..58cdc6676 --- /dev/null +++ b/docs/pages/kotlinx-rpc/topics/grpc-client.topic @@ -0,0 +1,31 @@ + + + + +

+ Example of using a gRPC client: +

+ + val grpcClient = GrpcClient("localhost", 8080) { + usePlaintext() + } + + val recognizer = grpcClient.withService<ImageRecognizer>() + + val image = Image { + data = byteArrayOf(0, 1, 2, 3) + } + val result = recognizer.recognize(image) + println("Recognized category: ${result.category}") + + grpcClient.cancel() + + +
  • + usePlaintext() - is a JVM binding to Java gRPC runtime. Other bindings are also present. +
  • +
    +
    \ No newline at end of file diff --git a/docs/pages/kotlinx-rpc/topics/grpc-configuration.topic b/docs/pages/kotlinx-rpc/topics/grpc-configuration.topic new file mode 100644 index 000000000..5ac509320 --- /dev/null +++ b/docs/pages/kotlinx-rpc/topics/grpc-configuration.topic @@ -0,0 +1,130 @@ + + + + + +

    + Artifacts for gRPC integration are published separately + and updated frequently, independent of the main releases. +

    +

    + + Latest dev version + +

    +
    + +

    + gRPC integration is available in an experimental state. + The artifacts are published separately in our Space repository. +

    + +

    Below is an example of a project setup.

    + settings.gradle.kts: + + pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/krpc/grpc") + } + } + +

    + build.gradle.kts: +

    + + plugins { + kotlin("jvm") version "2.1.0" + kotlin("plugin.serialization") version "2.1.0" + id("org.jetbrains.kotlinx.rpc.plugin") version "<version>" + id("com.google.protobuf") version "0.9.4" + } + + repositories { + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/krpc/grpc") + } + + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-rpc-grpc-core:<version>") + implementation("ch.qos.logback:logback-classic:1.5.16") + implementation("io.grpc:grpc-netty:1.69.0") + } + +

    Here <version> comes from the badge above.

    + + The setup has only been tested on Kotlin/JVM projects. + +
    + +

    + gRPC requires additional code generation from the protoc + compiler. + This can be setup up in the following way: +

    + + protobuf { + protoc { + artifact = "com.google.protobuf:protoc:4.29.3" + } + + plugins { + create("kotlinx-rpc") { + artifact = "org.jetbrains.kotlinx:kotlinx-rpc-protobuf-plugin:<version>:all@jar" + } + + create("grpc") { + artifact = "io.grpc:protoc-gen-grpc-java:1.69.0" + } + + create("grpckt") { + artifact = "io.grpc:protoc-gen-grpc-kotlin:1.4.1:jdk8@jar" + } + } + + generateProtoTasks { + all().all { + plugins { + create("kotlinx-rpc") { + option("debugOutput=protobuf-plugin.log") + option("messageMode=interface") + } + create("grpc") + create("grpckt") + } + } + } + } + + +
  • + Four source sets will be generated: + +
  • java - protobuf Java declarations
  • +
  • grpc - gRPC Java declarations
  • +
  • grpckt - gRPC Kotlin wrappers for Java
  • +
  • kotlinx-rpc - pur wrappers for all of the above
  • +
    +

    + You won't need to use the first three directly, only the declarations from the kotlinx-rpc + source set are intended to be used. +

    + Source sets are generated into $BUILD_DIR/generated/source/proto/main directory + unless specified otherwise. + +
  • + option("debugOutput=protobuf-plugin.log") lets you specify the file + for the protoc plugin debug output. +
  • +
  • + option("messageMode=interface") is intended to be like so. Don't change it. +
  • + +
    +
    diff --git a/docs/pages/kotlinx-rpc/topics/grpc-server.topic b/docs/pages/kotlinx-rpc/topics/grpc-server.topic new file mode 100644 index 000000000..25b8916b3 --- /dev/null +++ b/docs/pages/kotlinx-rpc/topics/grpc-server.topic @@ -0,0 +1,29 @@ + + + + +

    + Example of using a gRPC server: +

    + + val grpcServer = GrpcServer(8080) { + registerService<ImageRecognizer> { ImageRecognizerImpl() } + } + + grpcServer.start() + grpcServer.awaitTermination() + + +
  • + GrpcServer allows to register multiple services, like regular RpcServer. + However, CoroutineContext parameter is not needed and should not be used. +
  • +
  • + GrpcServer does not bind to Java gRPC Server, + but provides some functions to cover for that. +
  • +
    +
    diff --git a/docs/pages/kotlinx-rpc/topics/grpc-services.topic b/docs/pages/kotlinx-rpc/topics/grpc-services.topic new file mode 100644 index 000000000..469df5338 --- /dev/null +++ b/docs/pages/kotlinx-rpc/topics/grpc-services.topic @@ -0,0 +1,104 @@ + + + + +

    + To define a service, create a new .proto file in the proto folder next to your source sets: +

    + + ├── build.gradle.kts + ├── settings.gradle.kts + └── src + ├── main + │ ├── kotlin + │ │ ├── Client.kt + │ │ ├── ImageRecognizer.kt + │ │ └── Server.kt + │ └── resources + │ └── logback.xml + └── proto + └── image-recognizer.proto + + +

    + Inside the .proto file define your service: +

    + + syntax = "proto3"; + + message Image { + bytes data = 1; + } + + message RecogniseResult { + int32 category = 1; + } + + service ImageRecognizer { + rpc recognize(Image) returns (RecogniseResult); + } + +

    + This will generate the necessary code, including the most important interfaces: + ImageRecognizer, Image, RecogniseResult: +

    + + @Grpc + interface ImageRecognizer { + suspend fun recognize(image: Image): RecogniseResult + } + + interface RecogniseResult { + val category: Int + + companion object + } + + interface Image { + val data: ByteArray + + companion object + } + +

    + You can implement the ImageRecognizer: +

    + + class ImageRecognizerImpl : ImageRecognizer { + override suspend fun recognize(image: Image): RecogniseResult { + val byte = image.data[0].toInt() + delay(100) // heavy processing + val result = RecogniseResult { + category = if (byte == 0) 0 else 1 + } + return result + } + } + +

    + Here you can also see the usage of the RecogniseResult interface. + To create an instance, use its .invoke() extension function: +

    + + RecogniseResult { + category = 0 + } + + + +

    Current known limitations:

    + +
  • No streaming
  • +
  • Only primitive types in messages
  • +
  • Mandatory java and kotlin protoc generation in addition to our codegen
  • +
  • Kotlin/JVM project only
  • +
    +

    + If you encounter other unexpected limitations or bugs, + please report them +

    +
    +