@ntrip/caster
Version:
NTRIP caster
178 lines (177 loc) • 7.82 kB
JavaScript
;
/*
* This file is part of the @ntrip/caster distribution (https://github.com/node-ntrip/caster).
* Copyright (c) 2020 Nebojsa Cvetkovic.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Caster = void 0;
const events = require("events");
const mountpoint_1 = require("./mountpoint");
const connection_1 = require("./connection");
const sourcetable_1 = require("./sourcetable");
const verror_1 = __importDefault(require("verror"));
class Caster extends events.EventEmitter {
constructor(parameters) {
super();
this._transports = new Set();
this._connections = new Set();
this._mountpoints = new Map();
this.staticSourcetableEntries = [];
this.authManager = parameters.authManager;
this.mountpointOptions = parameters.mountpointOptions;
}
get transports() { return this._transports; }
;
get connections() { return this._connections; }
get mountpoints() { return this._mountpoints; }
async authenticate(request) {
return this.authManager.authenticate(request);
}
createMountpoint(mountpointName, options) {
if (this._mountpoints.has(mountpointName))
throw new Error("Mountpoint with name \"" + mountpointName + "\" already exists");
if (options === undefined) {
if (typeof this.mountpointOptions === "function") {
options = this.mountpointOptions(mountpointName);
}
else {
options = this.mountpointOptions;
}
}
const mountpoint = new mountpoint_1.Mountpoint(mountpointName, options);
mountpoint.on('close', () => this._mountpoints.delete(mountpointName));
this._mountpoints.set(mountpointName, mountpoint);
this.emit('mountpoint', mountpoint);
return mountpoint;
}
prepareMountpoint(type, mountpointName) {
let mountpoint = this._mountpoints.get(mountpointName);
if (type === 'server') {
if (mountpoint === undefined)
mountpoint = this.createMountpoint(mountpointName);
else if (mountpoint.active)
throw new verror_1.default({
name: 'ConnectionError',
info: {
mountpoint: mountpointName,
server: mountpoint.server
}
}, 'Mountpoint %s conflict: A server is already connected');
}
else { // if (type === 'client') {
if (mountpoint === undefined || !mountpoint.active)
throw new verror_1.default({
name: 'ConnectionError',
info: {
mountpoint: mountpointName
}
}, 'Mountpoint %s does not exist (or is not currently active)');
}
return mountpoint;
}
connect(params) {
var _a, _b;
const mountpoint = this.prepareMountpoint(params.type, params.mountpoint);
let connection;
const parameters = {
...params,
mountpoint: mountpoint,
input: (_a = params.input) !== null && _a !== void 0 ? _a : params.stream,
output: (_b = params.output) !== null && _b !== void 0 ? _b : params.stream
};
if (params.type === 'server') {
if (parameters.input === undefined)
throw new Error("Missing input stream for server");
connection = new connection_1.Server(parameters);
}
else { // if (params.type === 'client') {
if (parameters.output === undefined)
throw new Error("Missing output stream for client");
connection = new connection_1.Client(parameters);
}
this._connections.add(connection);
connection.once('close', () => this._connections.delete(connection));
// Wait for one tick to allow transport to send successful connection message
process.nextTick(() => {
if (params.type === 'server') {
mountpoint.setServer(connection);
}
else { // if (params.type === 'client') {
mountpoint.addClient(connection);
}
this.emit('connect', connection);
});
return connection;
}
addTransport(constructor) {
const transport = constructor(this);
this._transports.add(transport);
return transport;
}
removeTransport(transport) {
this._transports.delete(transport);
}
/**
* Gets a list of sourcetable entries for the caster with an optional set of filters
*
* @param filters Optional filters to apply to the sourcetable list
* @param auth Authentication request for auth filter
*/
async getSourcetableEntries(filters, auth) {
let entries = Array.from(this._mountpoints.values()).map(m => m.sourceEntry);
if (filters !== undefined) {
// Include static entries if not filtering by auth
if (!filters.auth)
entries = this.staticSourcetableEntries.concat(entries);
// Filter entries
if (filters.simple !== undefined)
entries = entries.filter(e => e.filter(filters.simple, true, filters.strict));
if (filters.advanced !== undefined)
entries = entries.filter(e => e.filter(filters.advanced, false, filters.strict));
// Filter authentication
if (filters === null || filters === void 0 ? void 0 : filters.auth) {
if (auth === undefined)
throw new Error("Attempting to filter sourcetable entries by authentication without providing authentication request");
const filterResults = await Promise.all(entries.map(async (entry) => {
const mountpointAuth = Object.assign({}, auth);
mountpointAuth.mountpoint = entry.mountpoint;
return (await this.authenticate(mountpointAuth)).authenticated;
}));
entries = entries.filter((e, i) => filterResults[i]);
}
// Filter aggregations on all remaining entries
if ((filters === null || filters === void 0 ? void 0 : filters.advanced) !== undefined)
entries = sourcetable_1.Sourcetable.filterApproximations(filters.advanced, entries, filters.strict);
}
return entries;
}
/**
* Generates the sourcetable for the caster with an optional set of filters
*
* @param filters Optional filters to apply to the sourcetable list
* @param auth Authentication request for auth filter
*/
async generateSourcetable(filters, auth) {
return (await this.getSourcetableEntries(filters, auth))
.map(e => e.toSourcetableLine())
.concat('ENDSOURCETABLE\r\n').join('\r\n');
}
}
exports.Caster = Caster;
Caster.NAME = 'NodeNtripCaster/0.0.1';