@fibercom/routeros-api
Version:
Robust MikroTik RouterOS API client for Node.js and TypeScript
203 lines • 16.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RStream = void 0;
const events_1 = require("events");
const Channel_1 = require("./Channel");
const RosException_1 = require("./RosException");
const timers_1 = require("timers");
const utils_1 = require("./utils");
/**
* RStream is used for handling continuous or long-lived data streams
* from RouterOS, such as `/tool/torch`, `/ip/address/listen`, etc.
* It can be paused, resumed, or stopped gracefully.
*/
class RStream extends events_1.EventEmitter {
constructor(channel, params, callback) {
super();
this.shouldDebounceEmptyData = false;
this.streaming = true;
this.pausing = false;
this.paused = false;
this.stopping = false;
this.stopped = false;
this.trapped = false;
this.currentSection = null;
this.forcelyStop = false;
this.currentSectionPacket = [];
this.channel = channel;
this.params = params;
this.callback = callback;
}
data(callback) {
if (this.streaming) {
console.warn("Replacing callback mid-stream. Use with caution.");
}
this.callback = callback;
}
resume() {
if (this.stopped || this.stopping)
return Promise.reject(new RosException_1.RosException("STREAMCLOSD"));
if (!this.streaming) {
this.pausing = false;
if (!this.channel)
return Promise.reject(new RosException_1.RosException("STREAMCLOSD"));
this.start();
this.streaming = true;
}
return Promise.resolve();
}
pause() {
if (this.stopped || this.stopping)
return Promise.reject(new RosException_1.RosException("STREAMCLOSD"));
if (this.pausing || this.paused)
return Promise.resolve();
if (this.streaming) {
this.pausing = true;
return this.stop(true)
.then(() => {
this.pausing = false;
this.paused = true;
})
.catch((err) => {
this.pausing = false;
return Promise.reject(err);
});
}
return Promise.resolve();
}
stop(pausing = false) {
if (this.stopped || this.stopping)
return Promise.resolve();
if (!pausing)
this.forcelyStop = true;
if (this.paused) {
this.streaming = false;
this.stopping = false;
this.stopped = true;
if (this.channel)
this.channel.close(true);
return Promise.resolve();
}
if (!this.pausing)
this.stopping = true;
let chann = new Channel_1.Channel(this.channel.Connector);
chann.on("close", () => (chann = null));
if (this.debounceSendingEmptyData)
this.debounceSendingEmptyData.cancel();
return chann
.write(["/cancel", "=tag=" + this.channel.Id])
.then(() => {
this.streaming = false;
if (!this.pausing) {
this.stopping = false;
this.stopped = true;
}
this.emit("stopped");
})
.catch((err) => {
this.emit("error", new RosException_1.RosException("Cancel failed: " + err.message));
return Promise.reject(err);
});
}
close() {
return this.stop();
}
start() {
if (!this.stopped && !this.stopping) {
this.channel.on("close", () => {
if (this.forcelyStop || (!this.pausing && !this.paused)) {
if (!this.trapped)
this.emit("done");
this.emit("close");
}
this.stopped = false;
});
this.channel.on("stream", (packet) => {
if (this.debounceSendingEmptyData)
this.debounceSendingEmptyData.run();
this.onStream(packet);
});
this.channel.once("trap", this.onTrap.bind(this));
this.channel.once("done", this.onDone.bind(this));
try {
this.channel.write(this.params.slice(), true, false);
}
catch (err) {
this.emit("error", new RosException_1.RosException("Failed to start stream: " + err.message));
return;
}
this.emit("started");
if (this.shouldDebounceEmptyData)
this.prepareDebounceEmptyData();
}
}
prepareDebounceEmptyData() {
this.shouldDebounceEmptyData = true;
const intervalParam = this.params.find((param) => /=interval=/.test(param));
let interval = 2000;
if (intervalParam) {
const val = intervalParam.split("=")[2];
const parsed = parseInt(val, 10);
if (!isNaN(parsed))
interval = parsed * 1000;
}
this.debounceSendingEmptyData = (0, utils_1.debounce)(() => {
if (!this.stopped || !this.stopping || !this.paused || !this.pausing) {
this.onStream([]);
this.debounceSendingEmptyData.run();
}
}, interval + 300);
}
onStream(packet) {
this.emit("data", packet);
if (!this.callback)
return;
try {
if (packet[".section"]) {
(0, timers_1.clearTimeout)(this.sectionPacketSendingTimeout);
const sendData = () => {
this.callback(null, this.currentSectionPacket.slice(), this);
this.currentSectionPacket = [];
};
this.sectionPacketSendingTimeout = (0, timers_1.setTimeout)(sendData.bind(this), 300);
if (this.currentSectionPacket.length > 0 &&
packet[".section"] !== this.currentSection) {
(0, timers_1.clearTimeout)(this.sectionPacketSendingTimeout);
sendData();
}
this.currentSection = packet[".section"];
this.currentSectionPacket.push(packet);
}
else {
this.callback(null, packet, this);
}
}
catch (err) {
this.emit("error", new RosException_1.RosException("Callback processing failed: " + err.message));
}
}
onTrap(data) {
const message = (data === null || data === void 0 ? void 0 : data.message) || "Unknown trap error";
if (message === "interrupted") {
this.streaming = false;
}
else {
this.stopped = true;
this.trapped = true;
if (this.callback) {
this.callback(new Error(message), null, this);
}
else {
this.emit("error", data);
}
this.emit("trap", data);
}
}
onDone() {
if (this.stopped && this.channel) {
this.channel.close(true);
}
}
}
exports.RStream = RStream;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUlN0cmVhbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9SU3RyZWFtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUFzQztBQUN0Qyx1Q0FBb0M7QUFDcEMsaURBQThDO0FBQzlDLG1DQUFrRDtBQUNsRCxtQ0FBbUM7QUFFbkM7Ozs7R0FJRztBQUNILE1BQWEsT0FBUSxTQUFRLHFCQUFZO0lBb0J2QyxZQUNFLE9BQWdCLEVBQ2hCLE1BQWdCLEVBQ2hCLFFBQStEO1FBRS9ELEtBQUssRUFBRSxDQUFDO1FBbkJGLDRCQUF1QixHQUFZLEtBQUssQ0FBQztRQUV6QyxjQUFTLEdBQVksSUFBSSxDQUFDO1FBQzFCLFlBQU8sR0FBWSxLQUFLLENBQUM7UUFDekIsV0FBTSxHQUFZLEtBQUssQ0FBQztRQUN4QixhQUFRLEdBQVksS0FBSyxDQUFDO1FBQzFCLFlBQU8sR0FBWSxLQUFLLENBQUM7UUFDekIsWUFBTyxHQUFZLEtBQUssQ0FBQztRQUV6QixtQkFBYyxHQUFXLElBQUksQ0FBQztRQUM5QixnQkFBVyxHQUFZLEtBQUssQ0FBQztRQUM3Qix5QkFBb0IsR0FBVSxFQUFFLENBQUM7UUFTdkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDM0IsQ0FBQztJQUVNLElBQUksQ0FDVCxRQUE4RDtRQUU5RCxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNuQixPQUFPLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFTSxNQUFNO1FBQ1gsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxRQUFRO1lBQy9CLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FB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