skybrush-io / live

An open-source drone show and drone swarm ground control station GUI frontend
https://skybrush.io
GNU General Public License v3.0
44 stars 32 forks source link

Switch from WebSocket to raw TCP when Live is packaged as a desktop app #15

Closed ntamas closed 1 year ago

ntamas commented 1 year ago

Skybrush Live currently uses JSON messages wrapped in a Socket.IO WebSocket connection to connect to the server. The advantage of this approach is that one can use the same connection from the desktop app and the browser-based version of Skybrush Live, and it just works. However, the server has supported raw TCP connections for quite a while now and it would be great if we could investigate what it would take to switch to TCP from WebSocket when Live is packaged in Electron.

This is likely to be a longer, non-trivial task.

The server listens for incoming TCP connections on port 5001. Live can discover this endpoint automatically with SSDP by scanning for urn:collmot-com:service:flockwave-tcp:1 instead of urn:collmot-com:service:flockwave-sio:1. The connection uses newline-delimited JSON messages; in other words, you can simply split messages by looking for newline characters and each chunk must be valid JSON then. It is guaranteed that the JSON messages themselves do not contain newline characters (they can only occur in strings, and in strings they are encoded as \n).

One thing that will surely be needed is to extend the preload script of the renderer process in Electron to provide limited access to TCP functionality to the sandboxed environment in which the renderer is running. The functionality should be as limited as possible, i.e. we should not simply expose the entire Node.js tcp module to the renderer process but only those functions that the renderer will actually need. (Maybe the best would be that the preload module provides only a createTCPSocket function that returns a wrapper class around the TCP socket with nice async functions for reading from, writing to and closing the socket).

We will probably also need a mechanism to periodically check whether the connection is alive. WebSocket already contained this mechanism (it has special frames for that), but we need to implement it ourselves for TCP. The easiest is to set up a timer in Live to send a newline over the TCP connection every five seconds; TCP timeouts on the OS level will handle the rest if the connection is broken, the point is that there needs to be some traffic over the connection even if Live has nothing to say, otherwise it is not possible to detect that the connection has been broken if the server exited without cleaning up its own end of the TCP connection.