11# rsocket-kotlin
22
3- RSocket Kotlin multi-platform implementation based on [ kotlinx.coroutines] ( https://github.com/Kotlin/kotlinx.coroutines ) .
3+ RSocket Kotlin multi-platform implementation based on
4+ [ kotlinx.coroutines] ( https://github.com/Kotlin/kotlinx.coroutines ) and [ ktor-io] ( https://github.com/ktorio/ktor ) .
45
5- RSocket is a binary protocol for use on byte stream transports such as TCP, WebSockets and Aeron.
6+ RSocket is a binary application protocol providing Reactive Streams semantics for use on byte stream transports such as
7+ TCP, WebSockets, QUIC and Aeron.
68
79It enables the following symmetric interaction models via async message passing over a single connection:
810
9- - request/response (stream of 1 )
10- - request/stream (finite stream of many )
11- - fire-and-forget (no response)
12- - event subscription (infinite stream of many )
11+ * [ Fire-and-Forget ] ( https://rsocket.io/about/motivations#fire-and-forget )
12+ * [ Request-Response ] ( https://rsocket.io/about/motivations#requestresponse-single-response )
13+ * [ Request-Stream ] ( https://rsocket.io/about/motivations#requeststream-multi- response-finite )
14+ * [ Request-Channel ] ( https://rsocket.io/about/motivations#channel )
1315
1416Learn more at http://rsocket.io
1517
1618## Supported platforms and transports :
1719
18- Transports are implemented based on [ ktor] ( https://github.com/ktorio/ktor ) to ensure Kotlin multiplatform. So it depends on ` ktor ` engines
19- for available transports and platforms (JVM, JS, Native):
20+ Local (in memory) transport is supported on all targets.
21+ Most of other transports are implemented using [ ktor] ( https://github.com/ktorio/ktor ) to ensure Kotlin multiplatform.
22+ So it depends on ` ktor ` client/server engines for available transports and platforms.
2023
21- * JVM - TCP and WebSocket for both client and server
22- * JS - WebSocket client only
23- * Native - TCP (linux x64, macos, ios, watchos, tvos) for both client and server
24+ ### Client transports:
2425
25- ## Interactions
26+ | | TCP | WebSocket |
27+ | -----------------------------| -----------------------------------------| ------------|
28+ | JVM | ✅ via ktor | ✅ via ktor |
29+ | JS | ✅ via nodeJS (not supported in browser) | ✅ via ktor |
30+ | Native<br />(except windows) | ✅ via ktor | ✅ via ktor |
2631
27- RSocket interface contains 5 methods :
32+ ### Server transports :
2833
29- * Fire and Forget:
30-
31- ` suspend fun fireAndForget(payload: Payload) `
32- * Request-Response:
33-
34- ` suspend requestResponse(payload: Payload): Payload `
35- * Request-Stream:
36-
37- ` fun requestStream(payload: Payload): Flow<Payload> `
38- * Request-Channel:
39-
40- ` fun requestChannel(initPayload: Payload, payloads: Flow<Payload>): Flow<Payload> `
41- * Metadata-Push:
42-
43- ` suspend fun metadataPush(metadata: ByteReadPacket) `
34+ | | TCP | WebSocket |
35+ | -----------------------------| -----------------------------------------| ------------|
36+ | JVM | ✅ via ktor | ✅ via ktor |
37+ | JS | ✅ via nodeJS (not supported in browser) | ❌ |
38+ | Native<br />(except windows) | ✅ via ktor | ✅ via ktor |
4439
4540## Using in your projects
4641
47- Make sure, that you use Kotlin 1.6.10
42+ rsocket-kotlin is available on [ Maven Central ] ( https://mvnrepository.com/artifact/io.rsocket.kotlin )
4843
49- ### Gradle :
44+ Make sure, that you use Kotlin 1.6.20+, ktor 2.0.0+ and have ` mavenCentral() ` in the list of repositories :
5045
5146``` kotlin
5247repositories {
5348 mavenCentral()
5449}
55- dependencies {
56- implementation(" io.rsocket.kotlin:rsocket-core:0.14.3" )
57-
58- // TCP ktor transport
59- implementation(" io.rsocket.kotlin:rsocket-transport-ktor:0.14.3" )
50+ ```
6051
61- // WS ktor transport client plugin
62- implementation(" io.rsocket.kotlin:rsocket-transport-ktor-client:0.14.3" )
52+ ### Ktor plugins
6353
64- // WS ktor transport server plugin
65- implementation(" io.rsocket.kotlin:rsocket-transport-ktor-server:0.14.3" )
66- }
67- ```
54+ rsocket-kotlin provides [ client] ( https://ktor.io/docs/http-client-plugins.html )
55+ and [ server] ( https://ktor.io/docs/plugins.html ) plugins for [ ktor] ( https://ktor.io )
6856
69- For WS ktor transport, available client or server engine should be added :
57+ Dependencies :
7058
7159``` kotlin
7260dependencies {
73- // client engines for WS transport
74- implementation(" io.ktor:ktor-client-js:1.6.7" ) // js
75- implementation(" io.ktor:ktor-client-cio:1.6.7" ) // jvm
76- implementation(" io.ktor:ktor-client-okhttp:1.6.7" ) // jvm
77-
78- // server engines for WS transport (jvm only)
79- implementation(" io.ktor:ktor-server-cio:1.6.7" )
80- implementation(" io.ktor:ktor-server-netty:1.6.7" )
81- implementation(" io.ktor:ktor-server-jetty:1.6.7" )
82- implementation(" io.ktor:ktor-server-tomcat:1.6.7" )
61+ // for client
62+ implementation(" io.rsocket.kotlin:rsocket-ktor-client:0.15.0" )
63+
64+ // for server
65+ implementation(" io.rsocket.kotlin:rsocket-ktor-server:0.15.0" )
8366}
8467```
8568
86- ## Usage
87-
88- ### Client WebSocket with CIO ktor engine
69+ Example of client plugin usage:
8970
9071``` kotlin
9172// create ktor client
92- val client = HttpClient ( CIO ) {
93- install(WebSockets )
73+ val client = HttpClient {
74+ install(WebSockets ) // rsocket requires websockets plugin installed
9475 install(RSocketSupport ) {
95- connector = RSocketConnector {
96- // configure rSocket connector (all values have defaults)
76+ // configure rSocket connector (all values have defaults)
77+ connector {
78+ maxFragmentSize = 1024
79+
9780 connectionConfig {
9881 keepAlive = KeepAlive (
9982 interval = 30 .seconds,
10083 maxLifetime = 2 .minutes
10184 )
10285
10386 // payload for setup frame
104- setupPayload { buildPayload { data(" hello world" ) } }
87+ setupPayload {
88+ buildPayload {
89+ data(""" { "data": "setup" }""" )
90+ }
91+ }
10592
10693 // mime types
10794 payloadMimeType = PayloadMimeType (
108- data = " application/json " ,
109- metadata = " application/json "
95+ data = WellKnownMimeType . ApplicationJson ,
96+ metadata = WellKnownMimeType . MessageRSocketCompositeMetadata
11097 )
11198 }
11299
@@ -124,22 +111,30 @@ val client = HttpClient(CIO) {
124111val rSocket: RSocket = client.rSocket(" wss://demo.rsocket.io/rsocket" )
125112
126113// request stream
127- val stream: Flow <Payload > = rSocket.requestStream(Payload .Empty )
114+ val stream: Flow <Payload > = rSocket.requestStream(
115+ buildPayload {
116+ data(""" { "data": "hello world" }""" )
117+ }
118+ )
128119
129120// take 5 values and print response
130121stream.take(5 ).collect { payload: Payload ->
131122 println (payload.data.readText())
132123}
133124```
134125
135- ### Server WebSocket with CIO ktor engine
126+ Example of server plugin usage:
136127
137128``` kotlin
138129// create ktor server
139130embeddedServer(CIO ) {
131+ install(WebSockets ) // rsocket requires websockets plugin installed
140132 install(RSocketSupport ) {
141133 // configure rSocket server (all values have defaults)
142- server = RSocketServer {
134+
135+ server {
136+ maxFragmentSize = 1024
137+
143138 // install interceptors
144139 interceptors {
145140 forConnection(::SomeConnectionInterceptor )
@@ -148,23 +143,29 @@ embeddedServer(CIO) {
148143 }
149144 // configure routing
150145 routing {
151- // configure route `url:port /rsocket`
146+ // configure route `/rsocket`
152147 rSocket(" rsocket" ) {
148+ println (config.setupPayload.data.readText()) // print setup payload data
149+
153150 RSocketRequestHandler {
154151 // handler for request/response
155152 requestResponse { request: Payload ->
156- // ... some work here
153+ println (request.data.readText()) // print request payload data
157154 delay(500 ) // work emulation
158155 buildPayload {
159- data(" data" )
160- metadata(" metadata" )
156+ data(""" { "data": "Server response" }""" )
161157 }
162158 }
163159 // handler for request/stream
164160 requestStream { request: Payload ->
161+ println (request.data.readText()) // print request payload data
165162 flow {
166- repeat(1000 ) { i ->
167- emit(buildPayload { data(" data: $i " ) })
163+ repeat(10 ) { i ->
164+ emit(
165+ buildPayload {
166+ data(""" { "data": "Server stream response: $i " }""" )
167+ }
168+ )
168169 }
169170 }
170171 }
@@ -174,10 +175,72 @@ embeddedServer(CIO) {
174175}.start(true )
175176```
176177
178+ ### Standalone transports
179+
180+ rsocket-kotlin also provides standalone transports which can be used to establish RSocket connection:
181+
182+ Dependencies:
183+
184+ ``` kotlin
185+ dependencies {
186+ implementation(" io.rsocket.kotlin:rsocket-core:0.15.0" )
187+
188+ // TCP ktor client/server transport
189+ implementation(" io.rsocket.kotlin:rsocket-transport-ktor-tcp:0.15.0" )
190+
191+ // WS ktor client transport
192+ implementation(" io.rsocket.kotlin:rsocket-transport-ktor-websocket-client:0.15.0" )
193+
194+ // WS ktor server transport
195+ implementation(" io.rsocket.kotlin:rsocket-transport-ktor-websocket-server:0.15.0" )
196+
197+ // TCP nodeJS client/server transport
198+ implementation(" io.rsocket.kotlin:rsocket-transport-nodejs-tcp:0.15.0" )
199+ }
200+ ```
201+
202+ Example of usage standalone client transport:
203+
204+ ``` kotlin
205+
206+ val transport = TcpClientTransport (" 0.0.0.0" , 8080 )
207+ val connector = RSocketConnector {
208+ // configuration goes here
209+ }
210+ val rsocket: RSocket = connector.connect(transport)
211+ // use rsocket to do request
212+ val response = rsocket.requestResponse(buildPayload { data(""" { "data": "hello world" }""" ) })
213+ println (response.data.readText())
214+ ```
215+
216+ Example of usage standalone server transport:
217+
218+ ``` kotlin
219+
220+ val transport = TcpServerTransport (" 0.0.0.0" , 8080 )
221+ val connector = RSocketServer {
222+ // configuration goes here
223+ }
224+ val server: TcpServer = server.bind(transport) {
225+ RSocketRequestHandler {
226+ // handler for request/response
227+ requestResponse { request: Payload ->
228+ println (request.data.readText()) // print request payload data
229+ delay(500 ) // work emulation
230+ buildPayload {
231+ data(""" { "data": "Server response" }""" )
232+ }
233+ }
234+ }
235+ }
236+ server.handlerJob.join() // wait for server to finish
237+ ```
238+
177239### More samples:
178240
179- - [ multiplatform-chat] ( samples/chat ) - chat implementation with JVM server and JS/JVM client with shared classes and
180- serializing data using [ kotlinx.serialization] ( https://github.com/Kotlin/kotlinx.serialization )
241+ - [ multiplatform-chat] ( samples/chat ) - chat implementation with JVM/JS/Native server and JVM/JS/Native client with
242+ shared classes and shared data serialization
243+ using [ kotlinx.serialization] ( https://github.com/Kotlin/kotlinx.serialization )
181244
182245## Reactive Streams Semantics
183246
@@ -187,9 +250,10 @@ From [RSocket protocol](https://github.com/rsocket/rsocket/blob/master/Protocol.
187250 This is a credit-based model where the Requester grants the Responder credit for the number of PAYLOADs it can send.
188251 It is sometimes referred to as "request-n" or "request(n)".
189252
190- ` kotlinx.coroutines ` doesn't truly support ` request(n) ` semantic, but it has flexible ` CoroutineContext `
191- which can be used to achieve something similar. ` rsocket-kotlin ` contains ` RequestStrategy ` coroutine context element, which defines,
192- strategy for sending of ` requestN ` frames.
253+ ` kotlinx.coroutines ` doesn't truly support ` request(n) ` semantic,
254+ but it has flexible ` CoroutineContext ` which can be used to achieve something similar.
255+ ` rsocket-kotlin ` contains ` RequestStrategy ` coroutine context element, which defines,
256+ strategy for sending of ` requestN ` frames.
193257
194258Example:
195259
@@ -215,7 +279,7 @@ For bugs, questions and discussions please use the [Github Issues](https://githu
215279
216280## LICENSE
217281
218- Copyright 2015-2020 the original author or authors.
282+ Copyright 2015-2022 the original author or authors.
219283
220284Licensed under the Apache License, Version 2.0 (the "License");
221285you may not use this file except in compliance with the License.
0 commit comments