UNPKG

@fibercom/routeros-api

Version:

Robust MikroTik RouterOS API client for Node.js and TypeScript

303 lines 24.9 kB
"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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