Use Case
● Tracks your route.
● Get a place from location.
Slide 12
Slide 12 text
Use Case
● Tracks your route.
● Get a place from location.
● List Places around location.
Slide 13
Slide 13 text
Use Case
● Tracks your route.
● Get a place from location.
● List Places around location.
● Chat with others at location.
Shoreline Golf links
2940 N Shoreline Blvd
Mountain View, CA 94043
Start typing
Slide 14
Slide 14 text
Building gRPC Server
Slide 15
Slide 15 text
Building gRPC Server
● Configure Server with Kroto-Plus
● Create Service with Protocol Buffers
● Implement Service
● Start Server
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
}
Keyword
Slide 37
Slide 37 text
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
}
Message name
Slide 38
Slide 38 text
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
Fields
Slide 39
Slide 39 text
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
Type
Slide 40
Slide 40 text
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
Type
.proto
Type
C++ Java Go
double double Double *float64
int32 int32 int *int32
Int64 long int/long *int64
https://developers.google.com/protocol-buffers/docs/overview#scalar
Slide 41
Slide 41 text
Unary RPC Call
service Places {
message Location {
double latitude = 1;
double longitude = 2;
}
Field numbers
Slide 42
Slide 42 text
Unary RPC Call
syntax = “proto3”;
service Places {
rpc GetPlace(Location) returns (Place) {};
}
How do we define Place message?
Slide 43
Slide 43 text
Unary RPC Call
message Place {
string name = 1;
Location location = 2;
}
Name & Location
Slide 44
Slide 44 text
Unary RPC Call
message Place {
string name = 1;
Location location = 2;
PlaceType placeType = 3;
}
Enum
Bidirectional
abstract class PlacesImplBase
rpc Chat(stream Comment) returns (stream Comment) {};
suspend fun chat(
requestChannel: ReceiveChannel,
responseChannel: SendChannel
)
Slide 103
Slide 103 text
Bidirectional
abstract class PlacesImplBase
rpc Chat(stream Comment) returns (stream Comment) {};
suspend fun chat(
requestChannel: ReceiveChannel,
responseChannel: SendChannel
)
Slide 104
Slide 104 text
Channel Coroutine
interface Channel : SendChannel, ReceiveChannel
interface ReceiveChannel {
suspend fun receive(): E
}
Slide 105
Slide 105 text
Bidirectional
abstract class PlacesImplBase
rpc Chat(stream Comment) returns (stream Comment) {};
suspend fun chat(
requestChannel: ReceiveChannel,
responseChannel: SendChannel
)
Slide 106
Slide 106 text
Streaming
Client
Server Scope (Dispatcher)
Request Send Channel
Receive Channel
Slide 107
Slide 107 text
Streaming
Client
Server Scope (Dispatcher)
Request
Send Channel
Receive Channel
Slide 108
Slide 108 text
Streaming
Client
Server Scope (Dispatcher)
Response
Send Channel
Receive Channel
Slide 109
Slide 109 text
Generate Service
abstract class PlacesImplBase {
open suspend fun getPlace(…): Place
open suspend fun listPlaces(…)
open suspend fun chat(…)
open suspend fun recordTrip(…)
}
Slide 110
Slide 110 text
Implement Service
class PlacesService(): PlacesImplBase() {
}
Inherit base Implementation
Slide 111
Slide 111 text
Implement Service
class PlacesService(): PlacesImplBase() {
override val initialContext: CoroutineContext
get() = Dispatchers.IO
}
Specify Dispatcher
Slide 112
Slide 112 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase() {
override val initialContext: CoroutineContext
get() = Dispatchers.IO
}
Slide 113
Slide 113 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase() {
override val initialContext: CoroutineContext
get() = dispatcher
}
Specify Dispatcher
Slide 114
Slide 114 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase() {
override suspend fun getPlace(request: Location): Place {
}
}
Slide 115
Slide 115 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase() {
override suspend fun getPlace(request: Location): Place {
val placeFromDB = getPlacesFromDb()
.first { it.location "== request }
}
}
Get Place from DB
Slide 116
Slide 116 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase() {
override suspend fun getPlace(request: Location): Place {
val placeFromDB = getPlacesFromDb()
.first { it.location "== request }
return Place {
name = placeFromDb.name
!!...
}
}
Map it to Proto Message
Slide 117
Slide 117 text
Implement Service
abstract class PlacesImplBase
rpc ListPlaces(Area) returns (stream Place) {};
suspend fun listPlaces(
request: Area,
responseChannel: SendChannel
)
Slide 118
Slide 118 text
Implement Service
abstract class PlacesImplBase
suspend fun listPlaces(
area: Area,
responseChannel: SendChannel
) {
val places = getPlaces(area)
places.forEach { responseChannel.send(it) }
}
}
Send to Channel
Slide 119
Slide 119 text
Implement Service
abstract class PlacesImplBase
suspend fun listPlaces(
area: Area,
responseChannel: SendChannel
) {
val places = getPlaces(area)
places.forEach { responseChannel.send(it) }
}
}
How does channel close?
Errors
abstract class PlacesImplBase
suspend fun listPlaces(
area: Area,
responseChannel: SendChannel
) {
val places = getPlaces(area)
places.forEach { responseChannel.send(it) }
}
}
Exception occurs?
Slide 122
Slide 122 text
Errors
kroto-plus
kroto-plus/ServerCalls.kt
rpcScope.launch {
try {
block(responseChannel)
responseChannel.close()
} finally {
cancelScope()
}
Clean up on error
Slide 123
Slide 123 text
Implement Service
class PlacesService(dispatcher): PlacesImplBase {
suspend fun getPlace(…): Place
suspend fun listPlaces(…)
suspend fun chat(…)
suspend fun recordTrip(…)
}
Slide 124
Slide 124 text
Building gRPC Server
● Configure Server with Kroto-Plus
● Create Service with Protocol Buffers
● Implement Service
● Start Server
Slide 125
Slide 125 text
grpc-java
grpc-java/ServerBuilder.java
class ServerBuilder {
forPort(port)
addService(service)
interceptor(interceptor)
Slide 126
Slide 126 text
Configure gRPC Server
val server: Server = ServerBuilder
.forPort(port)
.addService(PlacesService())
.build()
Slide 127
Slide 127 text
Configure gRPC Server
val server: Server = ServerBuilder
.forPort(port)
.addService(PlacesService())
.build()
Slide 128
Slide 128 text
Start gRPC Server
fun start() {
server.start()
Runtime.getRuntime().addShutdownHook(
Thread {
server.shutdown()
}
)
}
Slide 129
Slide 129 text
Start gRPC Server
fun main() {
val port = 50051
val server = configureServer(port)
server.start()
server.blockUntilShutdown()
}
Slide 130
Slide 130 text
Building gRPC Server
● Configure Server with Kroto-Plus
● Create Service with Protocol Buffers
● Implement Service
● Start Server
grpc/grpc-kotlin
gRPC-Kotlin/JVM - An RPC library and framework
grpc-kotlin-stub v0.1.4 protoc-gen-grpc-kotlinstub v0.1.4 grpc-kotlin-stub-lite v0.1.4
A Kotlin/JVM implementation of gRPC: A high performance,
open source, general RPC framework that puts mobile and
HTTP/2 first.
Bazel Build passing
Gradle Build passing
Slide 134
Slide 134 text
Server
Service Proto File
Slide 135
Slide 135 text
Client Server
Service Proto File
Service Proto File
Slide 136
Slide 136 text
Client Server
Service Proto File
Service Proto File
Client Stub
Generated Client
class CoroutineStub {
}
rpc GetPlace(Location) returns (Place) {};
suspend fun getPlace(request: Location): Place
Slide 140
Slide 140 text
Generated Client
class CoroutineStub {
}
rpc ListPlaces(Area) returns (stream Place) {};
fun listPlaces(request: Area): Flow
Stream is map to Flow
Slide 141
Slide 141 text
Generated Client
class CoroutineStub {
}
rpc Chat(stream Comment) returns (stream Comment) {};
fun chat(requests: Flow): Flow
Stream is map to Flow
Slide 142
Slide 142 text
Generated Client
class CoroutineStub {
}
suspend fun getPlace(request: Location): Place
fun recordTrip(requests: Flow): TripSummary
fun listPlaces(request: Area): Flow
fun chat(requests: Flow): Flow
Slide 143
Slide 143 text
Using Client
val managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.useTransportSecurity()
.build()
Specify host and port
Slide 144
Slide 144 text
Using Client
val managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.useTransportSecurity()
.build()
for https
Slide 145
Slide 145 text
Using Client
val managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.intercept(object : ClientInterceptor {
fun interceptCall(method, callOptions, channel) {
})
.build()
Intercept RPC Calls
Slide 146
Slide 146 text
Using Client
val managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.useTransportSecurity()
.build()
Slide 147
Slide 147 text
Using Client
val managedChannel = ManagedChannelBuilder
.forAddress(host, port)
.useTransportSecurity()
.build()
val client = CoroutineStub(managedChannel)
Slide 148
Slide 148 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
}
Slide 149
Slide 149 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun getPlace(location: Location) {
viewModelScope.launch {
val place = client.getPlace(location)
}
}
}
Slide 150
Slide 150 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun listPlaces(area: Area) {
viewModelScope.launch {
val places: Flow = client.listPlaces(area)
places.collect {
}
}
}
}
Slide 151
Slide 151 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun chat(comments: ReceiveChannel) {
viewModelScope.launch {
client.chat(comments.consumeAsFlow()).collect { }
}
}
}
Stream of comments
Slide 152
Slide 152 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun chat(comments: ReceiveChannel) {
viewModelScope.launch {
client.chat(comments.consumeAsFlow())
.collect {
}
}
}
}
Convert Channel to Flow
Slide 153
Slide 153 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun chat(comments: ReceiveChannel) {
viewModelScope.launch {
client.chat(comments.consumeAsFlow())
.collect {
}
}
}
}
Collect from Flow
Slide 154
Slide 154 text
Using Client
class GrpcViewModel(val client: CoroutineStub): ViewModel() {
fun getPlace(location: Location)
fun listPlaces(area: Area)
fun chat(chat: ReceiveChannel)
}