routeros-api
Version:
Mikrotik Routerboard RouterOS API for NodeJS
389 lines • 21.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RosApiCommands = void 0;
const RosApiCrud_1 = require("./RosApiCrud");
const RosApiModel_1 = require("./RosApiModel");
const debug = require("debug");
const info = debug("routeros-client:commands:info");
const error = debug("routeros-client:commands:error");
class RosApiCommands extends RosApiCrud_1.RouterOSAPICrud {
/**
* Creates a set of operations to do over a menu
*
* @param rosApi The raw API
* @param path The menu path we are doing actions on
* @param snakeCase If we should use snake_case
*/
constructor(rosApi, path, snakeCase) {
super(rosApi, path, snakeCase);
}
/**
* Limits the returned fields when printing
*
* @param fields Fields to return
*/
select(fields) {
let commaFields = "=.proplist=";
if (typeof fields === "string")
fields = [fields];
for (let i = 0; i < fields.length; i++) {
const field = fields[i];
if (/^(id|dead|nextid)$/.test(field))
fields[i] = "." + field;
}
// Convert array to a string comma separated
commaFields += fields;
this.proplistVal = commaFields;
return this;
}
/**
* Moves a rule ABOVE the destination
*
* @param from the rule you want to move
* @param to the destination where you want to move
*/
move(from, to) {
return super.moveEntry(from, to);
}
/**
* Alias for select()
* @param fields Fields to return
*/
only(fields) {
return this.select(fields);
}
/**
* Add an option to the command. As an example: count-only or detail
*
* @param opts an option or array of options
* @param args multiple strings of parameters of options
*/
options(opts, ...args) {
if (typeof opts === "string")
opts = [opts];
opts = opts.concat(args || []);
const optObj = {};
for (const opt of opts)
optObj[opt] = "";
return this.where(optObj, "", false);
}
/**
* Alias for select()
* @param fields
*/
proplist(fields) {
return this.select(fields);
}
/**
* Filters the content when printing or define which item
* will do actions to when not printing
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
* @param addQuestionMark if will start the sentence with a question mark (?), else, starts with equal (=)
*/
where(key, value = "", addQuestionMark = true) {
let search = new Object();
if (typeof key === "string") {
search[key] = value;
}
else {
search = key;
}
this.makeQuery(search, addQuestionMark);
return this;
}
/**
* Alias to where, but without adding question marks
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
query(key, value) {
return this.where(key, value, false);
}
/**
* Alias to where, but without adding question marks
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
filter(key, value) {
return this.where(key, value, false);
}
/**
* Raw API syntax to be added to the stack
*
* @param search array of sentences to send over the api
*/
whereRaw(search) {
this.queryVal = this.queryVal.concat(search);
return this;
}
/**
* Adds an OR operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
orWhere(key, value) {
this.where(key, value);
this.queryVal.push("?#|");
return this;
}
/**
* Adds a NOT and then OR operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
orWhereNot(key, value) {
this.where(key, value);
this.queryVal.push("?#!", "?#|");
return this;
}
/**
* Adds an AND operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
andWhere(key, value) {
this.where(key, value);
this.queryVal.push("?#&");
return this;
}
/**
* Adds a NOT and then an AND operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
andWhereNot(key, value) {
this.where(key, value);
this.queryVal.push("?#!", "?#&");
return this;
}
/**
* Adds an NOT operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
whereNot(key, value) {
this.where(key, value);
this.queryVal.push("?#!");
return this;
}
/**
* Adds a HIGHER THAN (>) operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
whereHigher(key, value) {
this.where(">" + key, value);
return this;
}
/**
* Adds a LOWER THAN (<) operator when filtering content
*
* @param key a key to a value or an object with keys and values to filter
* @param value the value if a string key is passed
*/
whereLower(key, value) {
this.where("<" + key, value);
return this;
}
/**
* Checks if the parameter or key exists by having a value when filtering
*
* @param key the parameter to check
*/
whereExists(key) {
return this.whereHigher(key);
}
/**
* Alias to whereExists
*
* @param key the parameter to check
*/
whereNotEmpty(key) {
return this.whereHigher(key);
}
/**
* Check if the parameter or key doesn't exist or has no value when filtering
*
* @param key the parameter to check
*/
whereEmpty(key) {
this.where("-" + key);
return this;
}
/**
* Alias of whereEmpty
*
* @param key the parameter to check
*/
whereNotExists(key) {
return this.whereEmpty(key);
}
/**
* Prints the data of the menu
*
* @param data optional filtering, like what you get when using the where function
*/
get(data) {
if (data)
this.makeQuery(data, true);
const query = this.fullQuery("/print");
return this.write(query);
}
/**
* Alias of get
*
* @param data optional filtering, like what you get when using the where function
*/
getAll(data) {
return this.get(data);
}
/**
* Alias of get, but in the process creates a model
* of each item returned
*
* @param data optional filtering, like what you get when using the where function
*/
getModel(data) {
return this.get(data).then((results) => {
for (let i = 0; i < results.length; i++) {
results[i] = new RosApiModel_1.RosApiModel(this.rosApi, results[i], this.snakeCase);
}
return Promise.resolve(results);
}).catch((err) => {
return Promise.reject(err);
});
}
/**
* Alias of get
*
* @param data optional filtering, like what you get when using the where function
*/
print(data) {
return this.get(data);
}
/**
* Alias of find
*
* @param data optional filtering, like what you get when using the where function
*/
first(data) {
return this.find(data);
}
/**
* Returns the first item if found, else return null
*
* @param data optional filtering, like what you get when using the where function
*/
find(data) {
return this.get(data).then((results) => {
let result = new Object();
if (results.length > 0)
result = results[0];
else
result = null;
return Promise.resolve(result);
}).catch((err) => {
return Promise.reject(err);
});
}
/**
* Alias of find
*
* @param data optional filtering, like what you get when using the where function
*/
getOne(data) {
return this.find(data);
}
/**
* Alias of find
*
* @param data optional filtering, like what you get when using the where function
*/
getOnly(data) {
return this.find(data);
}
/**
* Remove all entries of the current menu
*/
purge() {
return this.write([
this.pathVal + "/print",
"=.proplist=.id"
]).then((results) => {
const ids = results.map((result) => {
return result[".id"];
});
return this.write([
this.pathVal + "/remove",
"=numbers=" + ids
]);
}).catch((err) => {
return Promise.reject(err);
});
}
/**
* Start a streaming of content and returns a Stream object
* so it can be paused, resumed or stopped
*
* @param action optional action to add when streaming, like "listen" for example
* @param callback
*/
stream(action, callback) {
if (typeof action === "function") {
callback = action;
action = "";
}
else if (action && typeof action === "string") {
action = "/" + action.replace(/^\//, "");
}
const query = this.fullQuery(action);
info("Streaming query %o", query);
this.queryVal = [];
this.proplistVal = "";
if (!callback) {
const stream = this.rosApi.stream(query);
stream.on("data", (packet) => {
if (!Array.isArray(packet)) {
packet = this.treatMikrotikProperties([packet])[0];
}
else {
packet = this.treatMikrotikProperties(packet);
}
stream.emit("parsed-data", packet);
});
stream.on("error", (err) => {
err = this.treatMikrotikProperties([err])[0];
stream.emit("parsed-error", err);
});
return stream;
}
return this.rosApi.stream(query, (err, packet, stream) => {
if (err)
error("When streaming, got error: %o", err);
if (typeof callback === "function") {
if (packet) {
info("Received stream packet: %o", packet);
if (!Array.isArray(packet)) {
packet = this.treatMikrotikProperties([packet])[0];
}
else {
packet = this.treatMikrotikProperties(packet);
}
}
callback(err, packet, stream);
}
});
}
}
exports.RosApiCommands = RosApiCommands;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm9zQXBpQ29tbWFuZHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvUm9zQXBpQ29tbWFuZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsNkNBQStDO0FBQy9DLCtDQUE0QztBQUU1QywrQkFBK0I7QUFJL0IsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLCtCQUErQixDQUFDLENBQUM7QUFDcEQsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7QUFFdEQsTUFBYSxjQUFlLFNBQVEsNEJBQWU7SUFFL0M7Ozs7OztPQU1HO0lBQ0gsWUFBWSxNQUFtQixFQUFFLElBQVksRUFBRSxTQUFrQjtRQUM3RCxLQUFLLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxNQUF5QjtRQUNuQyxJQUFJLFdBQVcsR0FBVyxhQUFhLENBQUM7UUFDeEMsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRO1lBQUUsTUFBTSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFbEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDcEMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3hCLElBQUksb0JBQW9CLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztnQkFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxHQUFHLEtBQUssQ0FBQztTQUNqRTtRQUVELDZDQUE2QztRQUM3QyxXQUFXLElBQUksTUFBTSxDQUFDO1FBQ3RCLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLElBQUksQ0FBQyxJQUFjLEVBQUUs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