mcopy/app/lib/sequencer/index.js

245 lines
7.0 KiB
JavaScript

'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.Sequencer = void 0;
const electron_1 = require("electron");
const log_1 = require("log");
const delay_1 = require("delay");
let seq;
/** @module lib/sequencer */
/**
* Class representing all sequencer features.
*/
class Sequencer {
/**
* @constructor
* Create a new sequencer and assign command and UI as private sub-classes
*
* @param {object} cfg Configuration object
* @param {object} cmd Shared command class
* @param {object} ui Electron UI, browser window
**/
constructor(cfg, cmd, ui) {
this.running = false;
this.paused = false;
this.grid = [];
this.gridLoops = 1;
this.arr = []; //store sequence from gui
this.loops = 1;
this.CMDS = {};
this.ipc = electron_1.ipcMain;
this.id = 'sequence';
this.alerted = false;
this.cfg = cfg;
this.cmd = cmd;
this.ui = ui;
this.cmds(cfg.cmd);
this.init();
}
/**
* Take configuration object and assign all commands as keys
* in the internal CMDS object.
*
* @param {object} obj Configuration object
**/
cmds(obj) {
let keys = Object.keys(obj);
for (let key of keys) {
this.CMDS[obj[key]] = key;
}
}
/**
* Initialize the class by requiring ipcMain from electron
* and creating logger.
*
**/
async init() {
this.log = await (0, log_1.Log)({ label: this.id });
this.listen();
}
/**
* Bind ipc listener to channel 'sequencer' or current id of
* class.
**/
listen() {
this.ipc.on(this.id, this.listener.bind(this));
}
/**
* Listener callback function. Called whenever ipc
* message is sent to channel 'sequencer'.
*
* @param {object} event IPC message event
* @param {object} arg Arguments provided in message
**/
async listener(event, arg) {
if (arg && arg.start) {
this.start(arg);
}
else if (arg && arg.stop) {
this.stop();
}
else if (arg && arg.pause) {
this.pause();
}
else if (arg && arg.set) {
this.setSteps(arg.set);
}
else if (arg && arg.unset) {
this.unsetSteps(arg.unset);
}
else if (arg && arg.loops) {
this.setLoops(arg.loops);
}
event.returnValue = true;
}
/**
* Sets the value of the loops in the grid sequence
* to value sent by UI in ipc message.
*
* @param {integer} count Number of loops to set grid sequence to
**/
setLoops(count) {
this.gridLoops = count;
this.log.info(`Set loop count to ${count}`);
}
/**
* Sets multiple steps at once
*
* @param {array} steps Array of steps to set or update
**/
setSteps(steps) {
for (let step of steps) {
this.grid[step.x] = step;
}
}
/**
* Resets multiple steps to default 'undefined' state
*
* @param {array} steps Array containing the x location of steps to unset
**/
unsetSteps(steps) {
for (let x of steps) {
this.grid[x] = undefined;
}
}
/**
* Starts a sequence with the existing grid sequence,
* or if one is provided in the arg object, starts
* that sequence.
*
* @param {object} arg Arguments from ipc message
**/
async start(arg) {
const psbId = electron_1.powerSaveBlocker.start('prevent-display-sleep');
let startTime = +new Date();
let ms;
if (arg && arg.arr) {
this.arr = arg.arr; //overwrite sequence
}
else {
this.arr = this.grid;
}
if (arg && arg.loops) {
this.loops = arg.loops; //overwrite loops
}
else {
this.loops = this.gridLoops;
}
this.running = true;
this.paused = false;
//start sequence
this.log.info(`Starting sequence...`);
this.ui.send(this.id, { start: true });
if (this.cmd.proj.filmout.state.enabled === true && !this.cmd.proj.filmout.server.useServer()) {
await this.cmd.proj.filmout.display.open();
}
for (let x = 0; x < this.loops; x++) {
//start loop
this.log.info(`Starting loop ${x + 1}`);
this.ui.send(this.id, { loop: x, start: true });
for (let y = 0; y < this.arr.length; y++) {
//start step
if (!this.running) {
break;
}
//UI initiates pause, not planned
while (this.paused) {
await (0, delay_1.delay)(42);
}
if (typeof this.arr[y] === 'undefined') {
continue;
}
this.log.info(`Starting step ${y + 1} of loop ${x + 1}`);
this.ui.send(this.id, { step: y, loop: x, start: true });
await this.step(y);
//end step
this.log.info(`Ended step ${y + 1} of loop ${x + 1}`);
this.ui.send(this.id, { step: y, loop: x, stop: true });
}
if (!this.running) {
break;
}
//end loop
this.log.info(`Ended loop ${x + 1}`);
this.ui.send(this.id, { loop: x, stop: true });
}
if (this.cmd.proj.filmout.state.enabled === true && !this.cmd.proj.filmout.server.useServer()) {
await this.cmd.proj.filmout.display.close();
}
electron_1.powerSaveBlocker.stop(psbId);
this.psbId = null;
ms = (+new Date()) - startTime;
//end sequence
this.log.info(`Ended sequence`);
this.ui.send(this.id, { stop: true, ms });
}
/**
* Pauses sequence from UI.
**/
pause() {
this.paused = true;
}
/**
* Stops the sequence
**/
stop() {
if (this.cmd.proj.filmout.state.enabled === true) {
this.cmd.proj.filmout.display.close();
}
this.running = false;
if (this.psbId) {
electron_1.powerSaveBlocker.stop(this.psbId);
}
//clear?
}
/**
* Execute command @ step x. Wrapper with try catch.
*
* @param {integer} x Step to execute command at
**/
async step(x) {
try {
await this.cmdExec(x);
}
catch (err) {
throw err;
}
}
/**
* Locate step @ position x and execute the command.
*
* @param {integer} x Step to execute command at
**/
async cmdExec(x) {
const cmdOriginal = this.arr[x].cmd;
const cmd = this.CMDS[cmdOriginal];
this.log.info(`CMD: '${cmdOriginal}' -> ${cmd}`);
//@ts-ignore
return await this.cmd[cmd](this.arr[x]);
}
isRunning() {
return this.running;
}
}
exports.Sequencer = Sequencer;
module.exports = { Sequencer };
//# sourceMappingURL=index.js.map