/* _ __ _ __ | | / /___ _(_) /____ | | /| / / __ `/ / / ___/ | |/ |/ / /_/ / / (__ ) |__/|__/\__,_/_/_/____/ The lightweight framework for web-like apps (c) Lea Anthony 2019-present */ /* jshint esversion: 6 */ import { Error } from './log'; import { SendMessage } from 'ipc'; // Defines a single listener with a maximum number of times to callback /** * The Listener class defines a listener! :-) * * @class Listener */ class Listener { /** * Creates an instance of Listener. * @param {function} callback * @param {number} maxCallbacks * @memberof Listener */ constructor(callback, maxCallbacks) { // Default of -1 means infinite maxCallbacks = maxCallbacks || -1; // Callback invokes the callback with the given data // Returns true if this listener should be destroyed this.Callback = (data) => { callback.apply(null, data); // If maxCallbacks is infinite, return false (do not destroy) if (maxCallbacks === -1) { return false; } // Decrement maxCallbacks. Return true if now 0, otherwise false maxCallbacks -= 1; return maxCallbacks === 0; }; } } var eventListeners = {}; /** * Registers an event listener that will be invoked `maxCallbacks` times before being destroyed * * @export * @param {string} eventName * @param {function} callback * @param {number} maxCallbacks */ export function OnMultiple(eventName, callback, maxCallbacks) { eventListeners[eventName] = eventListeners[eventName] || []; const thisListener = new Listener(callback, maxCallbacks); console.log('Pushing event listener: ' + eventName); eventListeners[eventName].push(thisListener); } /** * Registers an event listener that will be invoked every time the event is emitted * * @export * @param {string} eventName * @param {function} callback */ export function On(eventName, callback) { OnMultiple(eventName, callback); } /** * Registers an event listener that will be invoked once then destroyed * * @export * @param {string} eventName * @param {function} callback */ export function Once(eventName, callback) { OnMultiple(eventName, callback, 1); } /** * Notify informs frontend listeners that an event was emitted with the given data * * @export * @param {string} encoded notification message */ export function Notify(notifyMessage) { // Parse the message var message; try { message = JSON.parse(notifyMessage); } catch (e) { const error = 'Invalid JSON passed to Notify: ' + notifyMessage; throw new Error(error); } var eventName = message.name; // Check if we have any listeners for this event if (eventListeners[eventName]) { // Keep a list of listener indexes to destroy const newEventListenerList = eventListeners[eventName].slice(); // Iterate listeners for (let count = 0; count < eventListeners[eventName].length; count += 1) { // Get next listener const listener = eventListeners[eventName][count]; var data = message.data; // Do the callback const destroy = listener.Callback(data); if (destroy) { // if the listener indicated to destroy itself, add it to the destroy list newEventListenerList.splice(count, 1); } } // Update callbacks with new list of listners eventListeners[eventName] = newEventListenerList; } } /** * Emit an event with the given name and data * * @export * @param {string} eventName */ export function Emit(eventName) { // Calculate the data if (arguments.length > 1) { // Notify backend const payload = { name: eventName, data: [].slice.apply(arguments).slice(1), }; SendMessage('Ej' + JSON.stringify(payload)); } else { SendMessage('ej' + eventName); } } // Callbacks for the heartbeat calls const heartbeatCallbacks = {}; /** * Heartbeat emits the event `eventName`, every `timeInMilliseconds` milliseconds until * the event is acknowledged via `Event.Acknowledge`. Once this happens, `callback` is invoked ONCE * * @export * @param {string} eventName * @param {number} timeInMilliseconds * @param {function} callback */ export function Heartbeat(eventName, timeInMilliseconds, callback) { // Declare interval variable let interval = null; // Setup callback function dynamicCallback() { // Kill interval clearInterval(interval); // Callback callback(); } // Register callback heartbeatCallbacks[eventName] = dynamicCallback; // Start emitting the event interval = setInterval(function () { Emit(eventName); }, timeInMilliseconds); } /** * Acknowledges a heartbeat event by name * * @export * @param {string} eventName */ export function Acknowledge(eventName) { // If we are waiting for acknowledgement for this event type if (heartbeatCallbacks[eventName]) { // Acknowledge! heartbeatCallbacks[eventName](); } else { throw new Error(`Cannot acknowledge unknown heartbeat '${eventName}'`); } }