UNPKG

routeros-api

Version:

Mikrotik Routerboard RouterOS API for NodeJS

511 lines 36.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RouterOSAPICrud = void 0; const lodash_1 = require("lodash"); const utils = require("./utils"); const RosException_1 = require("./RosException"); class RouterOSAPICrud { /** * Creates a CRUD set of operations and handle * the raw query to input on the raw API * * @param rosApi the raw api * @param path the menu path we are in * @param snakeCase if should return routerboard properties in snake_case, defaults to camelCase */ constructor(rosApi, path, snakeCase) { this.queryVal = []; this.needsObjectTranslation = false; this.rosApi = rosApi; this.snakeCase = snakeCase; this.pathVal = path .replace(/ /g, "/") .replace(/(print|enable|disable|add|set|remove|getall|move)$/, "") .replace(/\/$/, ""); } /** * Get the current menu */ getCurrentMenu() { return this.pathVal; } /** * Adds an item on the menu * * @param data the params that will be used to add the item */ add(data) { return this.exec("add", data).then((results) => { if (results.length === 0) return Promise.resolve(null); return this.recoverDataFromChangedItems(results.shift().ret); }); } /** * Alias of add * * @param data the params that will be used to add the item */ create(data) { return this.add(data); } /** * Disable one or more entries * * @param ids the id(s) or number(s) to disable */ disable(ids) { if (ids) { ids = this.stringfySearchQuery(ids); this.queryVal.push("=numbers=" + ids); } let disabledIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.queryForIdsIfNeeded(disabledIds).then((ids) => { disabledIds = ids; return this.exec("disable"); }).then((response) => { return this.recoverDataFromChangedItems(disabledIds); }); } /** * Delete one or more entries * * @param ids the id(s) or number(s) to delete */ delete(ids) { return this.remove(ids); } /** * Enable one or more entries * * @param ids the id(s) or number(s) to enable */ enable(ids) { if (ids) { ids = this.stringfySearchQuery(ids); this.queryVal.push("=numbers=" + ids); } let enabledIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.queryForIdsIfNeeded(enabledIds).then((ids) => { enabledIds = ids; return this.exec("enable"); }).then((response) => { return this.recoverDataFromChangedItems(enabledIds); }); } /** * Run a custom command over the api, for example "export" * * @param command the command to run * @param data optional data that goes with the command */ exec(command, data) { if (data) this.makeQuery(data); const query = this.fullQuery("/" + command); return this.translateQueryIntoId(query).then((consultedQuery) => { return this.write(consultedQuery); }).then((results) => { // Only runs when using the place-after feature // otherwise it will return the response immediately return this.prepareToPlaceAfter(results); }); } /** * Move a queried rule above another. * * @param to where to move the queried rule */ moveAbove(to) { let movedIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.queryForIdsIfNeeded(movedIds).then((ids) => { movedIds = ids; if (to) this.queryVal.push("=destination=" + to); return this.exec("move"); }).then(() => { return this.recoverDataFromChangedItems(movedIds); }); } /** * Update an entry or set of entries of the menu * * @param data the new data to update the item * @param ids optional id(s) of the rules */ update(data, ids) { if (ids) { ids = this.stringfySearchQuery(ids); this.queryVal.push("=numbers=" + ids); } let updatedIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.queryForIdsIfNeeded(updatedIds).then((ids) => { updatedIds = ids; this.makeQuery(data); return this.exec("set"); }).then((response) => { return this.recoverDataFromChangedItems(updatedIds); }); } /** * Unset a property or set of properties of one or more entries * * @param properties one or more properties to unset * @param ids the id(s) of the entries to unset the property(ies) */ unset(properties, ids) { if (ids) { ids = this.stringfySearchQuery(ids); this.queryVal.push("=numbers=" + ids); } let updatedIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.queryForIdsIfNeeded(updatedIds).then((ids) => { updatedIds = ids; if (typeof properties === "string") properties = [properties]; const $q = []; // Saving current queryVal for reuse, since running exec will reset it const curQueryVal = this.queryVal.slice(); // Cleaning current queryVal to prevent duplication this.queryVal = []; properties.forEach((property) => { // Putting back queryVal after a cleanup this.queryVal = curQueryVal.slice(); this.queryVal.push("=value-name=" + utils.camelCaseOrSnakeCaseToDashedCase(property)); $q.push(this.exec("unset")); }); return Promise.all($q); }).then(() => { return this.recoverDataFromChangedItems(updatedIds); }); } /** * Removes an entry or set of entries of the menu * * @param ids optional id(s) to be removed from the menu */ remove(ids) { if (ids) { ids = this.stringfySearchQuery(ids); this.queryVal.push("=numbers=" + ids); } const idsForRemoval = utils.lookForIdParameterAndReturnItsValue(this.queryVal); let responseData; return this.queryForIdsIfNeeded(idsForRemoval).then((ids) => { return this.recoverDataFromChangedItems(ids); }).then((response) => { responseData = response; return this.exec("remove"); }).then(() => { return Promise.resolve(responseData); }); } /** * Alias of update * * @param data the new data to update the item * @param ids optional id(s) of the rules */ set(data, ids) { return this.update(data, ids); } /** * Alias of update * * @param data the new data to update the item * @param ids optional id(s) of the rules */ edit(data, ids) { return this.update(data, ids); } /** * Moves a rule ABOVE the destination * * @param from the rule you want to move * @param to the destination where you want to move */ moveEntry(from, to) { if (!Array.isArray(from)) from = [from]; from = this.stringfySearchQuery(from); this.queryVal.push("=numbers=" + from); if (to) { to = this.stringfySearchQuery(to); this.queryVal.push("=destination=" + to); } const movedIds = utils.lookForIdParameterAndReturnItsValue(this.queryVal); return this.exec("move").then(() => { return this.recoverDataFromChangedItems(movedIds); }); } /** * Creates the full array of sentences that will be * compatible with the raw API to be sent to the * routerboard using all the functions triggered * up until now * * @param append action to add in front of the menu */ fullQuery(append) { let val = []; if (append) { val.push(this.pathVal + append); } else { val.push(this.pathVal); } if (this.proplistVal) val.push(this.proplistVal); val = val.concat(this.queryVal).slice(); if (!/(print|getall)$/.test(val[0])) { for (let index = 0; index < val.length; index++) { val[index] = val[index].replace(/^\?/, "="); } } return val; } /** * Make the query array to write on the API, * adding a question mark if it needs to print * filtered content * * @param searchParameters The key-value pair to add to the search */ makeQuery(searchParameters, addQuestionMark = false, addToLocalQuery = true) { let tmpKey; let tmpVal; const tmpQuery = addToLocalQuery ? this.queryVal : []; for (const key in searchParameters) { if (searchParameters.hasOwnProperty(key)) { tmpVal = searchParameters[key]; if (/[A-Z]/.test(tmpKey)) { tmpKey = tmpKey.replace(/([A-Z])/g, "$1").toLowerCase(); } tmpKey = key.replace(/_/, "-"); // if selecting for id, convert it to .id to match mikrotik standards switch (tmpKey) { case "id": tmpKey = ".id"; break; case "next": tmpKey = ".nextid"; break; case "dead": tmpKey = ".dead"; break; default: break; } if (typeof tmpVal === "boolean") { tmpVal = tmpVal ? "yes" : "no"; } else if (tmpVal === null) { tmpVal = ""; } else if (typeof tmpVal === "object") { tmpVal = this.stringfySearchQuery(tmpVal); } else if (tmpKey === "placeAfter") { this.placeAfter = tmpVal; tmpKey = "placeBefore"; } tmpKey = (addQuestionMark ? "?" : "=") + tmpKey; tmpKey = utils.camelCaseOrSnakeCaseToDashedCase(tmpKey); tmpQuery.push(tmpKey + "=" + tmpVal); } } return tmpQuery; } /** * Write the query using the raw API * * @param query the raw array of sentences to write on the socket */ write(query) { this.queryVal = []; this.proplistVal = ""; return this.rosApi.write(query).then((results) => { return Promise.resolve(this.treatMikrotikProperties(results)); }); } /** * Translates .id, place-before and number without using internal * mikrotik id (something like *4A). * * This should check if one of those parameters are an object * and use that object to search the real id of the item. * * @param queries query array */ translateQueryIntoId(queries) { if (queries.length === 0 || !this.needsObjectTranslation) return Promise.resolve(queries); const promises = []; const consultedIndexes = []; for (const [index, element] of queries.entries()) { const str = element.replace(/^\?/, "").replace(/^\=/, ""); if (str.includes(".id=") || str.includes("place-before=") || str.includes("place-after=") || str.includes("numbers=")) { if (/\{.*\}/.test(str)) { const key = str.split("=").shift(); const value = JSON.parse(str.split("=").pop()); const treatedQuery = [ this.pathVal + "/print", "=.proplist=.id" ].concat(this.makeQuery(value, true, false)); const promise = this.rosApi.write(treatedQuery); consultedIndexes.push({ index: index, key: key }); promises.push(promise); } } } return Promise.all(promises).then((results) => { for (let result of results) { if (Array.isArray(result)) result = result.shift(); const consulted = consultedIndexes.shift(); if (!result) return Promise.reject(new RosException_1.RosException("REFNOTFND", { key: consulted.key })); if (consulted.key === "place-after") { this.placeAfter = result[".id"]; consulted.key = "place-before"; } queries[consulted.index] = "=" + consulted.key + "=" + result[".id"]; } this.needsObjectTranslation = false; return Promise.resolve(queries); }); } /** * If the place-after feature was used, the rule below * will be moved above here. * * @param results */ prepareToPlaceAfter(results) { if (!this.placeAfter || results.length !== 1) return Promise.resolve(results); if (!results[0].ret) return Promise.resolve(results); const from = this.placeAfter; const to = results[0].ret; this.placeAfter = null; return this.moveEntry(from, to).then(() => { return Promise.resolve(results); }); } /** * Transform mikrotik properties to either camelCase or snake_case * and casts values of true or false to boolean and * integer strings to number * * @param results the result set of an operation */ treatMikrotikProperties(results) { const treatedArr = []; results.forEach((result) => { const tmpItem = { $$path: this.pathVal }; for (const key in result) { if (result.hasOwnProperty(key)) { const tmpVal = result[key]; let tmpKey = this.snakeCase ? utils.dashedCaseToSnakeCase(key) : utils.dashedCaseToCamelCase(key); tmpKey = tmpKey.replace(/^\./, ""); tmpItem[tmpKey] = tmpVal; if (tmpVal === "true" || tmpVal === "false") { tmpItem[tmpKey] = tmpVal === "true"; } else if (/^\d+(\.\d+)?$/.test(tmpVal)) { tmpItem[tmpKey] = parseFloat(tmpVal); } } } treatedArr.push(tmpItem); }); return treatedArr; } /** * Stringify a json formated object to be used later * for a translation * * @param items object items to stringfy */ stringfySearchQuery(items) { let isArray = true; const newItems = []; if (!Array.isArray(items)) { isArray = false; items = [items]; } for (const item of items) { if (typeof item === "object") { this.needsObjectTranslation = true; newItems.push(JSON.stringify(item)); } else newItems.push(item); } return isArray ? newItems : newItems.shift(); } /** * Clean data print of provided ids, used only when * creating, editting or unsetting properties * * @param data * @param ids */ recoverDataFromChangedItems(ids) { if (!ids) { return this.rosApi.write([this.pathVal + "/print"]) .then((data) => Promise.resolve(this.treatMikrotikProperties(data).shift())); } const promises = []; const splittedIds = ids.split(","); for (const id of splittedIds) { const promise = this.rosApi.write([ this.pathVal + "/print", "?.id=" + id ]); promises.push(promise); } return Promise.all(promises).then((data) => { if (!data) return Promise.resolve(data); data = lodash_1.flatten(data); data = this.treatMikrotikProperties(data); if (!ids.includes(",")) return Promise.resolve(data.shift()); return Promise.resolve(data); }); } /** * If trying do any action without providing any id, just * a query. Find all their ids and return them * * @param ids */ queryForIdsIfNeeded(ids) { if (ids) return Promise.resolve(ids); this.queryVal.push("=.proplist=.id"); const query = this.fullQuery("/print"); let queriedIds; return this.write(query).then((data) => { data = lodash_1.reduce(data, (result, value, key) => { result.push(value.id); return result; }, []); queriedIds = data + ""; if (queriedIds) this.queryVal.push("=numbers=" + queriedIds); return Promise.resolve(queriedIds); }); } } exports.RouterOSAPICrud = RouterOSAPICrud; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm9zQXBpQ3J1ZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Sb3NBcGlDcnVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1DQUF5QztBQUN6QyxpQ0FBaUM7QUFHakMsaURBQThDO0FBRTlDLE1BQXNCLGVBQWU7SUFnQmpDOzs7Ozs7O09BT0c7SUFDSCxZQUFZLE1BQW1CLEVBQUUsSUFBWSxFQUFFLFNBQWtCO1FBaEJ2RCxhQUFRLEdBQWEsRUFBRSxDQUFDO1FBSTFCLDJCQUFzQixHQUFZLEtBQUssQ0FBQztRQWE1QyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUk7YUFDZCxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQzthQUNsQixPQUFPLENBQUMsb0RBQW9ELEVBQUUsRUFBRSxDQUFDO2FBQ2pFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksY0FBYztRQUNqQixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxHQUFHLENBQUMsSUFBWTtRQUNuQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQVksRUFBRSxFQUFFO1lBQ2hELElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO2dCQUFFLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN2RCxPQUFPLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDakUsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FB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