signalk-server
Version:
An implementation of a [Signal K](http://signalk.org) server for boats.
172 lines • 6.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.startEvents = startEvents;
exports.startServerEvents = startServerEvents;
exports.wrapEmitter = wrapEmitter;
const debug_1 = require("./debug");
function startEvents(app, spark, onEvent, eventsFromQuery = '') {
const events = eventsFromQuery.split(',');
events.forEach((event) => {
app.on(event, (data) => onEvent({ event, data }));
spark.onDisconnects.push(() => app.removeListener(event, onEvent));
});
}
function startServerEvents(app, spark, onServerEvent) {
app.on('serverevent', onServerEvent);
spark.onDisconnects.push(() => {
app.removeListener('serverevent', onServerEvent);
});
try {
spark.write({
type: 'VESSEL_INFO',
data: {
name: app.config.vesselName,
mmsi: app.config.vesselMMSI,
uuid: app.config.vesselUUID
}
});
}
catch (e) {
if (e.code !== 'ENOENT') {
console.error(e);
}
}
Object.keys(app.lastServerEvents).forEach((propName) => {
spark.write(app.lastServerEvents[propName]);
});
spark.write({
type: 'DEBUG_SETTINGS',
data: app.logging.getDebugSettings()
});
if (app.securityStrategy.canAuthorizeWS()) {
spark.write({
type: 'RECEIVE_LOGIN_STATUS',
data: app.securityStrategy.getLoginStatus(spark.request)
});
}
spark.write({
type: 'SOURCEPRIORITIES',
data: app.config.settings.sourcePriorities || {}
});
}
function safeApply(handler, context, args) {
try {
Reflect.apply(handler, context, args);
}
catch (err) {
// Throw error after timeout so as not to interrupt the stack
setTimeout(() => {
throw err;
});
}
}
function arrayClone(arr) {
const n = arr.length;
const copy = new Array(n);
for (let i = 0; i < n; i += 1) {
copy[i] = arr[i];
}
return copy;
}
function wrapEmitter(targetEmitter) {
const targetAddListener = targetEmitter.addListener.bind(targetEmitter);
const eventDebugs = {};
const eventsData = {};
let emittedCount = 0;
function safeEmit(eventName, ...args) {
if (eventName !== 'serverlog') {
let eventDebug = eventDebugs[eventName];
if (!eventDebug) {
eventDebugs[eventName] = eventDebug = (0, debug_1.createDebug)(`signalk-server:events:${eventName}`);
}
if (eventDebug.enabled) {
//there is ever only one rest argument, outputting args results in a 1 element array
eventDebug(args[0]);
}
}
// from https://github.com/MetaMask/safe-event-emitter/blob/main/index.t
let doError = eventName === 'error';
const events = targetEmitter._events;
if (events !== undefined) {
doError = doError && events.error === undefined;
}
else if (!doError) {
return false;
}
// If there is no 'error' event listener then throw.
if (doError) {
let er;
if (args.length > 0) {
;
[er] = args;
}
if (er instanceof Error) {
// Note: The comments on the `throw` lines are intentional, they show
// up in Node's output if this results in an unhandled exception.
throw er; // Unhandled 'error' event
}
// At least give some kind of context to the user
const err = new Error(`Unhandled error.${er ? ` (${er.message})` : ''}`);
err.context = er;
throw err; // Unhandled 'error' event
}
const handler = events[eventName];
if (handler === undefined) {
return false;
}
emittedCount++;
if (typeof handler === 'function') {
safeApply(handler, this, args);
}
else {
const len = handler.length;
const listeners = arrayClone(handler);
for (let i = 0; i < len; i += 1) {
safeApply(listeners[i], this, args);
}
}
return true;
}
function emitWithEmitterId(emitterId, eventName, ...args) {
const emittersForEvent = (eventsData[eventName] ??
(eventsData[eventName] = { emitters: {}, listeners: {} })).emitters;
if (!emittersForEvent[emitterId]) {
emittersForEvent[emitterId] = 0;
}
emittersForEvent[emitterId]++;
safeEmit(`${emitterId}:${eventName}`, ...args);
return safeEmit(eventName, ...args);
}
const addListenerWithId = function (listenerId, eventName, listener) {
const listenersForEvent = (eventsData[eventName] ??
(eventsData[eventName] = { emitters: {}, listeners: {} })).listeners;
if (!listenersForEvent[listenerId]) {
listenersForEvent[listenerId] = true;
}
return targetAddListener(eventName, listener);
};
return {
getEmittedCount: () => emittedCount,
getEventRoutingData: () => ({
events: Object.entries(eventsData).map(([event, data]) => ({
event,
...data
}))
}),
emit: function (eventName, ...args) {
return emitWithEmitterId('NO_EMITTER_ID', eventName, ...args);
},
addListener: (eventName, listener) => addListenerWithId('NO_LISTENER_ID', eventName, listener),
bindMethodsById: (actorId) => {
const addListener = (eventName, listener) => addListenerWithId(actorId, eventName, listener);
return {
emit: function (eventName, ...args) {
return emitWithEmitterId(actorId, eventName, ...args);
},
addListener,
on: addListener
};
}
};
}
//# sourceMappingURL=events.js.map