timeline-state-resolver
Version:
Have timeline, control stuff
193 lines • 6.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShotokuCommandType = exports.ShotokuAPI = void 0;
const eventemitter3_1 = require("eventemitter3");
const net_1 = require("net");
const TIMEOUT = 3000; // ms
const RETRY_TIMEOUT = 5000; // ms
class ShotokuAPI extends eventemitter3_1.EventEmitter {
constructor() {
super(...arguments);
this._tcpClient = undefined;
this._connected = false;
this._setDisconnected = false; // set to true if disconnect() has been called (then do not trye to reconnect)
}
/**
* Connnects to the OSC server.
* @param host ip to connect to
* @param port port the osc server is hosted on
*/
async connect(host, port) {
this._host = host;
this._port = port;
return this._connectTCPClient();
}
async dispose() {
return this._disconnectTCPClient();
}
get connected() {
return this._connected;
}
async executeCommand(command) {
if ('shot' in command) {
return this.send(command);
}
else {
Object.values(command.shots).forEach((command) => {
setTimeout(() => {
this.send(command).catch(() => this.emit('warn', 'Command from sequence failed...'));
}, command.offset);
});
return Promise.resolve();
}
}
async send(command) {
const codes = {
[ShotokuCommandType.Fade]: 0x01,
[ShotokuCommandType.Cut]: 0x02,
};
let commandCode = codes[command.type];
const show = command.show || 1;
if (command.changeOperatorScreen)
commandCode += 0x20;
const cmd = [0xf9, 0x01, commandCode, 0x00, show, command.shot, 0x00, 0x00];
cmd.push(0x40 - cmd.reduce((a, b) => a + b)); // add checksum
return this._sendTCPMessage(Buffer.from(cmd));
}
_setConnected(connected) {
if (this._connected !== connected) {
this._connected = connected;
if (!connected) {
this.emit('disconnected');
this._triggerRetryConnection();
}
else {
this.emit('connected');
}
}
}
_triggerRetryConnection() {
if (!this._retryConnectTimeout) {
this._retryConnectTimeout = setTimeout(() => {
this._retryConnection();
}, RETRY_TIMEOUT);
}
}
_retryConnection() {
if (this._retryConnectTimeout) {
clearTimeout(this._retryConnectTimeout);
this._retryConnectTimeout = undefined;
}
if (!this.connected && !this._setDisconnected) {
this._connectTCPClient().catch((err) => {
this.emit('error', 'reconnect TCP', err);
});
}
}
async _disconnectTCPClient() {
return new Promise((resolve) => {
this._setDisconnected = true;
if (this._tcpClient) {
if (this.connected) {
this._tcpClient.once('close', () => {
resolve();
});
this._tcpClient.once('end', () => {
resolve();
});
this._tcpClient.end();
setTimeout(() => {
resolve();
}, TIMEOUT);
setTimeout(() => {
if (this._tcpClient && this.connected) {
// Forcefully destroy the connection:
this._tcpClient.destroy();
}
}, Math.floor(TIMEOUT / 2));
}
else {
resolve();
}
}
else {
resolve();
}
}).then(() => {
if (this._tcpClient) {
this._tcpClient.removeAllListeners('connect');
this._tcpClient.removeAllListeners('close');
this._tcpClient.removeAllListeners('end');
this._tcpClient.removeAllListeners('error');
this._tcpClient = undefined;
}
this._setConnected(false);
});
}
async _connectTCPClient() {
this._setDisconnected = false;
if (!this._tcpClient) {
this._tcpClient = new net_1.Socket();
this._tcpClient.on('connect', () => {
this._setConnected(true);
});
this._tcpClient.on('close', () => {
this._setConnected(false);
delete this._tcpClient;
});
this._tcpClient.on('end', () => {
this._setConnected(false);
delete this._tcpClient;
});
this._tcpClient.on('error', (e) => {
if (e.message.match(/econn/i)) {
// disconnection
this._setConnected(false);
}
else {
this.emit('error', 'TCP socket', e);
}
});
}
if (!this.connected) {
return new Promise((resolve, reject) => {
if (!this._host || !this._port) {
reject(new Error('Missing host or port'));
return;
}
let resolved = false;
this._tcpClient.connect(this._port, this._host, () => {
resolve();
resolved = true;
// client.write('Hello, server! Love, Client.');
});
setTimeout(() => {
reject(new Error(`TCP timeout: Unable to connect to ${this._host}:${this._port}`));
this._triggerRetryConnection();
if (!resolved && this._tcpClient) {
this._tcpClient.destroy();
delete this._tcpClient;
}
}, TIMEOUT);
});
}
else {
return Promise.resolve();
}
}
async _sendTCPMessage(message) {
// Do we have a client?
if (this._tcpClient) {
this._tcpClient.write(message);
}
else
throw Error('_shotokuAPI: _tcpClient is falsy!');
}
}
exports.ShotokuAPI = ShotokuAPI;
var ShotokuCommandType;
(function (ShotokuCommandType) {
ShotokuCommandType["Cut"] = "cut";
ShotokuCommandType["Fade"] = "fade";
})(ShotokuCommandType = exports.ShotokuCommandType || (exports.ShotokuCommandType = {}));
//# sourceMappingURL=connection.js.map