timeline-state-resolver
Version:
Have timeline, control stuff
218 lines • 8.47 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeviceInstanceWrapper = void 0;
const EventEmitter = require("eventemitter3");
const lib_1 = require("../lib");
const stateHandler_1 = require("./stateHandler");
const devices_1 = require("./devices");
/**
* Top level container for setting up and interacting with any device integrations
*/
class DeviceInstanceWrapper extends EventEmitter {
constructor(id, time, config, getRemoteCurrentTime) {
super();
this.config = config;
this.getRemoteCurrentTime = getRemoteCurrentTime;
this._isActive = false;
this._logDebug = false;
this._logDebugStates = false;
const deviceSpecs = devices_1.DevicesDict[config.type];
if (!deviceSpecs) {
throw new Error('Could not find device of type ' + config.type);
}
this._device = new deviceSpecs.deviceClass(this._getDeviceContextAPI());
this._deviceId = id;
this._deviceType = config.type;
this._deviceName = deviceSpecs.deviceName(id, config);
this._instanceId = Math.floor(Math.random() * 10000);
this._startTime = time;
this._updateTimeSync();
this._stateHandler = new stateHandler_1.StateHandler({
deviceId: id,
logger: {
debug: (...args) => this.emit('debug', ...args),
info: (info) => this.emit('info', info),
warn: (warn) => this.emit('warning', warn),
error: (context, e) => this.emit('error', context, e),
},
emitTimeTrace: (trace) => this.emit('timeTrace', trace),
reportStateChangeMeasurement: (report) => {
report.commands.forEach((cReport) => {
if (cReport.executeDelay && cReport.executeDelay > (this.config.limitSlowSentCommand || 40)) {
this.emit('slowSentCommand', {
added: report.added,
prepareTime: 0,
plannedSend: report.scheduled,
send: report.executed || 0,
queueId: '',
args: cReport.args,
sendDelay: cReport.executeDelay,
addedDelay: 0,
internalDelay: 0,
});
}
if (cReport.fulfilledDelay && cReport.fulfilledDelay > (this.config.limitSlowFulfilledCommand || 100)) {
this.emit('slowFulfilledCommand', {
added: report.added,
prepareTime: 0,
plannedSend: report.scheduled,
send: report.executed || 0,
queueId: '',
args: cReport.args,
fullfilled: cReport.fulfilled || 0,
fulfilledDelay: cReport.fulfilledDelay,
});
}
this.emit('commandReport', {
plannedSend: report.scheduled,
queueId: '',
added: report.added,
prepareTime: 0,
send: cReport.executed,
fullfilled: cReport.fulfilled || 0,
args: cReport.args,
});
});
},
getCurrentTime: () => this.getCurrentTime(),
}, {
executionType: deviceSpecs.executionMode(config.options),
}, this._device);
}
async initDevice(_activeRundownPlaylistId) {
return this._device.init(this.config.options);
}
async terminate() {
await this._stateHandler.terminate();
return this._device.terminate();
}
async executeAction(id, payload) {
const action = this._device.actions[id];
if (!action) {
return (0, lib_1.actionNotFoundMessage)(id);
}
return action(id, payload);
}
async makeReady(okToDestroyStuff) {
return this._device.makeReady(okToDestroyStuff);
}
async standDown() {
if (this._device.standDown) {
return this._device.standDown();
}
}
/** @deprecated - just here for API compatiblity with the old class */
prepareForHandleState() {
//
}
handleState(newState, newMappings) {
this._stateHandler.handleState(newState, newMappings).catch((e) => {
this.emit('error', 'Error while handling state', e);
});
this._isActive = Object.keys(newMappings).length > 0;
}
clearFuture(t) {
this._stateHandler.clearFutureAfterTimestamp(t);
}
getDetails() {
return {
deviceId: this._deviceId,
deviceType: this._deviceType,
deviceName: this._deviceName,
instanceId: this._instanceId,
startTime: this._startTime,
supportsExpectedPlayoutItems: false,
canConnect: devices_1.DevicesDict[this.config.type].canConnect,
};
}
handleExpectedPlayoutItems(_expectedPlayoutItems) {
// do nothing yet, as this isn't implemented.
}
getStatus() {
return { ...this._device.getStatus(), active: this._isActive };
}
setDebugLogging(value) {
this._logDebug = value;
}
setDebugState(value) {
this._logDebugStates = value;
}
getCurrentTime() {
if (!this._lastUpdateCurrentTime ||
this._tDiff === undefined ||
Date.now() - this._lastUpdateCurrentTime > 5 * 60 * 1000) {
this._updateTimeSync();
}
return Date.now() + (this._tDiff ?? 0);
}
_getDeviceContextAPI() {
return {
logger: {
error: (context, err) => {
this.emit('error', context, err);
},
warning: (warning) => {
this.emit('warning', warning);
},
info: (info) => {
this.emit('info', info);
},
debug: (...debug) => {
if (this._logDebug)
this.emit('debug', ...debug);
},
},
getCurrentTime: () => this.getCurrentTime(),
emitDebugState: (state) => {
if (this._logDebugStates) {
this.emit('debugState', state);
}
},
connectionChanged: (status) => {
this.emit('connectionChanged', {
...status,
active: this._isActive,
});
},
resetResolver: () => {
this.emit('resetResolver');
},
commandError: (error, context) => {
this.emit('commandError', error, context);
},
updateMediaObject: (collectionId, docId, doc) => {
this.emit('updateMediaObject', collectionId, docId, doc);
},
clearMediaObjects: (collectionId) => {
this.emit('clearMediaObjects', collectionId);
},
timeTrace: (trace) => {
this.emit('timeTrace', trace);
},
resetState: async () => {
await this._stateHandler.setCurrentState(undefined);
await this._stateHandler.clearFutureStates();
this.emit('resyncStates');
},
resetToState: async (state) => {
await this._stateHandler.setCurrentState(state);
await this._stateHandler.clearFutureStates();
this.emit('resyncStates');
},
};
}
_updateTimeSync() {
this._lastUpdateCurrentTime = Date.now(); // set this first so we don't update twice at the same time
const start = Date.now();
this.getRemoteCurrentTime()
.then((t) => {
const end = Date.now();
this._tDiff = t - Math.round((start + end) / 2);
})
.catch((e) => {
this.emit('error', 'Error when syncing time', e);
});
}
}
exports.DeviceInstanceWrapper = DeviceInstanceWrapper;
//# sourceMappingURL=DeviceInstance.js.map