UNPKG

mythtv-event-emitter

Version:
259 lines 9.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.disconnectMythProto = exports.monitorEvents = void 0; const net_1 = require("net"); const lodash_1 = require("lodash"); const events_1 = require("./events"); const events_2 = require("events"); const messages_1 = require("./messages"); const moment = require("moment"); class DoneMessage { constructMessage() { return 'DONE'; } } class AbstractMessageConstructor { constructMessage() { return this.constructMessageParts().join(' '); } } class MythProtoVersionMessage extends AbstractMessageConstructor { constructor(version) { super(); this.version = version ? version : MythProtoVersionMessage.protocolVersions.entries().next().value[0]; } static get protocolVersions() { if (this._protocolVersions.size == 0) { this._protocolVersions.set(91, 'BuzzOff'); this._protocolVersions.set(90, 'BuzzCut'); this._protocolVersions.set(89, 'BuzzKill'); this._protocolVersions.set(88, 'XmasGift'); this._protocolVersions.set(85, 'BluePool'); } return this._protocolVersions; } constructMessageParts() { const token = MythProtoVersionMessage.protocolVersions.get(this.version); if (token != undefined) { return ['MYTH_PROTO_VERSION', this.version, token]; } else { throw new Error('Unsupported proto version ' + this.version); } } } MythProtoVersionMessage._protocolVersions = new Map(); var EventMode; (function (EventMode) { EventMode[EventMode["NO_EVENT"] = 0] = "NO_EVENT"; EventMode[EventMode["ALL_EVENTS"] = 1] = "ALL_EVENTS"; EventMode[EventMode["NO_SYSTEM_EVENT"] = 2] = "NO_SYSTEM_EVENT"; EventMode[EventMode["ONLY_SYSTEM_EVENT"] = 3] = "ONLY_SYSTEM_EVENT"; })(EventMode || (EventMode = {})); class AnnMonitorMessage extends AbstractMessageConstructor { constructor(hostname, eventMode) { super(); this.hostname = hostname; this.eventMode = eventMode; } constructMessageParts() { return ['ANN', 'Monitor', this.hostname, this.eventMode]; } } class RejectMessageHandler { constructor() { this.messageType = 'REJECT'; } process(client, message) { client.connectEmitter.emit('REJECT', Number(message[1])); } } class AcceptMessageHandler { constructor() { this.messageType = 'ACCEPT'; } process(client, message) { client.connectEmitter.emit('ACCEPT', Number(message[1])); } } class BackendMessageHandler { constructor() { this.messageType = "BACKEND_MESSAGE"; this.dataSuffixes = ['UTC', 'ISO', 'ISOUTC']; } addDateFields(fieldName, notificationMessage) { const dateValue = new Date(notificationMessage[fieldName]); this.dataSuffixes.forEach(suffix => { notificationMessage[fieldName + suffix] = dateValue; }); notificationMessage[fieldName] = dateValue; } process(client, message) { const eventMessage = message[1].split(' '); const notificationMessage = {}; for (let i = 0; i < eventMessage.length; i += 2) { const key = eventMessage[i]; const value = eventMessage[i + 1]; notificationMessage[key] = value; if (messages_1.dateFields.indexOf(key) >= 0) { this.addDateFields(key, notificationMessage); } else if (key == 'ORIGINALAIRDATE') { notificationMessage[key] = moment(value, 'YYYY-MM-DD').toDate(); } } const eventType = notificationMessage['SYSTEM_EVENT']; const sender = notificationMessage['SENDER']; notificationMessage['EVENTNAME'] = eventType; events_1.notifyEvent(eventType, sender, notificationMessage); } } class OkMessageHandler { constructor() { this.messageType = "OK"; } process(client, message) { client.connectEmitter.emit('OK'); } } class MythProtocolClient { constructor(host, port) { this.messageHandlers = new Map(); this.connectEmitter = new events_2.EventEmitter(); this.messageHandlers.set('ACCEPT', new AcceptMessageHandler()); this.messageHandlers.set('BACKEND_MESSAGE', new BackendMessageHandler()); this.messageHandlers.set('OK', new OkMessageHandler()); this.messageHandlers.set('REJECT', new RejectMessageHandler()); if (!port) { port = 6543; } this.options = { port: port, host: host, timeout: 3 }; } get connection() { if (!this._connection) { const lConnection = net_1.createConnection(this.options, () => { lConnection.on('data', (data) => { let msgEnd = 0; while (msgEnd < data.length) { msgEnd = this.readMessage(data, msgEnd); } }); lConnection.on('close', (had_error) => { console.log('close backend connection'); this._connection = undefined; if (had_error) { this.connectEmitter.emit('error', new Error('Connection Error')); } else { this.connectEmitter.emit('close'); } }); }); this._connection = lConnection; } return this._connection; } createBackendMessage(message) { const msgLen = message.length; const msgPrefix = lodash_1.padEnd(msgLen.toString(), 8); return msgPrefix + message; } readMessage(data, start) { const msgLenEnd = start + 8; const msgLen = Number(data.toString(MythProtocolClient.LOCALE, start, msgLenEnd)); const msgEnd = msgLenEnd + msgLen; const message = data.toString(MythProtocolClient.LOCALE, msgLenEnd, msgEnd); const messageParts = message.split(MythProtocolClient.LIST_DELIMITER); const messageHandler = this.messageHandlers.get(messageParts[0]); if (messageHandler) { try { messageHandler.process(this, messageParts); } catch (err) { this.connectEmitter.emit('error', err); } } else { console.log('No handler found for message %s', message); } return msgEnd; } sendMessage(message) { try { const backendMessage = this.createBackendMessage(message.constructMessage()); this.connection.write(backendMessage); } catch (err) { this.connectEmitter.emit('error', err); } } disconnect() { if (this._connection) { return new Promise((resolve, reject) => { this.connectEmitter.once('close', () => { resolve(); }); this.sendMessage(new DoneMessage()); }); } else { return Promise.resolve(); } } createList(args) { return args.join(MythProtocolClient.LIST_DELIMITER); } connectClient() { return new Promise((resolve, reject) => { this.connectEmitter.once('ACCEPT', (version) => { this.connectEmitter.removeAllListeners(); resolve(version); }); this.connectEmitter.once('REJECT', (version) => { this.connectEmitter.once('close', () => { this.sendMessage(new MythProtoVersionMessage(version)); }); }); this.connectEmitter.once('error', (err) => { reject(err); }); this.sendMessage(new MythProtoVersionMessage()); }); } async monitor(monitorHostName, eventMode) { await this.connectClient(); return new Promise((resolve, reject) => { this.connectEmitter.on('OK', () => { console.log('Monitor mythbacked using host %s', monitorHostName); resolve(); }); this.connectEmitter.once('error', (err) => { reject(err); }); this.sendMessage(new AnnMonitorMessage(monitorHostName, eventMode)); }); } } MythProtocolClient.LOCALE = 'utf-8'; MythProtocolClient.LIST_DELIMITER = '[]:[]'; let client; async function monitorEvents(monitorHostName, backendHostName, host, port) { client = new MythProtocolClient(host, port); await client.monitor(monitorHostName, EventMode.ONLY_SYSTEM_EVENT); const mythEventEmitter = events_1.mythNotifier.hostEmitter(backendHostName); mythEventEmitter.on('MASTER_STARTED', async (message) => { await client.monitor(monitorHostName, EventMode.ONLY_SYSTEM_EVENT); }); } exports.monitorEvents = monitorEvents; async function disconnectMythProto() { if (client) { await client.disconnect(); } } exports.disconnectMythProto = disconnectMythProto; //# sourceMappingURL=mythProtocol.js.map