Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions docs/pages/kotlinx-rpc/rpc.tree
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
<toc-element topic="features.topic"/>
<toc-element topic="transport.topic"/>
</toc-element>
<toc-element toc-title="gRPC">
<toc-element topic="grpc-configuration.topic"/>
<toc-element topic="grpc-services.topic"/>
<toc-element topic="grpc-client.topic"/>
<toc-element topic="grpc-server.topic"/>
</toc-element>
</toc-element>
<toc-element topic="strict-mode.topic"/>
<toc-element topic="versions.topic"/>
Expand Down
31 changes: 31 additions & 0 deletions docs/pages/kotlinx-rpc/topics/grpc-client.topic
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="Client" id="grpc-client">

<p>
Example of using a gRPC client:
</p>
<code-block lang="Kotlin">
val grpcClient = GrpcClient("localhost", 8080) {
usePlaintext()
}

val recognizer = grpcClient.withService&lt;ImageRecognizer&gt;()

val image = Image {
data = byteArrayOf(0, 1, 2, 3)
}
val result = recognizer.recognize(image)
println("Recognized category: ${result.category}")

grpcClient.cancel()
</code-block>
<list>
<li>
<code>usePlaintext()</code> - is a JVM binding to Java gRPC runtime. Other bindings are also present.
</li>
</list>
</topic>
130 changes: 130 additions & 0 deletions docs/pages/kotlinx-rpc/topics/grpc-configuration.topic
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="Configuration" id="grpc-configuration">

<tldr>
<p>
Artifacts for gRPC integration are published <a href="https://public.jetbrains.space/p/krpc/packages/maven/grpc">separately</a>
and updated frequently, independent of the main releases.
</p>
<p>
<a href="https://maven.pkg.jetbrains.space/public/p/krpc/grpc">
<img alt="Latest dev version"
src="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&amp;query=%2F%2Fmetadata%2Fversioning%2Flatest&amp;label=Latest%20dev%20version&amp;color=forest-green&amp;cacheSeconds=60"/>
</a>
</p>
</tldr>

<p>
<a href="https://grpc.io">gRPC</a> integration is available in an experimental state.
The artifacts are published separately in our <a
href="https://public.jetbrains.space/p/krpc/packages/maven/grpc">Space repository</a>.
</p>
<chapter title="Dependencies configuration" id="dependencies-configuration">
<p>Below is an example of a project setup.</p>
<code>settings.gradle.kts</code>:
<code-block lang="Kotlin">
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/krpc/grpc")
}
}
</code-block>
<p>
<code>build.gradle.kts</code>:
</p>
<code-block lang="Kotlin">
plugins {
kotlin("jvm") version "2.1.0"
kotlin("plugin.serialization") version "2.1.0"
id("org.jetbrains.kotlinx.rpc.plugin") version "&lt;version&gt;"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the version defined in the v.list file like this: %kotlinx-rpc-version%

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't define a dynamic version there. For gRPC it may be updated a lot of times, and I don't want to change the docs every time. Badge renders latest version dynamically.

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:&lt;version&gt;")
implementation("ch.qos.logback:logback-classic:1.5.16")
implementation("io.grpc:grpc-netty:1.69.0")
}
</code-block>
<p>Here <code>&lt;version&gt;</code> comes from the badge above.</p>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed if you replace <version> with %kotlinx-rpc-version% in the code block.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

<warning>
The setup has only been tested on <code>Kotlin/JVM</code> projects.
</warning>
</chapter>
<chapter title="Protoc setup" id="protoc-setup">
<p>
gRPC requires additional code generation from the <a href="https://github.com/google/protobuf-gradle-plugin">protoc</a>
compiler.
This can be setup up in the following way:
</p>
<code-block lang="Kotlin">
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:4.29.3"
}

