node-roon-api icon indicating copy to clipboard operation
node-roon-api copied to clipboard

Several issues with using this library from the Web due to differing WebSocket implementation

Open trisweb opened this issue 1 year ago • 0 comments

Trying out the web example, there are several issues preventing it from working properly with the native browser WebSocket that I've had to work around or am in the process of working around.

https://github.com/roonlabs/roon-extension-web-testapp

The following methods are used by the Roon library, however are not available in native browser WebSocket: on(), ping(), and terminate()

The following polyfills within the example app are working reasonably to get the app running:

WebSocket.prototype.on = function(event, handler) {
    this.addEventListener(event, handler);
};
WebSocket.prototype.ping = function() {
    this.send("[]");
};
WebSocket.prototype.terminate = function() { this.close(); };

However, ping() is not sufficient as it's not a true websocket ping message. I still receive the error:

Roon API Connection to 192.168.1.10:9330 closed due to missed heartbeat

And the connection genuinely closes.

However, with those polyfills, the web app does work for a few seconds! Better than nothing.

I've explored how to get the ping() message working from the web, but there doesn't seem to be a reasonable way to send a message with the proper opcode directly from the native WebSocket. It's below the abstraction layer of the browser websocket library, and you don't get to break down and send the right message type for a true ping, whereas the Node library does offer just that.

You can't use the node library in the browser, that's the first thing I tried.

I'm not sure how to get around this ping piece exactly. Ideally, the Roon API itself is a little more open to how native browser WebSocket works (it sends its own ping packets automatically, afaik, on a slightly slower rate than Roon expects it seems).

My next workaround is probably to just do the Roon API connection on a backend instead of in the browser, and message pass to the frontend, but I'd rather not go that direction if it can be helped.

Steps I see:

  1. Fix implementation of node-roon-api to be compatible with the native WebSocket browser API, and avoid using methods not available in the browser.
  2. Bigger ask but the only proper solution I see -- adjust the timing or implementation of the Roon API service to be friendly with browser WebSocket connections. Will require inspecting what browsers actually do for keepalive and adjusting to fit; or alternatively being open to recieving a standard websocket message with a special payload as an "alternative ping" that browsers can send and considering it the same thing.

I could potentially help with the first, but likely not the second! Thanks.

trisweb avatar Mar 05 '23 15:03 trisweb