node-routeros-altostrat
Version:
Mikrotik Routerboard RouterOS API for NodeJS
212 lines • 12.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const events_1 = require("events");
const RosException_1 = require("./RosException");
const debug = require("debug");
const info = debug('routeros-api:channel:info');
const error = debug('routeros-api:channel:error');
/**
* Channel class is responsible for generating
* ids for the channels and writing over
* the ids generated, while listening for
* their responses
*/
class Channel extends events_1.EventEmitter {
/**
* Constructor
*
* @param {Connector} connector
*/
constructor(connector) {
super();
/**
* Data received related to the channel
*/
this.data = [];
/**
* If received a trap instead of a positive response
*/
this.trapped = false;
/**
* If is streaming content
*/
this.streaming = false;
/**
* Timeout for streaming operations to wait for delayed responses
*/
this.streamingTimeout = null;
/**
* Delay in milliseconds to wait for streaming responses (configurable)
*/
this.streamingDelay = 5000;
this.id = Math.random().toString(36).substring(3);
this.connector = connector;
this.once('unknown', this.onUnknown.bind(this));
}
/**
* Get the id of the channel
*
* @returns {string}
*/
get Id() {
return this.id;
}
/**
* Get the connector used in the channel
*
* @returns {Connector}
*/
get Connector() {
return this.connector;
}
/**
* Set the streaming delay for this channel
*
* @param {number} delay - delay in milliseconds
*/
setStreamingDelay(delay) {
this.streamingDelay = delay;
}
/**
* Organize the data to be written over the socket with the id
* generated. Adds a reader to the id provided, so we wait for
* the data.
*
* @param {Array} params
* @returns {Promise}
*/
write(params, isStream = false, returnPromise = true) {
this.streaming = isStream;
params.push('.tag=' + this.id);
if (returnPromise) {
this.on('data', (packet) => this.data.push(packet));
return new Promise((resolve, reject) => {
this.once('done', (data) => resolve(data));
this.once('trap', (data) => reject(new Error(data.message)));
this.readAndWrite(params);
});
}
this.readAndWrite(params);
return;
}
/**
* Closes the channel, algo asking for
* the connector to remove the reader.
* If streaming, not forcing will only stop
* the reader, not the listeners of the events
*
* @param {boolean} force - force closing by removing all listeners
*/
close(force = false) {
// Clear any pending streaming timeout
if (this.streamingTimeout) {
clearTimeout(this.streamingTimeout);
this.streamingTimeout = null;
}
this.emit('close');
// First unregister the tag reader to prevent any unregistered tag issues
this.connector.stopRead(this.id);
if (!this.streaming || force) {
this.removeAllListeners();
}
}
/**
* Register the reader for the tag and write the params over
* the socket
*
* @param {Array} params
*/
readAndWrite(params) {
this.connector.read(this.id, (packet) => this.processPacket(packet));
this.connector.write(params);
}
/**
* Process the data packet received to
* figure out the answer to give to the
* channel listener, either if it's just
* the data we were expecting or if
* a trap was given.
*
* @param {Array} packet
*/
processPacket(packet) {
const reply = packet.shift();
info('Processing reply %s with data %o', reply, packet);
const parsed = this.parsePacket(packet);
if (reply === '!trap') {
this.trapped = true;
this.emit('trap', parsed);
return;
}
if (packet.length > 0 && !this.streaming)
this.emit('data', parsed);
switch (reply) {
case '!re':
if (this.streaming)
this.emit('stream', parsed);
break;
case '!done':
if (!this.trapped)
this.emit('done', this.data);
this.close();
break;
case '!empty':
if (!this.trapped) {
this.emit('empty', parsed); // Pass parsed data to empty event
}
// For streaming operations, wait a bit longer before closing
// to handle delayed responses that might come after !empty
if (this.streaming) {
info('Streaming operation received !empty, waiting %dms for potential delayed responses', this.streamingDelay);
this.streamingTimeout = setTimeout(() => {
info('Streaming delay timeout reached, closing channel');
if (!this.trapped) {
this.emit('done', this.data);
}
this.close();
}, this.streamingDelay);
}
else {
if (!this.trapped) {
this.emit('done', []); // Emit 'done' with empty array for non-streaming
}
this.close();
}
break;
default:
this.emit('unknown', reply);
this.close();
break;
}
}
/**
* Parse the packet line, separating the key from the data.
* Ex: transform '=interface=ether2' into object {interface:'ether2'}
*
* @param {Array} packet
* @return {Object}
*/
parsePacket(packet) {
const obj = {};
for (const line of packet) {
const linePair = line.split('=');
linePair.shift(); // remove empty index
obj[linePair.shift()] = linePair.join('=');
}
info('Parsed line, got %o as result', obj);
return obj;
}
/**
* Waits for the unknown event.
* It shouldn't happen, but if it does, throws the error and
* stops the channel
*
* @param {string} reply
* @returns {function}
*/
onUnknown(reply) {
throw new RosException_1.RosException('UNKNOWNREPLY', { reply: reply });
}
}
exports.Channel = Channel;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhbm5lbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9DaGFubmVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBQXNDO0FBRXRDLGlEQUE4QztBQUM5QywrQkFBK0I7QUFHL0IsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7QUFDaEQsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7QUFFbEQ7Ozs7O0dBS0c7QUFDSCxNQUFhLE9BQVEsU0FBUSxxQkFBWTtJQW9DckM7Ozs7T0FJRztJQUNILFlBQVksU0FBb0I7UUFDNUIsS0FBSyxFQUFFLENBQUM7UUEvQlo7O1dBRUc7UUFDSSxTQUFJLEdBQVUsRUFBRSxDQUFDO1FBRXhCOztXQUVHO1FBQ0ksWUFBTyxHQUFZLEtBQUssQ0FBQztRQUVoQzs7V0FFRztRQUNJLGNBQVMsR0FBWSxLQUFLLENBQUM7UUFFbEM7O1dBRUc7UUFDSyxxQkFBZ0IsR0FBMEIsSUFBSSxDQUFDO1FBRXZEOztXQUVHO1FBQ0ssbUJBQWMsR0FBVyxJQUFJLENBQUM7UUFTbEMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsSUFBSSxFQUFFO1FBQ0YsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ25CLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsSUFBSSxTQUFTO1FBQ1QsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQzFCLENBQUM7SUFFRDs7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