Skip to content

Update get-started.md to latest RSocket version #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
80 changes: 36 additions & 44 deletions docs/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RSocket RPC uses [Protobuf 3](https://developers.google.com/protocol-buffers/doc
RSocket RPC is built with a full duplex protocol RSocket. An application that initiates a connection (traditionally a client) can actually serve requests from the application it is connecting with (traditionally the server). In other words a client can connect to a server, and the server can call a RSocket RPC service located on the client. The server does not have to wait for the client to initiate a call, only the connection is necessary.

### Reactive Streams Compatible
RSocket RPC's Java implementation is built using a [Reactive Streams](http://www.reactive-streams.org/) compliant library, [Reactor-core](https://github.com/reactor/reactor-core). RSocket RPC generated code returns either a Flux, which is a stream of many, or a Mono, which is a stream of one. RSocket RPC is compatible with any Reactive Streams implementation including RXJava 2 and Akka Streams.
RSocket RPC's Java implementation is built using a [Reactive Streams](http://www.reactive-streams.org/) compliant library, [Reactor-core](https://github.com/reactor/reactor-core). RSocket RPC generated code returns either a Flux, which is a stream of many, or a Mono, which is a stream of one. RSocket RPC is compatible with any Reactive Streams implementation including RXJava 2 and Akka Streams.

### Back-pressure
RSocket RPC respects both RSocket and Reactive Streams back-pressure. Back-pressure is where the consumer of a stream sends the stream's producer a message indicating how many messages it can handle. This makes RSocket RPC services very reliable, and not overwhelmed with demand.
Expand All @@ -24,15 +24,15 @@ RSocket RPC has five interaction models. They are modeled using a Protobuf 3 IDL
Request-response is analogous to a HTTP Rest call. A major difference is that because this is non-blocking the caller can wait for the response for a long time without blocking other requests on the same connection.

#### Protobuf
```
```protobuf
rpc RequestReply (SimpleRequest) returns (SimpleResponse) {}
```

### Fire-and-Forget
Fire-and-forget sends a request without expecting a response. This is not just ignoring the response; the underlying protocol does not send anything back to the caller. To make a request fire-and-forget with RSocket RPC you need to return `google.protobuf.Empty` in your IDL. This will generate fire-and-forget code.

#### Protobuf
```
```protobuf
import "google/protobuf/empty.proto";
rpc FireAndForget (SimpleRequest) returns (google.protobuf.Empty) {}
Expand All @@ -42,23 +42,23 @@ rpc FireAndForget (SimpleRequest) returns (google.protobuf.Empty) {}
This interaction model sends a single request and then receives multiple responses. This can be used to model subscriptions to topics and queues. It can be also used to do things like page from a database. To generate this, mark the response with the `stream` keyword.

#### Protobuf
```
```protobuf
rpc RequestStream (SimpleRequest) returns (stream SimpleResponse) {}
```

### Streaming Request / Single Response
This interaction model sends a stream of requests and then receives a single response. This can be used to model transactions. You can send multiple requests over a logic channel, and then receive a single response indicating whether they were processed correctly or not. Mark the request with the `stream` keyword to create this interaction model.

#### Protobuf
```
```protobuf
rpc StreamingRequestSingleResponse (stream SimpleRequest) returns (SimpleResponse) {}
```

### Streaming Request / Streaming Response
This interaction model sends a request stream and returns a response stream. This models a fully-duplex interaction. Mark the request and response with the `stream` keyword to create this interaction model.

#### Protobuf
```
```protobuf
rpc StreamingRequestAndResponse (stream SimpleRequest) returns (stream SimpleResponse) {}
```

Expand All @@ -83,14 +83,14 @@ $ sudo apt-get install libProtobuf-java Protobuf-compiler
### Configuring Gradle
RSocket RPC Java uses a Protobuf plugin to generate application code. Add the following code to your project's Gradle file so that it will generate code from your Protobuf IDL when your application is compiled.

```
```groovy
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.6.1'
artifact = 'com.google.protobuf:protoc:3.19.1'
}
plugins {
rsocketRpc {
artifact = 'io.rsocket.rpc:rsocket-rpc-protobuf:0.2.5'
artifact = 'io.rsocket.rpc:rsocket-rpc-protobuf:0.3.0'
}
}
generateProtoTasks {
Expand Down Expand Up @@ -120,7 +120,7 @@ clean {

### Define a Protobuf
After you have installed Protobuf and configured Gradle you need to create a Protobuf IDL to define your service. The following is a simple Protobuf example that defines all the interaction model varieties:
```
```protobuf
syntax = "proto3";

package io.rsocket.rpc.testing;
Expand Down Expand Up @@ -163,7 +163,7 @@ After you have configured your Protobuf IDL, use the Protobuf compiler via the G
$ gradlew generateProto
```

The Protobuf compiler will generate Protobuf builders for the message, and then use the RSocket RPC compiler to generate an interface for the service defined in the IDL. It will also generate a client that implements the interface, and a server takes an implementation of the interface. This is what serves the requests.
The Protobuf compiler will generate Protobuf builders for the message, and then use the RSocket RPC compiler to generate an interface for the service defined in the IDL. It will also generate a client that implements the interface, and a server takes an implementation of the interface. This is what serves the requests.

Using the above IDL as an example RSocket RPC will generate several classes from the above example, but the ones that you need to concern yourself with are:
* `SimpleRequest`
Expand All @@ -174,13 +174,13 @@ Using the above IDL as an example RSocket RPC will generate several classes from

### RSocket RPC IDL Example
Here is an example implementation of `SimpleService`, the service contract from the IDL. The `SimpleService` interface needs to be implemented in order to handle requests:
```
```java
class DefaultSimpleService implements SimpleService {
@Override
public Mono<Empty> fireAndForget(SimpleRequest message, ByteBuf metadata) {
System.out.println("got message -> " + message.getRequestMessage());
return Mono.just(Empty.getDefaultInstance());
}
public Mono<Empty> fireAndForget(SimpleRequest message, ByteBuf metadata) {
System.out.println("got message -> " + message.getRequestMessage());
return Mono.just(Empty.getDefaultInstance());
}

@Override
public Mono<SimpleResponse> requestReply(SimpleRequest message, ByteBuf metadata) {
Expand Down Expand Up @@ -245,64 +245,56 @@ class DefaultSimpleService implements SimpleService {

### RSocket RPC Server Configuration
The RSocket RPC Compiler generates a client and server interface for you. After you have implemented these generated interfaces you need to hand the implementation to the server. See the below example:
```
SimpleServiceServer serviceServer = new SimpleServiceServer(new DefaultSimpleService(), Optional.empty(), Optional.empty());
```java
SimpleServiceServer serviceServer = new SimpleServiceServer(new DefaultSimpleService(), Optional.empty(), Optional.empty(), Optional.empty());
```

Once you have created an instance of the the server, you need to configure RSocket. The
Once you have created an instance of the the server, you need to configure RSocket. The
following is a RSocket server configuration

```java
CloseableChannel closeableChannel = RSocketFactory
.receive()
CloseableChannel closeableChannel = RSocketServer
.create()
.acceptor((setup, sendingSocket) -> Mono.just(
new RequestHandlingRSocket(serviceServer)
new RequestHandlingRSocket().withEndpoint(serviceServer)
))
.transport(TcpServerTransport.create(8081))
.start()
.bind(TcpServerTransport.create(8081))
.block();
```

#### RSocket RPC Client Common Configuration
The RSocket RPC compiler generates a client as well as a server. The client implements the generated interface. You can configure the client either from an RSocket client connection, or server connection. The following shows how to configure an initiator of a connection, typically a client, to send requests to the `SimpleService` implementation.

```java
RSocket rSocket = RSocketFactory
.connect()
.transport(TcpClientTransport.create(8081))
.start()
.block();
RSocket rSocket = RSocketConnector
.connectWith(TcpClientTransport.create(8081))
.block();
SimpleServiceClient serviceClient = new SimpleServiceClient(rSocket);
```

#### RSocket RPC Client over Server Configuration
This configures the receiver of a connection, typically a server, to call the remote `SimpleService`. Notice that the client is created inside the closure in the acceptor method. The method passes in a variable called `sendingSocket`. This is the RSocket that is the connection to the client. You can make calls to the client *without* receiving requests first, or ever.
```
RSocketFactory.receive()
```java
RSocketServer.create()
.acceptor(
(setup, sendingSocket) -> {
SimpleServiceClient client = new SimpleServiceClient(sendingSocket);

// Trivial example - this could also be an RSocket RPC service.
return Mono.just(
new AbstractRSocket() {
@Override
public Mono<Void> fireAndForget(Payload payload) {
return client.fireAndForget(
SimpleRequest.newBuilder()
.setRequestMessage(payload.getDataUtf8())
.build());
}
});
})
.transport(TcpServerTransport.create(8081))
.start()
SocketAcceptor.forFireAndForget(payload ->
client.fireAndForget(
SimpleRequest.newBuilder()
.setRequestMessage(payload.getDataUtf8())
.build())));
}))
.bind(TcpServerTransport.create(8081))
.block();
```

### Calling the Client
Once the client is created, it can be called like any other method. Here is an example call to the `streamingRequestSingleResponse` method.
```
```java
SimpleServiceClient client = new SimpleServiceClient(rSocket);

Flux<SimpleRequest> requests =
Expand Down