0

I'm trying to implement a request -> response layer on top of websockets in Java. I recently stumbled across RxJava, which seems like a nice library to use for this. Down below is my current approach for handling the request response flow (unimportant code omitted for readability)

public class SimpleServer extends WebSocketServer {
  Gson gson = new Gson();
  Map<String, Function<JsonObject, Void>> requests = new HashMap<>();

  private static int count = 0;

  public SimpleServer(InetSocketAddress address) {
    super(address);
  }

  @Override
  public void onMessage(WebSocket conn, String message) {
    String type = ...;
    JsonObject payload = ...;
    if (type.equals("response")) {
      Request request = requests.get(requestId).apply(payload);
    }
  }

  public Single<JsonObject> request(String action) {
    requests.put(Integer.toString(count++), response -> {
      source.onSuccess(response);
      return null;
    });
    broadcast(...);
  }
}

Is this a viable solution or is there a better way?
I was thinking if there was a way to use RxJava for both ways, i.e. the request would listen to an "onMessage" observable or something along those lines.
All help will be greatly appreciated.

Lova Chittumuri
  • 2,994
  • 1
  • 30
  • 33
rosengrenen
  • 731
  • 6
  • 21

1 Answers1

0

You can use RxJava for communication in both ways. Let's start with a simpler one – receiving messages. I recommend you use BehaviorRelay what behaves both like Observer and Consumer. You can both listen for emitted values and produce values – messages in our case. A simple implementation might look like this:

public class SimpleServer extends WebSocketServer {
    private BehaviorRelay<String> receivedMessages = BehaviorRelay.create();

    public SimpleServer(InetSocketAddress address) {
        super(address);
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        receivedMessages.accept(message); // "sends" value to the relay
    }

    public Observable<String> getReceivedMessagesRx() {
        return receivedMessages.hide(); // Cast Relay to Observable
    }

    //...

You can now call function getReceivedMessagesRx() and subscribe for incoming messages.

Now the more interesting part – sending messages. Let's assume, you have some Observable, what produces messages you want to send:

    // ...

    private Disposable senderDisposable = Disposables.disposed(); // (1)

    public void setMessagesSender(Observable<String> messagesToSend) { // (2)
        senderDisposable = messagesToSend.subscribe(message -> { 
            broadcast(message);
        }, throwable -> {
            // handle broadcast error 
        });
    }

    public void clear() { // (3)
        senderDisposable.dispose(); 
    }
}

What happens here:

  1. Create Disposable which holds a reference to running observer of the messages to be sent.
  2. Subscribe to passed Observable what emits every time you want to send a message. This function is meant to be called only once. If you want to call it multiple times, handle the disposal of previous sender or use CompositeDisposable to store multiple disposables.
  3. When you are done working with your server, do not forget to dispose messages sender.
skywall
  • 3,956
  • 1
  • 34
  • 52