plugins {
create("kotlinx-rpc") {
artifact = "org.jetbrains.kotlinx:kotlinx-rpc-protobuf-plugin:&lt;version&gt;: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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to explain what this configuration does after the code block.

all().all {
plugins {
create("kotlinx-rpc") {
option("debugOutput=protobuf-plugin.log")
option("messageMode=interface")
}
create("grpc")
create("grpckt")
}
}
}
}
</code-block>
<list>
<li>
Four source sets will be generated:
<list>
<li><code>java</code> - protobuf Java declarations</li>
<li><code>grpc</code> - gRPC Java declarations</li>
<li><code>grpckt</code> - gRPC Kotlin wrappers for Java</li>
<li><code>kotlinx-rpc</code> - pur wrappers for all of the above</li>
</list>
<p>
You won't need to use the first three directly, only the declarations from the <code>kotlinx-rpc</code>
source set are intended to be used.
</p>
Source sets are generated into <code>$BUILD_DIR/generated/source/proto/main</code> directory
unless specified otherwise.
</li>
<li>
<code>option("debugOutput=protobuf-plugin.log")</code> lets you specify the file
for the <code>protoc</code> plugin debug output.
</li>
<li>
<code>option("messageMode=interface")</code> is intended to be like so. Don't change it.
</li>
</list>
</chapter>
</topic>
29 changes: 29 additions & 0 deletions docs/pages/kotlinx-rpc/topics/grpc-server.topic
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="Server" id="grpc-server">

<p>
Example of using a gRPC server:
</p>
<code-block lang="Kotlin">
val grpcServer = GrpcServer(8080) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it would also be nice to explain what each line does, for example with bullet points after the code block.

registerService&lt;ImageRecognizer&gt; { ImageRecognizerImpl() }
}

grpcServer.start()
grpcServer.awaitTermination()
</code-block>
<list>
<li>
<code>GrpcServer</code> allows to register multiple services, like regular <code>RpcServer</code>.
However, <code>CoroutineContext</code> parameter is not needed and should not be used.
</li>
<li>
<code>GrpcServer</code> does <b>not</b> bind to Java gRPC <code>Server</code>,
but provides some functions to cover for that.
</li>
</list>
</topic>
104 changes: 104 additions & 0 deletions docs/pages/kotlinx-rpc/topics/grpc-services.topic
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="Services" id="grpc-services">

<p>
To define a service, create a new <code>.proto</code> file in the <code>proto</code> folder next to your source sets:
</p>
<code-block>
├── build.gradle.kts
├── settings.gradle.kts
└── src
├── main
│ ├── kotlin
│ │ ├── Client.kt
│ │ ├── ImageRecognizer.kt
│ │ └── Server.kt
│ └── resources
│ └── logback.xml
└── proto
└── image-recognizer.proto
</code-block>

<p>
Inside the <code>.proto</code> file define your service:
</p>
<code-block lang="protobuf">
syntax = "proto3";

message Image {
bytes data = 1;
}

message RecogniseResult {
int32 category = 1;
}

service ImageRecognizer {
rpc recognize(Image) returns (RecogniseResult);
}
</code-block>
<p>
This will generate the necessary code, including the most important interfaces:
<code>ImageRecognizer</code>, <code>Image</code>, <code>RecogniseResult</code>:
</p>
<code-block lang="Kotlin">
@Grpc
interface ImageRecognizer {
suspend fun recognize(image: Image): RecogniseResult
}

interface RecogniseResult {
val category: Int

companion object
}

interface Image {
val data: ByteArray

companion object
}
</code-block>
<p>
You can implement the <code>ImageRecognizer</code>:
</p>
<code-block lang="Kotlin">
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
}
}
</code-block>
<p>
Here you can also see the usage of the <code>RecogniseResult</code> interface.
To create an instance, use its <code>.invoke()</code> extension function:
</p>
<code-block lang="Kotlin">
RecogniseResult {
category = 0
}
</code-block>

<chapter title="Limitations" id="limitations">
<p>Current known limitations:</p>
<list>
<li>No streaming</li>
<li>Only primitive types in messages</li>
<li>Mandatory java and kotlin protoc generation in addition to our codegen</li>
<li>Kotlin/JVM project only</li>
</list>
<p>
If you encounter other unexpected limitations or bugs,
please <a href="https://github.com/Kotlin/kotlinx-rpc/issues/new?template=bug_report.md">report</a> them
</p>
</chapter>
</topic>
Loading