Skip to content
This repository was archived by the owner on Jan 6, 2021. It is now read-only.

Commit 8c47369

Browse files
committed
Changed method of tasks starting
Added tasks queue, tasks with same config now firing after all tasks of this type processed Simplified run method Corrected data which writes to log
1 parent b269e20 commit 8c47369

File tree

2 files changed

+175
-168
lines changed

2 files changed

+175
-168
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Configuration parameters:
3535

3636
TODO
3737
===
38+
* Queue class with container inside and few helper methods, shift the save state problem on it.
39+
* Get user id in system (id -u {cfg.user})
3840
* Variables in command definition
3941
* Commands string instade of array.
40-
* cfg.require parameter with applying the cfg.commands results
42+
* cfg.require parameter with applying the cfg.commands results

app.js

+172-167
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,172 @@
1-
//Dependencies
2-
var http = require("http");
3-
var fs = require("fs");
4-
var path = require("path");
5-
var child_process = require('child_process');
6-
var log = require("./logging");
7-
//Runtime variables
8-
var cfg_dir = __dirname + '/config/';
9-
var cfg_map = {};
10-
11-
//Format function, move somewhere
12-
String.prototype.fmt = function(hash) {
13-
var s = this.toString();
14-
if(typeof hash == 'object') {
15-
for(var k in hash){
16-
s = s.split('{' + k + '}').join(hash[k]);
17-
}
18-
}
19-
return s;
20-
};
21-
22-
var processFile = function(fileName){
23-
var filePath = cfg_dir + fileName;
24-
var fileExt = path.extname(fileName);
25-
if(fileExt != '.json'){
26-
return log('Problem with file "' + filePath + '". There must be .json file extension.', 'runtime');
27-
}
28-
29-
fs.readFile(filePath, 'utf-8', function(err, data) {
30-
var cfg = {};
31-
try{
32-
if(err) throw err;
33-
34-
cfg = JSON.parse(data);
35-
if([cfg.path, cfg.user, cfg.commands].indexOf(undefined) !== -1){
36-
throw new Error('Bad config file "' + filePath + '". It need to be json object with path, user and commands keys.');
37-
}
38-
} catch(e) {
39-
return log('Error while processing file "' + filePath + '": ' + e, 'runtime');
40-
}
41-
//Populate good cfg object to objects map by filename without extension
42-
return cfg_map[path.basename(fileName, fileExt)] = cfg;
43-
});
44-
};
45-
46-
// Readfiles to object on server start
47-
fs.readdir(cfg_dir, function(wtf, files){
48-
var watchCallback = function(prev, next) {
49-
processFile(files[i]);
50-
};
51-
52-
for(var i in files){
53-
try{
54-
processFile(files[i]);
55-
fs.watchFile(cfg_dir + files[i], watchCallback);
56-
} catch(e) {
57-
log(e, 'startup');
58-
}
59-
}
60-
61-
//Watch for changes
62-
fs.watch(cfg_dir, function(event, fileName) {
63-
processFile(fileName);
64-
});
65-
});
66-
67-
//Server options
68-
if(process.argv[2]){
69-
var run_argv = process.argv[2].split(':');
70-
process.env.IP = run_argv[0] || '0.0.0.0';
71-
process.env.PORT = run_argv[1];
72-
}
73-
process.env.IP = process.env.IP || '0.0.0.0';
74-
process.env.PORT = process.env.PORT || 8001;
75-
76-
//Create Server
77-
http.createServer(function(request, response) {
78-
request.url = request.url.slice(1);
79-
80-
//Prevent favicon.ico requests
81-
if(request.url == 'favicon.ico') return request.connection.destroy();
82-
83-
if(request.method == 'POST' && cfg_map[request.url]){
84-
var body = '';
85-
request.on('data', function (data) {
86-
body += data;
87-
if (body.length > 1e6) {
88-
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
89-
request.connection.destroy();
90-
}
91-
});
92-
93-
request.on('end', function () {
94-
try{
95-
var bodyObj = JSON.parse(body);
96-
} catch(e) {
97-
return log('Malformed json. Request body: ' + body, request.url + '.error');
98-
}
99-
100-
var cfg = cfg_map[request.url];
101-
var spawn_options = {
102-
encoding: "utf-8",
103-
env: process.env
104-
};
105-
106-
if(cfg.user) {
107-
//id -u {cfg.user}
108-
spawn_options.uid = cfg.user;
109-
}
110-
111-
try{
112-
fs.readdirSync(cfg.path);
113-
spawn_options.cwd = cfg.path;
114-
} catch(e) {
115-
return log('Invalid path "' + cfg.path + '" in config "' + request.url + '"', request.url + '.error');
116-
}
117-
118-
if(cfg.refs){
119-
var refsType = typeof cfg.refs;
120-
if(['string', 'object'].indexOf(refsType)){
121-
if(refsType == 'string') cfg.refs = [cfg.refs];
122-
123-
var suitableRef = Object.keys(cfg.refs).some(function (k) {
124-
return bodyObj.ref.match(cfg.refs[k]);
125-
});
126-
if(!suitableRef) return log('Ref does not fit. Aborting.', request.url + '.info');
127-
}
128-
}
129-
130-
if(cfg.commands.length){
131-
var currentCommands = JSON.parse(JSON.stringify(cfg.commands));
132-
133-
var spawnCommand = function(cmd) {
134-
var commandString = cmd.join(' ');
135-
var result = child_process.spawn(cmd.shift(), cmd, spawn_options);
136-
137-
result.stdout.on('data', stdioCallback(commandString, 'Data from "{command}": {data}', request.url + '.info'));
138-
result.stderr.on('data', stdioCallback(commandString, 'Error in "{command}": {data}', request.url + '.error'));
139-
result.on('exit', function(code, signal) {
140-
var next = currentCommands.shift();
141-
if(next) {
142-
spawnCommand(next);
143-
}
144-
});
145-
};
146-
147-
var stdioCallback = function(cmd_string, format, file) {
148-
return function(data) {
149-
log(format.fmt({
150-
command: cmd_string,
151-
data: data
152-
}));
153-
};
154-
};
155-
156-
spawnCommand(currentCommands.shift());
157-
} else {
158-
return log('No commands to execute.', request.url + '.info');
159-
}
160-
});
161-
162-
response.end("Process in queue!");
163-
} else {
164-
response.writeHead(200);
165-
response.end("There is something, you don't need know.");
166-
}
167-
}).listen(process.env.PORT, process.env.IP);
1+
//Dependencies
2+
var http = require("http");
3+
var fs = require("fs");
4+
var path = require("path");
5+
var child_process = require('child_process');
6+
var log = require("./logging");
7+
//Runtime variables
8+
var cfg_dir = __dirname + '/config/';
9+
var cfg_map = {};
10+
11+
//Server options
12+
var run_argv = process.argv[2] ? process.argv[2].split(':') : [];
13+
process.env.IP = process.env.IP || run_argv[0] || '0.0.0.0';
14+
process.env.PORT = process.env.PORT || run_argv[1] || 8001;
15+
16+
var processFile = function (fileName) {
17+
var filePath = cfg_dir + fileName;
18+
var fileExt = path.extname(fileName);
19+
if (fileExt != '.json') {
20+
return log('Problem with file "' + filePath + '". There must be .json file extension.', 'runtime');
21+
}
22+
23+
fs.readFile(filePath, 'utf-8', function (err, data) {
24+
var cfg = {};
25+
try {
26+
if (err) throw err;
27+
28+
cfg = JSON.parse(data);
29+
if ([cfg.path, cfg.user, cfg.commands].indexOf(undefined) !== -1) {
30+
throw new Error('Bad config file "' + filePath + '". It need to be json object with path, user and commands keys.');
31+
}
32+
} catch (e) {
33+
return log('Error while processing file "' + filePath + '": ' + e, 'runtime');
34+
}
35+
//Populate good cfg object to objects map by filename without extension
36+
return cfg_map[path.basename(fileName, fileExt)] = cfg;
37+
});
38+
};
39+
40+
// Readfiles to object on server start
41+
fs.readdir(cfg_dir, function (wtf, files) {
42+
var watchCallback = function (prev, next) {
43+
processFile(files[i]);
44+
};
45+
46+
for (var i in files) {
47+
try {
48+
processFile(files[i]);
49+
fs.watchFile(cfg_dir + files[i], watchCallback);
50+
} catch (e) {
51+
log(e, 'startup');
52+
}
53+
}
54+
55+
//Watch for changes
56+
fs.watch(cfg_dir, function (event, fileName) {
57+
processFile(fileName);
58+
});
59+
});
60+
61+
//Declare queue container
62+
var queue = {};
63+
64+
//Function for task-up
65+
var runTask = function(task) {
66+
queue[task.name].running = true;
67+
var cmd = task.commands.shift();
68+
if(!cmd){
69+
return (queue[task.name].running = false);
70+
}
71+
72+
var proc = child_process.spawn(cmd.shift(), cmd, task.options),
73+
cmd_string = cmd.join(' '),
74+
stdout = '',
75+
stderror = '';
76+
77+
proc.stdout.on('data', function(data) { stdout += data; });
78+
proc.stderr.on('data', function(data) { stderror += data; });
79+
proc.on('exit', function (code, signal) {
80+
//Log results of current command
81+
if(stdout) log('Data from "' + cmd_string + '": ' + stdout, task.name + '.info');
82+
if(stderror) log('Errors in "' + cmd_string + '": ' + stderror, task.name + '.error');
83+
//Run next task, pass reference to current task
84+
runTask(task);
85+
});
86+
};
87+
88+
//Run task sheduler, lol
89+
setInterval(function () {
90+
for(var name in queue){
91+
if(queue[name].tasks.length && !queue[name].running){
92+
runTask(queue[name].tasks.shift());
93+
}
94+
}
95+
}, 1000);
96+
97+
//Create Server
98+
http.createServer(function (request, response) {
99+
//Strip request.url, remove first slash
100+
request.url = request.url.slice(1);
101+
//Prevent favicon.ico requests
102+
if (request.url == 'favicon.ico') return request.connection.destroy();
103+
104+
if (request.method == 'POST' && cfg_map[request.url]) {
105+
var body = '';
106+
request.on('data', function (data) {
107+
body += data;
108+
if (body.length > 1e6) {
109+
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
110+
request.connection.destroy();
111+
}
112+
});
113+
114+
request.on('end', function () {
115+
try {
116+
var bodyObj = JSON.parse(body);
117+
} catch (e) {
118+
return log('Malformed json. Request body: ' + body, request.url + '.error');
119+
}
120+
121+
//We need object copy!
122+
var cfg = JSON.parse(JSON.stringify(cfg_map[request.url]));
123+
var spawn_options = {
124+
encoding: "utf-8",
125+
env: process.env
126+
};
127+
128+
if (cfg.user) {
129+
spawn_options.uid = cfg.user;
130+
}
131+
132+
try {
133+
fs.readdirSync(cfg.path);
134+
spawn_options.cwd = cfg.path;
135+
} catch (e) {
136+
return log('Invalid path "' + cfg.path + '" in config "' + request.url + '"', request.url + '.error');
137+
}
138+
139+
if (cfg.refs) {
140+
var refsType = typeof cfg.refs;
141+
if (['string', 'object'].indexOf(refsType)) {
142+
if (refsType == 'string') cfg.refs = [cfg.refs];
143+
144+
var suitableRef = Object.keys(cfg.refs).some(function (k) {
145+
return bodyObj.ref.match(cfg.refs[k]);
146+
});
147+
if (!suitableRef) return log('Ref does not fit. Aborting.', request.url + '.info');
148+
}
149+
}
150+
151+
if (cfg.commands.length) {
152+
cfg.name = request.url;
153+
cfg.options = spawn_options;
154+
if(typeof queue[request.url] == 'object'){
155+
queue[request.url].tasks.push(cfg);
156+
} else {
157+
queue[request.url] = {
158+
running: false,
159+
tasks: [ cfg ]
160+
};
161+
}
162+
} else {
163+
return log('No commands to execute.', request.url + '.info');
164+
}
165+
});
166+
167+
response.end("Task added to queue!");
168+
} else {
169+
response.writeHead(200);
170+
response.end("There is something, you don't need know.");
171+
}
172+
}).listen(process.env.PORT, process.env.IP);

0 commit comments

Comments
 (0)