@fibercom/routeros-api
Version:
Robust MikroTik RouterOS API client for Node.js and TypeScript
303 lines • 24.9 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RStream = void 0;
const events_1 = require("events");
const timers_1 = require("timers");
const Channel_1 = require("./Channel");
const RosException_1 = require("./RosException");
const utils_1 = require("./utils");
/**
* Handles continuous RouterOS commands such as `/tool/torch` and listeners.
* A paused stream remains logically open, but receives a fresh tagged channel
* when it is resumed.
*/
class RStream extends events_1.EventEmitter {
constructor(channel, params, callback) {
super();
this.state = "idle";
this.trapped = false;
this.shouldDebounceEmptyData = false;
this.currentSection = null;
this.currentSectionPacket = [];
this.channel = channel;
this.connector = channel.Connector;
this.params = params;
this.callback = callback;
}
data(callback) {
if (this.state === "running") {
console.warn("Replacing callback mid-stream. Use with caution.");
}
this.callback = callback;
}
resume() {
var _a;
if (this.state === "stopped" || this.state === "stopping") {
return Promise.reject(new RosException_1.RosException("STREAMCLOSD"));
}
if (this.state === "pausing") {
return ((_a = this.transition) !== null && _a !== void 0 ? _a : Promise.resolve()).then(() => this.resume());
}
if (this.state !== "paused")
return Promise.resolve();
this.channel = new Channel_1.Channel(this.connector);
this.start();
return Promise.resolve();
}
pause() {
if (this.state === "stopped" || this.state === "stopping") {
return Promise.reject(new RosException_1.RosException("STREAMCLOSD"));
}
if (this.state === "paused" || this.state === "pausing") {
return Promise.resolve();
}
if (this.state !== "running")
return Promise.resolve();
return this.trackTransition(this.cancelActiveChannel(true));
}
stop(pausing = false) {
var _a, _b;
if (pausing)
return this.pause();
if (this.state === "stopped") {
return Promise.resolve();
}
if (this.state === "stopping") {
return (_a = this.transition) !== null && _a !== void 0 ? _a : Promise.resolve();
}
if (this.state === "paused" || this.state === "idle") {
this.finish(false);
return Promise.resolve();
}
if (this.state === "pausing") {
return ((_b = this.transition) !== null && _b !== void 0 ? _b : Promise.resolve()).then(() => this.stop());
}
return this.trackTransition(this.cancelActiveChannel(false));
}
close() {
return this.stop();
}
start() {
if (this.state !== "idle" && this.state !== "paused")
return;
if (!this.channel)
this.channel = new Channel_1.Channel(this.connector);
const activeChannel = this.channel;
this.state = "running";
this.trapped = false;
activeChannel.on("stream", (packet) => {
var _a;
if (this.channel !== activeChannel || this.state !== "running")
return;
(_a = this.debounceSendingEmptyData) === null || _a === void 0 ? void 0 : _a.run();
this.onStream(packet);
});
activeChannel.once("trap", (data) => {
if (this.channel !== activeChannel)
return;
this.onTrap(data);
});
activeChannel.once("done", () => {
if (this.channel !== activeChannel || this.state !== "running")
return;
this.finish(false);
});
activeChannel.once("close", () => {
if (this.channel !== activeChannel)
return;
if (this.state === "running")
this.finish(false, false);
else if (this.state === "stopping") {
this.finish(this.trapped, !this.trapped);
}
});
try {
activeChannel.write(this.params.slice(), true, false);
}
catch (err) {
this.state = "stopped";
this.channel = null;
this.emitError(new Error(`Failed to start stream: ${this.errorMessage(err)}`));
this.emit("stopped");
return;
}
if (this.shouldDebounceEmptyData)
this.prepareDebounceEmptyData();
this.emit("started");
}
prepareDebounceEmptyData() {
var _a;
this.shouldDebounceEmptyData = true;
(_a = this.debounceSendingEmptyData) === null || _a === void 0 ? void 0 : _a.cancel();
const intervalParam = this.params.find((param) => /=interval=/.test(param));
let interval = 2000;
if (intervalParam) {
const parsed = parseInt(intervalParam.split("=")[2], 10);
if (!isNaN(parsed))
interval = parsed * 1000;
}
this.debounceSendingEmptyData = (0, utils_1.debounce)(() => {
var _a;
if (this.state !== "running")
return;
this.onStream([]);
(_a = this.debounceSendingEmptyData) === null || _a === void 0 ? void 0 : _a.run();
}, interval + 300);
if (this.state === "running")
this.debounceSendingEmptyData.run();
}
cancelActiveChannel(pausing) {
const activeChannel = this.channel;
if (!activeChannel) {
if (pausing) {
this.state = "paused";
this.emit("paused");
}
else {
this.finish(false);
}
return Promise.resolve();
}
this.state = pausing ? "pausing" : "stopping";
this.cancelTimers();
const activeChannelClosed = activeChannel.Closed
? Promise.resolve()
: new Promise((resolve) => activeChannel.once("close", resolve));
const cancelChannel = new Channel_1.Channel(this.connector);
return cancelChannel
.write(["/cancel", "=tag=" + activeChannel.Id])
.then(() => __awaiter(this, void 0, void 0, function* () {
// RouterOS can acknowledge /cancel before the cancelled command sends
// its final !trap/!done. Keep its tag registered until that happens so
// in-flight stream packets can be safely consumed and ignored.
yield this.waitForChannelClose(activeChannel, activeChannelClosed);
activeChannel.close(true);
if (this.channel === activeChannel)
this.channel = null;
if (pausing) {
this.state = "paused";
this.emit("paused");
}
else {
this.finish(false);
}
}))
.catch((err) => {
this.state = "running";
this.emitError(new Error(`Cancel failed: ${err.message}`));
return Promise.reject(err);
});
}
waitForChannelClose(channel, channelClosed) {
if (channel.Closed)
return Promise.resolve();
return new Promise((resolve) => {
const timeout = (0, timers_1.setTimeout)(resolve, Math.max(1000, this.connector.timeout * 1000));
channelClosed.then(() => {
(0, timers_1.clearTimeout)(timeout);
resolve();
});
});
}
finish(trapped, emitDone = true) {
if (this.state === "stopped")
return;
const activeChannel = this.channel;
this.state = "stopped";
this.trapped = trapped;
this.channel = null;
this.cancelTimers();
activeChannel === null || activeChannel === void 0 ? void 0 : activeChannel.close(true);
if (emitDone && !trapped)
this.emit("done");
this.emit("close");
this.emit("stopped");
}
cancelTimers() {
var _a;
(_a = this.debounceSendingEmptyData) === null || _a === void 0 ? void 0 : _a.cancel();
if (this.sectionPacketSendingTimeout) {
(0, timers_1.clearTimeout)(this.sectionPacketSendingTimeout);
this.sectionPacketSendingTimeout = undefined;
}
this.currentSection = null;
this.currentSectionPacket = [];
}
onStream(packet) {
this.emit("data", packet);
if (!this.callback)
return;
try {
if (packet[".section"]) {
if (this.sectionPacketSendingTimeout) {
(0, timers_1.clearTimeout)(this.sectionPacketSendingTimeout);
}
const sendData = () => {
var _a;
(_a = this.callback) === null || _a === void 0 ? void 0 : _a.call(this, null, this.currentSectionPacket.slice(), this);
this.currentSectionPacket = [];
};
this.sectionPacketSendingTimeout = (0, timers_1.setTimeout)(sendData, 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.emitError(new Error(`Callback processing failed: ${this.errorMessage(err)}`));
}
}
onTrap(data) {
const message = (data === null || data === void 0 ? void 0 : data.message) || "Unknown trap error";
if (message === "interrupted" &&
(this.state === "pausing" || this.state === "stopping")) {
return;
}
if (message === "interrupted") {
this.state = "stopping";
this.cancelTimers();
return;
}
this.trapped = true;
this.state = "stopping";
this.cancelTimers();
if (this.callback)
this.callback(new Error(message), undefined, this);
else
this.emitError(new RosException_1.RosException("TRAP", { message }));
this.emit("trap", data);
}
trackTransition(transition) {
const tracked = transition.finally(() => {
if (this.transition === tracked)
this.transition = undefined;
});
this.transition = tracked;
return tracked;
}
emitError(error) {
if (this.listenerCount("error") > 0)
this.emit("error", error);
}
errorMessage(error) {
return error instanceof Error ? error.message : String(error);
}
}
exports.RStream = RStream;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUlN0cmVhbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9SU3RyZWFtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLG1DQUFzQztBQUN0QyxtQ0FBa0Q7QUFDbEQsdUNBQW9DO0FBRXBDLGlEQUE4QztBQUM5QyxtQ0FBbUM7QUFVbkM7Ozs7R0FJRztBQUNILE1BQWEsT0FBUSxTQUFRLHFCQUFZO0lBbUJ2QyxZQUNFLE9BQWdCLEVBQ2hCLE1BQWdCLEVBQ2hCLFFBQXNFO1FBRXRFLEtBQUssRUFBRSxDQUFDO1FBbkJGLFVBQUssR0FBaUIsTUFBTSxDQUFDO1FBQzdCLFlBQU8sR0FBWSxLQUFLLENBQUM7UUFPekIsNEJBQXVCLEdBQVksS0FBSyxDQUFDO1FBRXpDLG1CQUFjLEdBQWtCLElBQUksQ0FBQztRQUNyQyx5QkFBb0IsR0FBVSxFQUFFLENBQUM7UUFTdkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDO1FBQ25DLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFTSxJQUFJLENBQ1QsUUFBcUU7UUFFckUsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdCLE9BQU8sQ0FBQyxJQUFJLENBQUMsa0RBQWtELENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDM0IsQ0FBQztJQUVNLE1BQU07O1FBQ1gsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzFELE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLDJCQUFZLENBQUMsYUFBYSxDQUFDLENBQUMs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