UNPKG

nope-js-node

Version:

NoPE Runtime for Nodejs. For Browser-Support please use nope-browser

220 lines (219 loc) 7.7 kB
"use strict"; /** * @author Martin Karkowski * @email m.karkowski@zema.de */ Object.defineProperty(exports, "__esModule", { value: true }); exports.generateDefineMaster = exports.waitForDispatcher = exports.enableTimeSyncing = exports.generatePingAccessors = exports.generatePingServices = void 0; const arrayMethods_1 = require("../../helpers/arrayMethods"); const getLogger_1 = require("../../logger/getLogger"); const logger = (0, getLogger_1.getNopeLogger)("baseService"); /** * Generate and registers a ping service. * * @author M.Karkowski * @export * @param {INopeDispatcher} dispatcher * @return {*} The function to ping all dispatchers. */ async function generatePingServices(dispatcher) { // Name of the Service const serviceName = `nope/baseService/ping`; const ping = async () => { return { dispatcherId: dispatcher.id, timestamp: dispatcher.connectivityManager.now, }; }; logger.info("Adding 'ping' service!"); if (!dispatcher.rpcManager.isProviding(serviceName)) { // Registers the Ping Method at the Dispatcher. await dispatcher.rpcManager.registerService(ping, { id: serviceName, schema: { inputs: [], outputs: { type: "object", properties: { dispatcherId: { type: "string", description: "Id of the responding Dispatcher", }, timestamp: { type: "number", description: "UTC-Timestamp of the system which is responding", }, }, }, type: "function", description: "Ping", }, }); } return await generatePingAccessors(dispatcher); } exports.generatePingServices = generatePingServices; /** * Helper to generate the Accessors to ping dispatchers or ping all * systems * * @author M.Karkowski * @export * @param {INopeDispatcher} dispatcher The Dispatcher, used to perform the calls. * @return {*} */ async function generatePingAccessors(dispatcher) { const serviceName = `nope/baseService/ping`; logger.info("Adding 'determinePing' service!"); // Function to determine the ping in the services. const determinePing = async (target) => { // Call the Pings const start = dispatcher.connectivityManager.now; const result = await dispatcher.rpcManager.performCall(serviceName, [], { target }); const delay = dispatcher.connectivityManager.now; const ping = delay - start; return { ping, ...result, }; }; logger.info("Adding 'pingAll' service!"); // Function to Ping all Services const pingAll = async () => { const dispatchers = Array.from(dispatcher.rpcManager.services.keyMappingReverse.get(serviceName)); const promises = dispatchers.map((target) => { return determinePing(target); }); const pings = await Promise.all(promises); const avg = (0, arrayMethods_1.avgOfArray)(pings, "ping"); const max = (0, arrayMethods_1.maxOfArray)(pings, "ping"); const min = (0, arrayMethods_1.minOfArray)(pings, "ping"); return { pings, avg, max, min, }; }; return { determinePing, pingAll, }; } exports.generatePingAccessors = generatePingAccessors; /** * Registers a sync service, which will syncronize the time * * @author M.Karkowski * @export * @param {INopeDispatcher} dispatcher * @return {*} The Sync-Method to call */ async function enableTimeSyncing(dispatcher) { if (!dispatcher.rpcManager.isProviding(`nope/baseService/ping`)) { await generatePingServices(dispatcher); } const determinePing = (await generatePingAccessors(dispatcher)).determinePing; // Function to determine the ping in the services. const manualSyncTime = async () => { const masterId = dispatcher.connectivityManager.master.id; const ping = await determinePing(masterId); // Now use the delay to synchronize the time. dispatcher.connectivityManager.syncTime(ping.timestamp, ping.ping / 2); }; dispatcher.connectivityManager.dispatchers.onChange.subscribe((changes) => { if (dispatcher.disposing) { return; } if (!dispatcher.connectivityManager.isMaster) { manualSyncTime() .catch((e) => { logger.error("Failed synchronizing time"); logger.error(e); }) .then((_) => { logger.info(`Synchronized time with master=${dispatcher.connectivityManager.master.id}`); }); } }); logger.info("Adding 'manualSyncTime' service!"); return { manualSyncTime, }; } exports.enableTimeSyncing = enableTimeSyncing; /** * Helper, that lets enables waiting for a required dispatcher. * * @author M.Karkowski * @export * @param {INopeDispatcher} dispatcher * @return {*} */ async function waitForDispatcher(dispatcher, name) { dispatcher.ready.getter = (value) => { return (dispatcher.connectivityManager.dispatchers.data .getContent() .includes(name) && value); }; return {}; } exports.waitForDispatcher = waitForDispatcher; /** * A Helper to create a Service to manually define a master. * * @author M.Karkowski * @export * @param {INopeDispatcher} dispatcher The Dispatcher to use. * @return {*} */ async function generateDefineMaster(dispatcher) { /** * Create a Ping service. * * @author M.Karkowski * @param {string} requestId * @return {*} */ const defineAsMaster = async (value = true) => { dispatcher.connectivityManager.isMaster = value; }; // Registers the Ping Method at the Dispatcher. await dispatcher.rpcManager.registerService(defineAsMaster, { id: `nope/baseService/defineAsMaster`, schema: { description: "Defines the desired Node as Master. Propagets, that this system is a master", inputs: [ { name: "value", optional: true, schema: { type: "boolean", }, }, ], outputs: [], }, }); const setMaster = async () => { // Set the Master to True dispatcher.connectivityManager.isMaster = true; // Get the Master ID const masterId = dispatcher.id; const service = `nope/baseService/defineAsMaster`; // Get the Matching Dispatchers. const relevantDispatchers = dispatcher.rpcManager.services.keyMappingReverse.get(`nope/baseService/defineAsMaster`); relevantDispatchers.delete(masterId); const targets = Array.from(relevantDispatchers); await dispatcher.rpcManager.performCall(targets.map((_) => { return service; }), [false], targets.map((target) => { return { target, timeout: 200 }; })); }; logger.info("Adding 'setMaster' service!"); return { setMaster, }; } exports.generateDefineMaster = generateDefineMaster;