Files
genieacs/server/api-functions.js
T

189 lines
5.1 KiB
JavaScript

"use strict";
const http = require("http");
const https = require("https");
const url = require("url");
const querystring = require("querystring");
const config = require("./config");
const device = require("./device");
const filterParser = require("./filter-parser");
const commaAscii = ",".charCodeAt(0);
const newLineAscii = "\n".charCodeAt(0);
function filterToQuery(filter, negate = false, res = {}) {
const op = filter[0];
if ((!negate && op === "AND") || (negate && op === "OR")) {
for (let i = 1; i < filter.length; ++i)
filterToQuery(filter[i], negate, res);
} else if ((!negate && op === "OR") || (negate && op === "AND")) {
res["$or"] = res["$or"] || [];
for (let i = 1; i < filter.length; ++i)
res["$or"].push(filterToQuery(filter[i], negate));
} else if (op === "NOT") {
filterToQuery(filter[1], !negate, res);
} else if (op === "=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p["$ne"] = filter[2];
else p["$eq"] = filter[2];
} else if (op === "<>") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) {
p["$eq"] = filter[2];
} else {
p["$ne"] = filter[2];
p["$exists"] = true;
}
} else if (op === ">") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$gt"] = filter[2];
} else if (op === ">=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$gte"] = filter[2];
} else if (op === "<") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$lt"] = filter[2];
} else if (op === "<=") {
let p = (res[filter[1]] = res[filter[1]] || {});
if (negate) p = p["$not"] = p["$not"] || {};
p["$lte"] = filter[2];
} else if (op === "IS NULL") {
res[filter[1]] = { $exists: negate };
} else if (op === "IS NOT NULL") {
res[filter[1]] = { $exists: !negate };
} else {
throw new Error(`Unrecognized operator ${op}`);
}
return res;
}
function count(resource, filter, limit) {
return new Promise((resolve, reject) => {
let qs = {};
if (filter) {
let q = filterToQuery(filterParser.parse(filter));
if (resource === "devices") q = device.transposeQuery(q);
qs.query = JSON.stringify(q);
}
if (limit) qs.limit = limit;
let options = url.parse(
`${config.GENIEACS_NBI}${resource}?${querystring.stringify(qs)}`
);
options.method = "HEAD";
let _http = options.protocol === "https:" ? https : http;
_http
.request(options, res => {
if (res.statusCode !== 200) {
reject(new Error(`Unexpected status code ${res.statusCode}`));
res.resume();
return;
}
resolve(+res.headers["total"]);
})
.end();
});
}
function query(resource, filter, limit, callback) {
return new Promise((resolve, reject) => {
let ret;
if (!callback) ret = [];
let qs = {};
if (filter) {
let q = filterToQuery(filterParser.parse(filter));
if (resource === "devices") q = device.transposeQuery(q);
qs.query = JSON.stringify(q);
}
if (limit) qs.limit = limit;
let options = url.parse(
`${config.GENIEACS_NBI}${resource}?${querystring.stringify(qs)}`
);
let _http = options.protocol === "https:" ? https : http;
_http.get(options, res => {
if (res.statusCode !== 200) {
reject(new Error(`Unexpected status code ${res.statusCode}`));
res.resume();
return;
}
let chunks = [];
let bytes = 0;
res.on("data", chunk => {
let i;
while ((i = chunk.indexOf(newLineAscii)) !== -1) {
let buf;
if (chunk[chunk.length - 2] === commaAscii) {
i -= 1;
buf = new Buffer(bytes + i);
chunk.copy(buf, buf.length - i, 0, i);
chunk = chunk.slice(i + 2);
} else {
buf = new Buffer(bytes + i);
chunk.copy(buf, buf.length - i, 0, i);
chunk = chunk.slice(i + 1);
}
let o = 0;
for (let c of chunks) {
c.copy(buf, o, 0, c.length);
o += c.length;
}
if (buf.length > 1) {
let obj = JSON.parse(buf);
if (resource === "devices") obj = device.transpose(obj);
if (ret) ret.push(obj);
else callback(obj);
}
bytes = 0;
chunks = [];
}
bytes += chunk.length;
chunks.push(chunk);
});
res.on("end", () => {
let buf = new Buffer(bytes);
let o = 0;
for (let c of chunks) {
c.copy(buf, o, 0, c.length);
o += c.length;
}
if (buf.length > 1) {
let obj = JSON.parse(buf);
if (resource === "devices") obj = device.transpose(obj);
if (ret) ret.push(obj);
else callback(obj);
}
resolve(ret);
});
res.on("aborted", () => {
res.removeAllListeners("end");
reject(new Error("Timeout"));
});
});
});
}
exports.query = query;
exports.count = count;