Skip to content

Commit c19cdd6

Browse files
committed
grpc-native: Initial client setup
Signed-off-by: Johannes Zottele <[email protected]>
1 parent ebd3f90 commit c19cdd6

File tree

16 files changed

+575
-77
lines changed

16 files changed

+575
-77
lines changed

cinterop-c/BUILD.bazel

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
load("@rules_cc//cc:defs.bzl", "cc_library")
22

3-
cc_binary(
4-
name = "testdemo",
5-
srcs = ["src/main.cpp"],
6-
deps = [
7-
":protowire",
8-
],
9-
)
10-
113
cc_static_library(
124
name = "grpcpp_c_static",
135
deps = [
@@ -24,6 +16,7 @@ cc_library(
2416
visibility = ["//visibility:public"],
2517
deps = [
2618
# TODO: Reduce the dependencies and only use required once. KRPC-185
19+
"@com_github_grpc_grpc//:grpc",
2720
"@com_github_grpc_grpc//:channelz",
2821
"@com_github_grpc_grpc//:generic_stub",
2922
"@com_github_grpc_grpc//:grpc++",

cinterop-c/include/grpcpp_c.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define GRPCPP_C_H
77

88
#include <stdint.h>
9+
#include <grpc/grpc.h>
910
#include <grpc/slice.h>
1011
#include <grpc/byte_buffer.h>
1112

@@ -38,6 +39,14 @@ typedef enum StatusCode {
3839
GRPC_C_STATUS_DO_NOT_USE = -1
3940
} grpc_status_code_t;
4041

42+
43+
typedef struct {
44+
grpc_completion_queue_functor functor;
45+
void *user_data;
46+
} grpc_cb_tag;
47+
48+
49+
4150
grpc_client_t *grpc_client_create_insecure(const char *target);
4251
void grpc_client_delete(const grpc_client_t *client);
4352

@@ -59,6 +68,12 @@ uint32_t pb_decode_greeter_sayhello_response(grpc_slice response);
5968

6069
grpc_status_code_t grpc_byte_buffer_dump_to_single_slice(grpc_byte_buffer *byte_buffer, grpc_slice *slice);
6170

71+
72+
/////// CHANNEL ///////
73+
74+
typedef struct grpc_channel grpc_channel_t;
75+
typedef struct grpc_channel_credentials grpc_channel_credentials_t;
76+
6277
#ifdef __cplusplus
6378
}
6479
#endif

cinterop-c/src/grpcpp_c.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ struct grpc_context {
2727
std::unique_ptr<grpc::ClientContext> context;
2828
};
2929

30+
// struct grpc_channel {
31+
// std::shared_ptr<grpc::Channel> channel;
32+
// };
33+
3034
extern "C" {
3135

3236
grpc_client_t *grpc_client_create_insecure(const char *target) {
@@ -196,6 +200,11 @@ extern "C" {
196200
return GRPC_C_STATUS_OK;
197201
}
198202

203+
204+
//// CHANNEL ////
205+
206+
207+
199208
}
200209

201210

grpc/grpc-core/src/nativeInterop/cinterop/libgrpcpp_c.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
headers = grpcpp_c.h
2-
headerFilter= grpcpp_c.h grpc/slice.h grpc/byte_buffer.h
1+
headers = grpcpp_c.h grpc/grpc.h grpc/credentials.h
2+
headerFilter= grpcpp_c.h grpc/slice.h grpc/byte_buffer.h grpc/grpc.h grpc/impl/grpc_types.h grpc/credentials.h grpc/support/time.h
33

44
noStringConversion = grpc_slice_from_copied_buffer my_grpc_slice_from_copied_buffer
55

grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/ManagedChannel.native.kt

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,21 @@
33
*/
44

55
@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
6+
@file:OptIn(ExperimentalForeignApi::class, ExperimentalNativeApi::class)
67

78
package kotlinx.rpc.grpc
89

10+
import cnames.structs.grpc_channel
11+
import kotlinx.cinterop.CPointer
12+
import kotlinx.cinterop.ExperimentalForeignApi
13+
import kotlinx.rpc.grpc.internal.ClientCall
14+
import kotlinx.rpc.grpc.internal.GrpcCallOptions
915
import kotlinx.rpc.grpc.internal.GrpcChannel
16+
import kotlinx.rpc.grpc.internal.MethodDescriptor
17+
import libgrpcpp_c.*
18+
import kotlin.experimental.ExperimentalNativeApi
19+
import kotlin.native.ref.createCleaner
20+
import kotlin.time.Duration
1021

1122
/**
1223
* Same as [ManagedChannel], but is platform-exposed.
@@ -23,7 +34,13 @@ public actual abstract class ManagedChannelBuilder<T : ManagedChannelBuilder<T>>
2334
}
2435

2536
internal actual fun ManagedChannelBuilder<*>.buildChannel(): ManagedChannel {
26-
error("Native target is not supported in gRPC")
37+
return NativeManagedChannel(
38+
target = "localhost:50051",
39+
credentials = GrpcCredentials(
40+
grpc_insecure_credentials_create()
41+
?: error("Failed to create credentials")
42+
)
43+
)
2744
}
2845

2946
internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedChannelBuilder<*> {
@@ -33,3 +50,58 @@ internal actual fun ManagedChannelBuilder(hostname: String, port: Int): ManagedC
3350
internal actual fun ManagedChannelBuilder(target: String): ManagedChannelBuilder<*> {
3451
error("Native target is not supported in gRPC")
3552
}
53+
54+
55+
internal class NativeManagedChannel(
56+
private val target: String,
57+
// we must store them, otherwise the credentials are getting released
58+
private val credentials: GrpcCredentials,
59+
) : ManagedChannel, ManagedChannelPlatform() {
60+
61+
internal val raw: CPointer<grpc_channel> = grpc_channel_create(target, credentials.raw, null)
62+
?: error("Failed to create channel")
63+
private val rawCleaner = createCleaner(raw) {
64+
grpc_channel_destroy(it)
65+
}
66+
67+
override val platformApi: ManagedChannelPlatform = this
68+
69+
override val isShutdown: Boolean
70+
get() = TODO("Not yet implemented")
71+
override val isTerminated: Boolean
72+
get() = TODO("Not yet implemented")
73+
74+
override suspend fun awaitTermination(duration: Duration): Boolean {
75+
TODO("Not yet implemented")
76+
}
77+
78+
override fun shutdown(): ManagedChannel {
79+
TODO("Not yet implemented")
80+
}
81+
82+
override fun shutdownNow(): ManagedChannel {
83+
TODO("Not yet implemented")
84+
}
85+
86+
87+
override fun <RequestT, ResponseT> newCall(
88+
methodDescriptor: MethodDescriptor<RequestT, ResponseT>,
89+
callOptions: GrpcCallOptions,
90+
): ClientCall<RequestT, ResponseT> {
91+
TODO("Not yet implemented")
92+
}
93+
94+
override fun authority(): String {
95+
TODO("Not yet implemented")
96+
}
97+
98+
}
99+
100+
101+
internal class GrpcCredentials(
102+
internal val raw: CPointer<grpc_channel_credentials_t>,
103+
) {
104+
val rawCleaner = createCleaner(raw) {
105+
grpc_channel_credentials_release(it)
106+
}
107+
}

grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/Status.native.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,21 @@
44

55
package kotlinx.rpc.grpc
66

7-
public actual class Status {
8-
public actual fun getDescription(): String? {
9-
TODO("Not yet implemented")
10-
}
7+
public actual class Status internal constructor(
8+
private val description: String?,
9+
internal val statusCode: StatusCode,
10+
private val cause: Throwable?
11+
) {
12+
public actual fun getDescription(): String? = description
1113

12-
public actual fun getCause(): Throwable? {
13-
TODO("Not yet implemented")
14-
}
14+
public actual fun getCause(): Throwable? = cause
1515
}
1616

1717
public actual val Status.code: StatusCode
18-
get() = TODO("Not yet implemented")
18+
get() = this.statusCode
1919

2020
public actual fun Status(
2121
code: StatusCode,
2222
description: String?,
2323
cause: Throwable?,
24-
): Status {
25-
TODO("Not yet implemented")
26-
}
24+
): Status = Status(description, code, cause)

grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/StatusException.native.kt

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,39 @@
55
package kotlinx.rpc.grpc
66

77
public actual class StatusException : Exception {
8-
public actual fun getStatus(): Status {
9-
TODO("Not yet implemented")
10-
}
8+
private val status: Status
9+
private val trailers: GrpcTrailers?
1110

12-
public actual fun getTrailers(): GrpcTrailers? {
13-
TODO("Not yet implemented")
11+
public actual constructor(status: Status) : super(status.getDescription()) {
12+
this.status = status
13+
this.trailers = null
1414
}
1515

16-
public actual constructor(status: Status) {
17-
TODO("Not yet implemented")
16+
public actual constructor(status: Status, trailers: GrpcTrailers?) : super(status.getDescription()) {
17+
this.status = status
18+
this.trailers = trailers
1819
}
1920

20-
public actual constructor(status: Status, trailers: GrpcTrailers?) {
21-
TODO("Not yet implemented")
22-
}
21+
public actual fun getStatus(): Status = status
22+
23+
public actual fun getTrailers(): GrpcTrailers? = trailers
2324
}
2425

2526
public actual class StatusRuntimeException : RuntimeException {
26-
public actual fun getStatus(): Status {
27-
TODO("Not yet implemented")
28-
}
27+
private val status: Status
28+
private val trailers: GrpcTrailers?
2929

30-
public actual fun getTrailers(): GrpcTrailers? {
31-
TODO("Not yet implemented")
30+
public actual constructor(status: Status) : super(status.getDescription()) {
31+
this.status = status
32+
this.trailers = null
3233
}
3334

34-
public actual constructor(status: Status) {
35-
TODO("Not yet implemented")
35+
public actual constructor(status: Status, trailers: GrpcTrailers?) : super(status.getDescription()) {
36+
this.status = status
37+
this.trailers = trailers
3638
}
3739

38-
public actual constructor(status: Status, trailers: GrpcTrailers?) {
39-
TODO("Not yet implemented")
40-
}
40+
public actual fun getStatus(): Status = status
41+
42+
public actual fun getTrailers(): GrpcTrailers? = trailers
4143
}

grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/ClientCall.native.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public actual abstract class ClientCall<Request, Response> {
2020
public actual abstract fun halfClose()
2121
public actual abstract fun sendMessage(message: Request)
2222
public actual open fun isReady(): Boolean {
23-
TODO("Not yet implemented")
23+
// Default implementation returns true - subclasses can override if they need flow control
24+
return true
2425
}
2526

2627
@InternalRpcApi
@@ -46,5 +47,21 @@ public actual fun <Message> clientCallListener(
4647
onClose: (status: Status, trailers: GrpcTrailers) -> Unit,
4748
onReady: () -> Unit,
4849
): ClientCall.Listener<Message> {
49-
TODO("Not yet implemented")
50+
return object : ClientCall.Listener<Message>() {
51+
override fun onHeaders(headers: GrpcTrailers) {
52+
onHeaders(headers)
53+
}
54+
55+
override fun onMessage(message: Message) {
56+
onMessage(message)
57+
}
58+
59+
override fun onClose(status: Status, trailers: GrpcTrailers) {
60+
onClose(status, trailers)
61+
}
62+
63+
override fun onReady() {
64+
onReady()
65+
}
66+
}
5067
}

0 commit comments

Comments
 (0)