code optimization
This commit is contained in:
parent
2b37fc9cdd
commit
fe1a21f222
5 changed files with 264 additions and 97 deletions
13
config.json
13
config.json
|
@ -1,22 +1,21 @@
|
|||
{
|
||||
"server": {
|
||||
"listen": "0.0.0.0",
|
||||
"port": 3000,
|
||||
"timestamp": "DD.MM.YYYY HH:mm:ss:SS"
|
||||
"port": 3000
|
||||
},
|
||||
"log": {
|
||||
"level": "debug"
|
||||
"level": "debug",
|
||||
"timestamp": "DD.MM.YYYY HH:mm:ss:SS"
|
||||
},
|
||||
"api": [
|
||||
{
|
||||
"url": "/uptime",
|
||||
"type": "get",
|
||||
"command": "uptime123",
|
||||
"command": "uptime1",
|
||||
"args": [
|
||||
"-V",
|
||||
"-p"
|
||||
],
|
||||
"passargs": true
|
||||
"passargs": true,
|
||||
"detach": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,25 +1,83 @@
|
|||
const logger = require('../libs/logger.js');
|
||||
const logger = require('./logger.js');
|
||||
const { spawn } = require('child_process')
|
||||
|
||||
function execute(endpoint) {
|
||||
if (!endpoint || !endpoint.command) {
|
||||
logger.warn('no command defined');
|
||||
const cmds = new Map();
|
||||
|
||||
async function execute(endpoint) {
|
||||
if (endpoint === undefined) {
|
||||
return;
|
||||
}
|
||||
logger.debug('executing command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\'...');
|
||||
return new Promise((resolve, reject) => {
|
||||
logger.info('executing command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')...');
|
||||
var cmd = spawn(endpoint.command, endpoint.args);
|
||||
cmd.stdout.on('data', function(data) {
|
||||
logger.debug(data);
|
||||
cmd.timestamp = new Date().getTime();
|
||||
let result = '';
|
||||
let error = '';
|
||||
cmd.stdout.on('data', (data) => {
|
||||
result += data;
|
||||
});
|
||||
cmd.stderr.on('data', function(data) {
|
||||
logger.error(data);
|
||||
cmd.stderr.on('data', (data) => {
|
||||
error += data;
|
||||
});
|
||||
cmd.on('close', function(code) {
|
||||
logger.debug('command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\' finished with exit code ' + code);
|
||||
cmd.on('spawn', () => {
|
||||
logger.info('spawned command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\')');
|
||||
addCommand(cmd, endpoint);
|
||||
if (endpoint.detach !== false) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
cmd.on('error', function(err) {
|
||||
logger.error('command \'' + endpoint.command + '\' with args \'' + endpoint.args + '\' encountered an error >>> ' + err);
|
||||
cmd.on('error', (err) => {
|
||||
error += err;
|
||||
removeCommand(endpoint);
|
||||
if (endpoint.detach !== false) {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
cmd.on('close', (code) => {
|
||||
removeCommand(endpoint);
|
||||
let fn = logger.info;
|
||||
let msg = 'command \'' + endpoint.command + '\' (args: \'' + endpoint.args + '\') finished with exit code ' + code + ' after ' + (new Date().getTime() - cmd.timestamp) + 'ms';
|
||||
if (error !== undefined && error.length > 0) {
|
||||
msg += ' >>> ' + error;
|
||||
fn = logger.error;
|
||||
reject(error);
|
||||
}
|
||||
if (result !== undefined && result.length > 0) {
|
||||
msg += ' > ' + result;
|
||||
}
|
||||
fn(msg);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addCommand(command, endpoint) {
|
||||
if (command === undefined || endpoint === undefined) {
|
||||
return;
|
||||
}
|
||||
cmds.set(JSON.stringify(endpoint), command);
|
||||
}
|
||||
|
||||
function removeCommand(endpoint) {
|
||||
if (endpoint === undefined) {
|
||||
return;
|
||||
}
|
||||
cmds.delete(JSON.stringify(endpoint));
|
||||
}
|
||||
|
||||
function isCommandActive(endpoint) {
|
||||
return endpoint !== undefined && cmds.has(JSON.stringify(endpoint));
|
||||
}
|
||||
|
||||
function killCommand(endpoint) {
|
||||
if (endpoint === undefined) {
|
||||
return;
|
||||
}
|
||||
const command = cmds.get(JSON.stringify(endpoint));
|
||||
if (command === undefined) {
|
||||
return;
|
||||
}
|
||||
process.kill(command.pid);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
115
libs/logger.js
115
libs/logger.js
|
@ -1,48 +1,80 @@
|
|||
const config = require("../config.json");
|
||||
const moment = require("moment");
|
||||
const moment = require('moment');
|
||||
|
||||
// constants
|
||||
const LOG_PREFIX_DEBUG = "debug";
|
||||
const LOG_PREFIX_INFO = "info";
|
||||
const LOG_PREFIX_WARNING = "warning";
|
||||
const LOG_PREFIX_ERROR = "error";
|
||||
const LOG_PREFIX_DEBUG = 'debug';
|
||||
const LOG_PREFIX_INFO = 'info';
|
||||
const LOG_PREFIX_WARNING = 'warning';
|
||||
const LOG_PREFIX_ERROR = 'error';
|
||||
const LOGLEVEL_DEBUG = 0;
|
||||
const LOGLEVEL_INFO = 1;
|
||||
const LOGLEVEL_WARNING = 2;
|
||||
const LOGLEVEL_ERROR = 3;
|
||||
|
||||
// set loglevel on "require"
|
||||
const loglevel = function() {
|
||||
switch (config.log.level) {
|
||||
let loglevel;
|
||||
let timestamp;
|
||||
|
||||
initialize();
|
||||
|
||||
function initialize(loglevel, timestamp) {
|
||||
setLogLevel(loglevel || global.config?.log?.level);
|
||||
setTimestamp(timestamp || global.config?.log?.timestamp);
|
||||
}
|
||||
|
||||
// set the loglevel
|
||||
function setLogLevel(value) {
|
||||
switch (value) {
|
||||
case LOG_PREFIX_DEBUG:
|
||||
case LOGLEVEL_DEBUG:
|
||||
return LOGLEVEL_DEBUG;
|
||||
loglevel = LOGLEVEL_DEBUG;
|
||||
break;
|
||||
case LOG_PREFIX_INFO:
|
||||
case LOGLEVEL_INFO:
|
||||
return LOGLEVEL_INFO;
|
||||
loglevel = LOGLEVEL_INFO;
|
||||
break;
|
||||
case LOG_PREFIX_WARNING:
|
||||
case LOGLEVEL_WARNING:
|
||||
return LOGLEVEL_WARNING;
|
||||
loglevel = LOGLEVEL_WARNING;
|
||||
break;
|
||||
case LOG_PREFIX_ERROR:
|
||||
case LOGLEVEL_ERROR:
|
||||
return LOGLEVEL_ERROR;
|
||||
loglevel = LOGLEVEL_ERROR;
|
||||
break;
|
||||
default:
|
||||
return LOGLEVEL_INFO;
|
||||
loglevel = LOGLEVEL_INFO;
|
||||
break;
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
// log a http request
|
||||
function request(request) {
|
||||
let message = "[" + request.method + "] url: \"" + request.url + "\"";
|
||||
// get the timestamp format
|
||||
function setTimestamp(value) {
|
||||
timestamp = value || 'DD.MM.YYYY HH:mm:ss:SS';
|
||||
}
|
||||
|
||||
// log a http request - response object
|
||||
function http(object) {
|
||||
if (object === undefined) {
|
||||
return;
|
||||
}
|
||||
let message = '[' + object.request.method + ':' + object.code + '] url: \'' + object.request.url + '\'';
|
||||
let counter = 1;
|
||||
for (let param in request.body) {
|
||||
message += ", parameter " + counter + ": \"" + param + "=" + request.body[param] + "\"";
|
||||
for (let param in object.request.body) {
|
||||
message += ', parameter ' + counter + ': \'' + param + '=' + object.request.body[param] + '\'';
|
||||
counter++;
|
||||
}
|
||||
if (object.request.timestamp) {
|
||||
message += ' > ' + (new Date().getTime() - object.request.timestamp) + 'ms';
|
||||
}
|
||||
if (object.data) {
|
||||
message += ' > data: ' + object.data;
|
||||
}
|
||||
if (object.code != 200) {
|
||||
error(message.trim());
|
||||
return;
|
||||
}
|
||||
debug(message.trim());
|
||||
}
|
||||
|
||||
// prefix log with "info"
|
||||
// prefix log with 'info'
|
||||
function info(message) {
|
||||
if (loglevel > LOGLEVEL_INFO) {
|
||||
return;
|
||||
|
@ -50,28 +82,42 @@ function info(message) {
|
|||
trace(message);
|
||||
}
|
||||
|
||||
// prefix log with "info"
|
||||
// prefix log with 'info'
|
||||
function warn(message) {
|
||||
if (loglevel > LOGLEVEL_WARNING) {
|
||||
return;
|
||||
}
|
||||
trace(message, "warning");
|
||||
trace(message, 'warning');
|
||||
}
|
||||
|
||||
// prefix log with "debug"
|
||||
// prefix log with 'debug'
|
||||
function debug(message) {
|
||||
if (loglevel > LOGLEVEL_DEBUG) {
|
||||
return;
|
||||
}
|
||||
trace(message, "debug");
|
||||
trace(message, 'debug');
|
||||
}
|
||||
|
||||
// prefix log with "error"
|
||||
// prefix log with 'error'
|
||||
function error(message) {
|
||||
if (loglevel > LOGLEVEL_ERROR) {
|
||||
return;
|
||||
}
|
||||
trace(message, "error");
|
||||
if (message.stack) {
|
||||
trace(message.stack, 'error');
|
||||
return;
|
||||
}
|
||||
if (message.errors !== undefined) {
|
||||
for (let index = 0; index < message.errors.length; index++) {
|
||||
trace(message.errors[index], 'error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (message.message) {
|
||||
trace(message.message, 'error');
|
||||
return;
|
||||
}
|
||||
trace(message, 'error');
|
||||
}
|
||||
|
||||
// default logging function
|
||||
|
@ -80,31 +126,32 @@ function trace(message, prefix) {
|
|||
return;
|
||||
}
|
||||
if (prefix === undefined || prefix === null || prefix.length === 0) {
|
||||
prefix = "info";
|
||||
prefix = 'info';
|
||||
}
|
||||
let print;
|
||||
switch (prefix) {
|
||||
case "error":
|
||||
case 'error':
|
||||
print = console.error;
|
||||
break;
|
||||
case "debug":
|
||||
case 'debug':
|
||||
print = console.debug;
|
||||
break;
|
||||
case "warning":
|
||||
case 'warning':
|
||||
print = console.warn;
|
||||
break;
|
||||
default:
|
||||
print = console.log;
|
||||
}
|
||||
message = moment().format(config.server.timestamp) + " | " + prefix + " > " + message;
|
||||
message = moment().format(timestamp) + ' | ' + prefix + ' > ' + message;
|
||||
print(message);
|
||||
}
|
||||
|
||||
// exports
|
||||
module.exports = {
|
||||
initialize,
|
||||
info,
|
||||
warn,
|
||||
debug,
|
||||
error,
|
||||
request
|
||||
};
|
||||
http
|
||||
}
|
|
@ -1,50 +1,75 @@
|
|||
const config = require('../config.json');
|
||||
const logger = require('../libs/logger.js');
|
||||
const commands = require('../libs/commands.js');
|
||||
const http = require('http');
|
||||
const { time } = require('console');
|
||||
|
||||
var server;
|
||||
var api;
|
||||
let server;
|
||||
let api;
|
||||
|
||||
function start(callback) {
|
||||
async function start() {
|
||||
const listen = global.config?.server?.listen || '0.0.0.0';
|
||||
const port = global.config?.server?.port;
|
||||
buildAPI();
|
||||
if (!server) {
|
||||
if (server === undefined) {
|
||||
server = http.createServer();
|
||||
}
|
||||
server.listen(config.server.port, config.server.listen)
|
||||
return new Promise((resolve, reject) => {
|
||||
server.listen(port, listen)
|
||||
.on('listening', function () {
|
||||
logger.debug('server listening on ' + config.server.listen + ':' + config.server.port + '...');
|
||||
handleRequests();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleRequests() {
|
||||
server.on('request', function (request, response) {
|
||||
logger.request(request);
|
||||
var endpoint = api.get(request.url);
|
||||
if (!endpoint) {
|
||||
response.writeHead(501);
|
||||
response.end('endpoint not defined\n');
|
||||
return;
|
||||
}
|
||||
if (request.method.toLowerCase() != (endpoint.type.toLowerCase())) {
|
||||
response.writeHead(405);
|
||||
response.end('endpoint does not support ' + request.method + ' requests\n');
|
||||
return;
|
||||
}
|
||||
commands.execute(endpoint);
|
||||
response.end();
|
||||
server.on('request', (request, response) => {
|
||||
request.timestamp = new Date().getTime();
|
||||
respond(request, response, api.get(request.url));
|
||||
});
|
||||
}
|
||||
|
||||
function buildAPI(callback) {
|
||||
if (!config.api) {
|
||||
logger.warn('no api defined');
|
||||
async function respond(request, response, endpoint) {
|
||||
if (response === undefined) {
|
||||
return;
|
||||
}
|
||||
let data = {
|
||||
status: 'ok'
|
||||
};
|
||||
let code = 200;
|
||||
if (endpoint === undefined) {
|
||||
code = 501;
|
||||
data.status = 'error';
|
||||
data.msg = 'endpoint not defined';
|
||||
} else if (request.method.toLowerCase() !== (endpoint.type.toLowerCase())) {
|
||||
code = 405;
|
||||
data.status = 'error';
|
||||
data.msg = 'endpoint does not support ' + request.method + ' requests';
|
||||
} else {
|
||||
try {
|
||||
data.result = await commands.execute(endpoint);
|
||||
} catch (err) {
|
||||
code = 501;
|
||||
data.status = 'error';
|
||||
data.msg = err;
|
||||
}
|
||||
}
|
||||
const json = JSON.stringify(data);
|
||||
response.writeHead(code);
|
||||
response.end(json);
|
||||
logger.http({ request: request, code: code, data: data });
|
||||
}
|
||||
|
||||
function buildAPI() {
|
||||
const apiConfig = global.config?.api;
|
||||
if (apiConfig === undefined || apiConfig.length === 0) {
|
||||
throw new Error('no api endpoints configured - aborting');
|
||||
}
|
||||
api = new Map();
|
||||
config.api.forEach(function(endpoint) {
|
||||
var url = endpoint.url;
|
||||
var tmp = endpoint;
|
||||
config.api.forEach(function (endpoint) {
|
||||
let url = endpoint.url;
|
||||
let tmp = endpoint;
|
||||
delete tmp.url;
|
||||
api.set(url, tmp);
|
||||
});
|
||||
|
|
48
remex.js
48
remex.js
|
@ -1,11 +1,49 @@
|
|||
const logger = require('./libs/logger.js');
|
||||
const packageJSON = require('./package.json');
|
||||
const server = require('./libs/server.js')
|
||||
const server = require('./libs/server.js');
|
||||
const path = require('path');
|
||||
|
||||
logger.info("launching " + packageJSON.name + " " + packageJSON.version)
|
||||
server.start(function(err) {
|
||||
const INTERRUPTS = ['beforeExit', 'SIGINT', 'SIGTERM'];
|
||||
|
||||
main();
|
||||
|
||||
async function main() {
|
||||
let configPath = path.resolve('./config.json');
|
||||
try {
|
||||
global.config = require(configPath);
|
||||
} catch (err) {
|
||||
logger.warn('could not read config file at \'' + configPath + '\'');
|
||||
}
|
||||
logger.initialize();
|
||||
handleExit();
|
||||
logger.info("launching " + packageJSON.name + " " + packageJSON.version + "...");
|
||||
try {
|
||||
await server.start();
|
||||
} catch (err) {
|
||||
exit(err);
|
||||
}
|
||||
};
|
||||
|
||||
function handleExit() {
|
||||
for (var index = 0; index < INTERRUPTS.length; index++) {
|
||||
process.on(INTERRUPTS[index], async (code) => {
|
||||
exit(undefined, code);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function exit(err, code) {
|
||||
if (code === undefined) {
|
||||
code = 0;
|
||||
if (err !== undefined) {
|
||||
code = 1;
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
logger.error(packageJSON.name + ' ' + packageJSON.version + ' ended due to an error');
|
||||
} else {
|
||||
logger.info(packageJSON.name + ' ' + packageJSON.version + ' shutting down gracefully')
|
||||
}
|
||||
});
|
||||
process.exit(code);
|
||||
}
|
Loading…
Reference in a new issue