ForgeTotal.js 5
en

Total.js 5

Publish a local server through a tunnel with PROXYSERVER() and PROXYCLIENT()

Total.js 5 · total5@0.0.19 proxytunnelwebsocketintegrations Executed against Total.js 5

PROXY() forwards a request to a server that the proxy can reach. A tunnel is for the opposite case: the program is on a laptop or behind a firewall, so nobody can connect to it, but it can connect out. PROXYSERVER() and PROXYCLIENT() make that with one WebSocket that the private side opens:

  • PROXYSERVER([endpoint], [socketendpoint], [logger]) runs on the public server. Every request below endpoint (default /) is sent through the tunnel; socketendpoint (default /) is the WebSocket address where the client connects. Use different addresses when the same application serves anything else: a proxy on / takes every request, also the ones of your own routes (it runs before them). logger is a function (default: prints with the date); pass null for none.
  • PROXYCLIENT(serverurl, port, [logger]) runs on the private side (in this example the address of the server is built with CONF.$port, the port of the application). serverurl is the address of the WebSocket of the server (ws:// or wss://; http is changed to ws) and port is 3000 or ip:3000, the local program that receives the requests. It returns the WebSocket client.
  • One client at a time: when a second client connects, the server closes it with the code 4001. Without a client the answer of the server is Not yet available..
  • The local program receives the whole path of the original request, including the endpoint (/tunnel/hello), the headers of the visitor and an x-proxy: Total.js header, with host set to the local address.
  • The WebSocket route has no authentication of its own: do not publish it without something in front of it that decides who can connect (the address is the secret, a check of your own, a firewall).

Here one application is both sides: a small local program on port 9511 (any program would do), the server on /tunnel/ and the client that connects to the same application.

definitions/local.js
// The program that is "private": an ordinary HTTP server that only listens on the loopback address
require('http').createServer(function(req, res) {
	res.writeHead(200, { 'content-type': 'application/json' });
	res.end(JSON.stringify({ path: req.url, via: req.headers['x-proxy'] || null, host: req.headers.host }));
}).listen(9511, '127.0.0.1');
controllers/tunnel.js
exports.install = function() {
	ROUTE('GET /status/', status);
	ROUTE('POST /connect/', connect);
};

// The public side: /tunnel/* goes through the tunnel, the WebSocket of the client is /tunnel-socket/. No logger.
PROXYSERVER('/tunnel/', '/tunnel-socket/', null);

let client = null;

function connect($) {
	client = PROXYCLIENT('ws://127.0.0.1:' + CONF.$port + '/tunnel-socket/', '9511', null);
	$.json({ connecting: true });
}

function status($) {
	$.json({ connected: !!client });
}