Hot questions for Using EventBus in sockjs

Question:

I'm trying to make a sock.js connection from the frontend to the vertx backend.

my initial try looked like this:

let token = '<the token>';
let data = {'Authorization' : 'Bearer ' + token};
let eb = new EventBus("http://localhost:8080/eventbus");
  eb.onopen = function () {
  eb.registerHandler('notifications', data, (err, msg) =>  {
    // handle the response
  });
}

this doesn't work since I need to send the auth data on EventBus creation, even though the official sock.js documentation states that this is not supported. Obviously now sending new EventBus("http://localhost:9090/eventbus", data) doesn't work either.

https://github.com/sockjs/sockjs-node#authorisation

my backend handler for this:

final BridgeOptions bridgeOptions = new BridgeOptions()
  .addOutboundPermitted(new PermittedOptions().setAddress("notifications"))

final SockJSHandler sockJSHandler = SockJSHandler.create(vertx).bridge(bridgeOptions, event -> {
  event.complete(true);
});

router.route("/eventbus/*").handler(ctx -> {
  String token = ctx.request().getHeader("Authorization"); // null
});
router.route("/eventbus/*").handler(sockJSHandler);

whatever I tried the header field Authroization is always null.

What is the standard way to authenticate the sock.js connection and register to an eventbus request in vertx?


Answer:

SockJS uses WebSockets by default. You can't add custom headers (Authorization, etc) using JavaScript WebSocket API. Read this thread for more explanation.

I see 2 ways, how you can add authorization:

  1. Just add token parameter to URL:

    let eb = new EventBus("http://localhost:8080/eventbus?token=" + token);
    

    and here's how you can get it on a server:

    String token = ctx.request().getParam("token");
    
  2. Send authorization message after connecting to the server. It can be some JSON object, which contains token field.

I think, 1st option is enough, however, 2nd one can be harder to implement in terms of Event Bus and SockJS.

Question:

I build up with Vertx SockJs an Eventbus Bridge.

This is the code for my verticle:

@Override
public void start() throws Exception {
    Router router = Router.router(vertx);

    SockJSHandler sockJSHandler = SockJSHandler.create(vertx);
    BridgeOptions options = new BridgeOptions();

    options.addInboundPermitted(new PermittedOptions().setAddress("test"));
    options.addOutboundPermitted(new PermittedOptions().setAddress("test"));
    options.addInboundPermitted(new PermittedOptions().setAddress("test2"));
    options.addOutboundPermitted(new PermittedOptions().setAddress("test2"));

    sockJSHandler.bridge(options);

    router.route("/eventbus/*").handler(sockJSHandler);

    vertx.createHttpServer().requestHandler(router::accept).listen(8600);

    vertx.setTimer(5000, id -> {
        vertx.eventBus().send("test", "hallo!", async -> {
            if (async.succeeded()) {
                System.out.println("Success!");
            } else {
                System.out.println("Failure!");
                System.out.println(async.cause());
            }
        });
        System.out.println("SEND!");
    });

}

This is the code of ClientHtml:

var eb = new EventBus('http://localhost:8600/eventbus');

eb.onError=function() {
    console.log('error');
}

eb.onopen = function() {
    console.log('connected');
  // set a handler to receive a message
  eb.registerHandler('test', function(error, message) {
    console.log('received a message: ' + JSON.stringify(message));
    $( "#text" ).html(JSON.stringify(message));
  });

  eb.registerHandler('test2', function(error, message) {
        console.log('received a message: ' + JSON.stringify(message));
        console.log("Error: "+error);
        $( "#text2" ).html(JSON.stringify(message));
      });
}

eb.onclose = function() {
    console.log("disconnected");
    eb = null;
};

Now what Im concerned about:

After my verticle created a connection with the client, all is ok. But when Im restarting my verticle Im getting NO_HANDLER errors, because there is likely no new instance of Eventbus? Is there a way to handle this?


Answer:

You can put your setup code in a method called after the page is loaded. In the onclose callback, cleanup all reply handlers (you will never get the server response) and call your setup method again.

function setupEventBus() {
  var eb = new EventBus(window.location.protocol + "//" + window.location.host + "/eventbus");
  eb.onclose = function (e) {
    // Cleanup reply handlers
    var replyHandlers = eb.replyHandlers;
    for (var address in replyHandlers) {
      if (replyHandlers.hasOwnProperty(address)) {
        replyHandlers[address]({
          failureCode: -1,
          failureType: "DISCONNECT",
          message: "EventBus closed"
        });
      }
    }
    // Setup the EventBus object again (after some time)
    setTimeout(setupEventBus, 1000);
  };
  eb.onopen = function () {
    // Register your handlers here
  };
}