@x5e/gink
Version:
an eventually consistent database
73 lines • 3.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RoutingServer = void 0;
const Database_1 = require("./Database");
const RoutingServerInstance_1 = require("./RoutingServerInstance");
const utils_1 = require("./utils");
const fs_1 = require("fs");
const path_1 = require("path");
const Listener_1 = require("./Listener");
/**
* A class that listens on a port, and then serves either static content over HTTP(S)
* or opens websocket connections and hands it off to the appropriate RoutingServerInstance.
*
* The user passes in a dataFilesRoot, which should be a writable directory on the local system.
* The RoutingServer will create a RoutingServerInstance for each file/requested resource.
*/
class RoutingServer {
constructor(args) {
this.instances = new Map();
const logger = (this.logger = args.logger || (() => null));
this.authFunc = args.authFunc || (() => true);
this.identity = args.identity;
this.dataFilesRoot = args.dataFilesRoot;
(0, utils_1.ensure)((0, fs_1.existsSync)(this.dataFilesRoot), "data root not there");
this.listener = new Listener_1.Listener(Object.assign({ requestHandler: this.onRequest.bind(this), logger }, args));
this.ready = this.listener.ready.then(() => logger(`RoutingServer ready`));
}
/**
*
* @param path absolute path to the args.data_file
* @returns a promise of an instance that will manage that file
*/
getInstance(path) {
// Note: can't afford to await for the instance to be ready, or you'll miss the greeting.
let instance = this.instances.get(path);
if (!instance) {
instance = new RoutingServerInstance_1.RoutingServerInstance(path, this.identity, this.logger);
this.instances.set(path, instance);
}
return instance;
}
/**
* Decides whether to accept the request, and if it does, hands it off
* to a database instance to manage that connection to the specified resource.
* @param request contains information passed from the websocket server
*/
async onRequest(request) {
let protocol = null;
let token = null;
if (request.requestedProtocols.length) {
for (const protocol of request.requestedProtocols) {
if (protocol.match(/0x.*/)) {
token = (0, utils_1.decodeToken)(protocol);
}
}
if (request.requestedProtocols.includes(Database_1.Database.PROTOCOL))
protocol = Database_1.Database.PROTOCOL;
else
return request.reject(400, "bad protocol");
}
if ((0, utils_1.isPathDangerous)(request.resource))
return request.reject(400, "bad path");
if (!this.authFunc(token)) {
return request.reject(401, "authentication failed");
}
const connection = request.accept(protocol, request.origin);
const instanceKey = (0, path_1.join)(this.dataFilesRoot, request.resource);
const instance = this.getInstance(instanceKey);
await instance.onConnection(connection);
}
}
exports.RoutingServer = RoutingServer;
//# sourceMappingURL=RoutingServer.js.map