Skip to content

Commit 20019b1

Browse files
committed
grpc: Update kmp example
1 parent f750aa2 commit 20019b1

File tree

8 files changed

+81
-33
lines changed

8 files changed

+81
-33
lines changed

grpc/grpc-client/src/commonMain/kotlin/kotlinx/rpc/grpc/client/GrpcClient.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ private fun GrpcClient(
191191
* Configuration class for a gRPC client, providing customization options
192192
* for client behavior, including interceptors, credentials, codec resolution,
193193
* and authority overrides.
194+
*
195+
* @see credentials
196+
* @see overrideAuthority
197+
* @see intercept
194198
*/
195199
public class GrpcClientConfiguration internal constructor() {
196200
internal val interceptors: MutableList<ClientInterceptor> = mutableListOf()
@@ -226,6 +230,9 @@ public class GrpcClientConfiguration internal constructor() {
226230
* credentials = plaintext() // for testing purposes only!
227231
* }
228232
* ```
233+
*
234+
* @see tls
235+
* @see plaintext
229236
*/
230237
public var credentials: ClientCredentials? = null
231238

samples/grpc-kmp-app/composeApp/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ kotlin {
3232
implementation(libs.androidx.lifecycle.runtimeCompose)
3333
implementation(libs.kotlinx.datetime)
3434
implementation(libs.kotlinx.rpc.protobuf.core)
35-
implementation(libs.kotlinx.rpc.grpc.core)
35+
implementation(libs.kotlinx.rpc.grpc.client)
3636
implementation(libs.grpc.netty)
3737
implementation(projects.shared)
3838
}

samples/grpc-kmp-app/composeApp/src/commonMain/kotlin/kotlinx/rpc/sample/App.kt

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,16 @@ import androidx.compose.ui.Alignment
3333
import androidx.compose.ui.Modifier
3434
import androidx.compose.ui.graphics.Color
3535
import androidx.compose.ui.unit.dp
36+
import kotlinx.coroutines.CancellationException
37+
import kotlinx.coroutines.delay
38+
import kotlinx.coroutines.flow.catch
39+
import kotlinx.coroutines.flow.retryWhen
3640
import kotlinx.coroutines.launch
3741
import kotlinx.datetime.TimeZone
3842
import kotlinx.datetime.toLocalDateTime
39-
import kotlinx.rpc.grpc.GrpcClient
43+
import kotlinx.rpc.grpc.StatusException
44+
import kotlinx.rpc.grpc.client.GrpcClient
45+
import kotlinx.rpc.grpc.statusCode
4046
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
4147
import kotlinx.rpc.sample.messages.ChatEntry
4248
import kotlinx.rpc.sample.messages.MessageService
@@ -45,7 +51,9 @@ import kotlinx.rpc.sample.messages.SendMessageRequest
4551
import kotlinx.rpc.sample.messages.invoke
4652
import kotlinx.rpc.withService
4753
import org.jetbrains.compose.ui.tooling.preview.Preview
54+
import kotlin.random.Random
4855
import kotlin.time.Clock
56+
import kotlin.time.Duration.Companion.seconds
4957
import kotlin.time.ExperimentalTime
5058
import kotlin.time.Instant
5159

@@ -56,7 +64,7 @@ fun App() {
5664

5765
val grpcClient = remember {
5866
GrpcClient("localhost", 8080) {
59-
usePlaintext()
67+
credentials = plaintext()
6068
}
6169
}
6270

@@ -72,34 +80,63 @@ fun App() {
7280
private fun ChatScreen(service: MessageService) {
7381
val scope = rememberCoroutineScope()
7482

75-
var me by remember { mutableStateOf("me") }
83+
var me by remember { mutableStateOf("user-${Random.nextInt(until = 999)}" ) }
7684
var input by remember { mutableStateOf("") }
7785
val messages = remember { mutableStateListOf<ChatEntry>() }
86+
var error by remember { mutableStateOf<String?>(null) }
7887

7988
fun sendMessage() {
8089
scope.launch {
81-
val result = service.SendMessage(
82-
SendMessageRequest{
83-
user = me
84-
text = input
85-
}
86-
)
87-
if (result.success) {
88-
messages += ChatEntry {
89-
user = me
90-
text = input
91-
tsMillis = Clock.System.now().toEpochMilliseconds()
90+
try {
91+
val result = service.SendMessage(
92+
SendMessageRequest {
93+
user = me
94+
text = input
95+
}
96+
)
97+
if (result.success) {
98+
messages += ChatEntry {
99+
user = me
100+
text = input
101+
tsMillis = Clock.System.now().toEpochMilliseconds()
102+
}
103+
input = ""
104+
error = null
105+
} else {
106+
error = "Message not accepted by server."
92107
}
93-
input = ""
108+
} catch (e: CancellationException) {
109+
throw e
110+
} catch (e: StatusException) {
111+
error = e.getStatus().getDescription()?.let { "${e.getStatus().statusCode}: $it" } ?: "gRPC error: ${e.getStatus().statusCode}"
112+
} catch (e: Throwable) {
113+
error = e.message ?: "Unknown error while sending."
94114
}
95115
}
96116
}
97117

98118
LaunchedEffect(me) {
99119
messages.clear()
120+
error = null
100121
val req = ReceiveMessagesRequest { user = me }
101-
service.ReceiveMessages(req).collect { msg ->
102-
messages += msg
122+
try {
123+
service.ReceiveMessages(req)
124+
.retryWhen { cause, attempt ->
125+
if (cause is CancellationException) false
126+
else {
127+
error = (cause as? StatusException)?.getStatus()?.getDescription()?.let { "${cause.getStatus().statusCode}: $it" }
128+
?: cause.message ?: "Error receiving messages."
129+
delay(2.seconds)
130+
true
131+
}
132+
}
133+
.collect { msg -> messages += msg; error = null }
134+
} catch (e: CancellationException) {
135+
throw e
136+
} catch (e: StatusException) {
137+
error = e.getStatus().getDescription() ?: "gRPC error: ${e.getStatus().statusCode}"
138+
} catch (e: Throwable) {
139+
error = e.message ?: "Unknown error while receiving."
103140
}
104141
}
105142

@@ -108,6 +145,18 @@ private fun ChatScreen(service: MessageService) {
108145
.windowInsetsPadding(WindowInsets.safeDrawing)
109146
.padding(16.dp)
110147
) {
148+
149+
if (error != null) {
150+
Text(
151+
error!!,
152+
color = MaterialTheme.colorScheme.error,
153+
modifier = Modifier
154+
.fillMaxWidth()
155+
.background(MaterialTheme.colorScheme.errorContainer)
156+
.padding(8.dp)
157+
)
158+
}
159+
111160
OutlinedTextField(
112161
value = me,
113162
onValueChange = { me = it },

samples/grpc-kmp-app/gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ ktor-serverCore = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor
2424
ktor-serverNetty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" }
2525
ktor-serverTestHost = { module = "io.ktor:ktor-server-test-host-jvm", version.ref = "ktor" }
2626
kotlinx-rpc-grpc-core = { module = "org.jetbrains.kotlinx:kotlinx-rpc-grpc-core", version.ref = "kotlinx-rpc" }
27+
kotlinx-rpc-grpc-client = { module = "org.jetbrains.kotlinx:kotlinx-rpc-grpc-client", version.ref = "kotlinx-rpc" }
28+
kotlinx-rpc-grpc-server = { module = "org.jetbrains.kotlinx:kotlinx-rpc-grpc-server", version.ref = "kotlinx-rpc" }
2729
kotlinx-rpc-protobuf-core = { module = "org.jetbrains.kotlinx:kotlinx-rpc-protobuf-core", version.ref = "kotlinx-rpc" }
2830
grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc" }
2931
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datatime" }

samples/grpc-kmp-app/server/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ dependencies {
1616
implementation(projects.shared)
1717
implementation(libs.logback)
1818
implementation(libs.kotlinx.rpc.protobuf.core)
19-
implementation(libs.kotlinx.rpc.grpc.core)
19+
implementation(libs.kotlinx.rpc.grpc.server)
2020
implementation(libs.grpc.netty)
2121
}

samples/grpc-kmp-app/server/src/main/kotlin/kotlinx/rpc/sample/Application.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package kotlinx.rpc.sample
22

33
import kotlinx.coroutines.runBlocking
4-
import kotlinx.rpc.grpc.GrpcServer
4+
import kotlinx.rpc.grpc.server.GrpcServer
55
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
66
import kotlinx.rpc.registerService
77
import kotlinx.rpc.sample.messages.MessageService
88

99
@OptIn(ExperimentalRpcApi::class)
1010
fun main(): Unit = runBlocking {
1111
val grpcServer = GrpcServer(8080) {
12-
registerService<MessageService> { MessageServiceImpl() }
12+
services {
13+
registerService<MessageService> { MessageServiceImpl() }
14+
}
1315
}
1416

1517
grpcServer.start()

samples/grpc-kmp-app/shared/src/commonMain/kotlin/kotlinx/rpc/sample/Constants.kt

Lines changed: 0 additions & 3 deletions
This file was deleted.

samples/grpc-kmp-app/shared/src/commonMain/kotlin/kotlinx/rpc/sample/Greeting.kt

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)