@fibercom/routeros-api
Version:
Robust MikroTik RouterOS API client for Node.js and TypeScript
144 lines • 9.91 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Channel = void 0;
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 issuing commands with a unique tag,
* and receiving corresponding replies via the RouterOS API. It listens for
* specific reply types such as !re, !done, and !trap.
*/
class Channel extends events_1.EventEmitter {
constructor(connector) {
super();
this.data = [];
this.trapped = false;
this.streaming = false;
this.closed = false;
this.id = Math.random().toString(36).substring(3);
this.connector = connector;
this.once("unknown", this.onUnknown.bind(this));
}
/**
* Get the unique ID assigned to this channel.
*/
get Id() {
return this.id;
}
/**
* Get the underlying connector used by this channel.
*/
get Connector() {
return this.connector;
}
/** Whether this channel has completed cleanup and stopped reading its tag. */
get Closed() {
return this.closed;
}
/**
* Write a command to the RouterOS device with this channel's tag.
* Always returns a promise that resolves/rejects on done/trap.
*/
write(params, isStream = false, returnPromise = true) {
this.streaming = isStream;
const taggedParams = [...params, ".tag=" + this.id];
if (!returnPromise) {
this.readAndWrite(taggedParams);
return Promise.resolve([]);
}
this.data = []; // clear any old data
this.on("data", (packet) => this.data.push(packet));
return new Promise((resolve, reject) => {
this.once("done", (data) => resolve(data));
this.once("trap", (data) => {
const msg = (data === null || data === void 0 ? void 0 : data.message) || "Unknown error";
reject(new RosException_1.RosException("TRAP", { message: msg }));
});
this.readAndWrite(taggedParams);
});
}
/**
* Close the channel and stop reading its tag.
* Optionally force cleanup of event listeners.
*/
close(force = false) {
if (this.closed)
return;
this.closed = true;
this.emit("close");
if (!this.streaming || force) {
this.removeAllListeners();
}
this.connector.stopRead(this.id);
}
/**
* Bind a tag reader and issue the command.
*/
readAndWrite(params) {
this.connector.read(this.id, (packet) => this.processPacket(packet));
this.connector.write(params);
}
/**
* Parse incoming replies and emit appropriate events.
*/
processPacket(packet) {
const reply = packet.shift();
info("Processing reply %s with data %o", reply, packet);
if (reply === "!empty") {
info("Received !empty — interpreted as empty [] response");
// Explicitly clear data
this.data = [];
return;
}
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;
default:
this.emit("unknown", reply);
this.close();
break;
}
}
/**
* Convert an array of lines like '=key=value' into an object.
*/
parsePacket(packet) {
const obj = {};
for (const line of packet) {
const linePair = line.split("=");
linePair.shift(); // Remove leading empty element
const key = linePair.shift();
if (key !== undefined)
obj[key] = linePair.join("=");
}
info("Parsed line, got %o as result", obj);
return obj;
}
/**
* Handler for unexpected replies—emits and throws an error.
*/
onUnknown(reply) {
throw new RosException_1.RosException("UNKNOWNREPLY", { reply });
}
}
exports.Channel = Channel;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhbm5lbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9DaGFubmVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUFzQztBQUV0QyxpREFBOEM7QUFDOUMsK0JBQWdDO0FBR2hDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0FBQ2hELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0FBRWxEOzs7O0dBSUc7QUFDSCxNQUFhLE9BQVEsU0FBUSxxQkFBWTtJQVF2QyxZQUFZLFNBQW9CO1FBQzlCLEtBQUssRUFBRSxDQUFDO1FBTkYsU0FBSSxHQUFVLEVBQUUsQ0FBQztRQUNqQixZQUFPLEdBQVksS0FBSyxDQUFDO1FBQ3pCLGNBQVMsR0FBWSxLQUFLLENBQUM7UUFDM0IsV0FBTSxHQUFZLEtBQUssQ0FBQztRQUk5QixJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxFQUFFO1FBQ0osT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUN4QixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLElBQUksTUFBTTtRQUNSLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNyQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUNWLE1BQWdCLEVBQ2hCLFFB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