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