rtjscomp 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +16 -9
  2. package/rtjscomp.js +191 -158
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "rtjscomp",
3
- "author": "L3P3 <dev@l3p3.de> (https://l3p3.de)",
4
- "license": "Zlib",
5
- "version": "0.8.1",
3
+ "version": "0.8.2",
6
4
  "description": "php-like server but with javascript",
7
- "keywords": [
8
- "http",
9
- "javascript",
10
- "server"
11
- ],
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/L3P3/rtjscomp"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/L3P3/rtjscomp/issues"
11
+ },
12
12
  "dependencies": {
13
13
  "ipware": "latest",
14
14
  "parse-multipart-data": "latest",
@@ -19,5 +19,12 @@
19
19
  },
20
20
  "bin": {
21
21
  "rtjscomp": "./rtjscomp.js"
22
- }
22
+ },
23
+ "keywords": [
24
+ "http",
25
+ "javascript",
26
+ "server"
27
+ ],
28
+ "author": "L3P3 <dev@l3p3.de> (https://l3p3.de)",
29
+ "license": "Zlib"
23
30
  }
package/rtjscomp.js CHANGED
@@ -26,6 +26,7 @@ const AGENT_CHECK_BOT = /bot|googlebot|crawler|spider|robot|crawling|favicon/i;
26
26
  const AGENT_CHECK_MOBIL = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i;
27
27
  const HTTP_LIST_REG = /,\s*/;
28
28
 
29
+ let log_verbose = process.argv.includes('-v');
29
30
  let port_http = 0;
30
31
  let port_https = 0;
31
32
  const file_type_mimes = new Map;
@@ -61,7 +62,7 @@ if (!Object.fromEntries) {
61
62
  global.globals = rtjscomp;
62
63
  global.actions = rtjscomp.actions;
63
64
  global.data_load = name => {
64
- log('[deprecated!] load: ' + name);
65
+ log('[deprecated] load: ' + name);
65
66
  try {
66
67
  return fs.readFileSync(PATH_DATA + name, 'utf8');
67
68
  }
@@ -70,7 +71,7 @@ global.data_load = name => {
70
71
  }
71
72
  }
72
73
  global.data_save = (name, data) => (
73
- log('[deprecated!] save: ' + name),
74
+ log('[deprecated] save: ' + name),
74
75
  fs.writeFileSync(PATH_DATA + name, data, 'utf8')
75
76
  )
76
77
  global.number_check_int = number => (
@@ -81,13 +82,12 @@ global.number_check_uint = number => (
81
82
  )
82
83
 
83
84
  rtjscomp.data_load = async name => {
84
- log('load: ' + name);
85
+ if (log_verbose) log('load: ' + PATH_DATA + name);
85
86
  const data = await fsp.readFile(PATH_DATA + name, 'utf8').catch(() => null);
86
87
  return name.endsWith('.json') ? JSON.parse(data || null) : data;
87
88
  }
88
89
  rtjscomp.data_load_watch = (name, callback) => (
89
90
  file_keep_new(PATH_DATA + name, data => (
90
- log('load: ' + name),
91
91
  callback(
92
92
  name.endsWith('.json')
93
93
  ? JSON.parse(data || null)
@@ -96,7 +96,7 @@ rtjscomp.data_load_watch = (name, callback) => (
96
96
  ))
97
97
  )
98
98
  rtjscomp.data_save = (name, data) => (
99
- log('save: ' + name),
99
+ log_verbose && log('save: ' + PATH_DATA + name),
100
100
  fsp.writeFile(
101
101
  PATH_DATA + name,
102
102
  name.endsWith('.json') ? JSON.stringify(data) : data,
@@ -119,68 +119,99 @@ const custom_require = path => {
119
119
  }
120
120
 
121
121
  const services_active = new Map;
122
+ const services_loading = new Set;
122
123
  const services_list_react = async () => {
123
124
  await Promise.all(
124
125
  Array.from(services_active.entries())
125
126
  .filter(([path, _]) => !services.has(path))
126
127
  .map(([_, service_object]) => service_stop(service_object, true))
127
128
  );
128
- for (const path of services) {
129
- if (!services_active.has(path)) await service_start(path);
129
+ for (const path of services)
130
+ if (!services_active.has(path)) {
131
+ await service_start(path);
130
132
  }
131
133
  }
132
134
  const service_start = async path => {
133
135
  const service_object = {
136
+ content: null,
137
+ handler_stop: null,
134
138
  path,
135
- start: null,
136
- started: false,
137
- stop: null,
138
139
  stopped: false,
139
140
  };
140
141
 
141
142
  await file_keep_new(PATH_PUBLIC + path + '.service.js', async file_content => {
142
143
  if (file_content === null) {
143
- log('error, service file not found: ' + path);
144
- await service_stop(service_object, true);
145
- return;
144
+ log('[error] service file not found: ' + path);
145
+ return service_stop(service_object, true);
146
146
  }
147
- await service_stop_handler(service_object);
148
- await service_start_inner(path, service_object, file_content);
147
+ if (services_loading.size > 0) {
148
+ await Promise.all(Array.from(services_loading));
149
+ }
150
+ const start_promise = service_start_inner(path, service_object, file_content);
151
+ services_loading.add(start_promise);
152
+ await start_promise;
153
+ services_loading.delete(start_promise);
149
154
  });
150
155
  }
151
156
  const service_start_inner = async (path, service_object, file_content) => {
157
+ if (services_active.has(path)) {
158
+ await service_stop_handler(service_object);
159
+ }
160
+ const content_object = service_object.content = {};
161
+ log('start service: ' + path);
162
+
163
+ const start_interval = setInterval(() => {
164
+ log('[warning] still starting service: ' + path);
165
+ }, 1e3);
166
+
152
167
  try {
153
- const fun = new Function(
154
- 'require',
155
- `const log=a=>rtjscomp.log(${
168
+ const fun = (0, eval)(
169
+ `(async function(require){const log=a=>rtjscomp.log(${
156
170
  JSON.stringify(path + ': ')
157
- }+a);${file_content}`
171
+ }+a);${file_content + '\n'}})`
158
172
  );
159
- fun.call(service_object, custom_require);
173
+ const result = await fun.call(content_object, custom_require);
174
+ if (service_object.stopped) {
175
+ clearInterval(start_interval);
176
+ return;
177
+ }
178
+ if (typeof result === 'function') {
179
+ service_object.handler_stop = result;
180
+ }
160
181
  }
161
182
  catch (err) {
162
- log(`error in service ${path}: ${err.message}`);
163
- await service_stop(service_object, false);
164
- return;
183
+ clearInterval(start_interval);
184
+ log(`[error] ${path}: ${err.message}`);
185
+ if (service_object.stopped) return;
186
+ return service_stop(service_object, false);
165
187
  }
166
188
 
167
- if (service_object.start) {
189
+ const handler_start = content_object.start;
190
+ if (handler_start) {
191
+ log('[deprecated] service has start method: ' + path);
192
+ delete content_object.start;
168
193
  try {
169
- await service_object.start();
170
- service_object.start = null;
171
- service_object.started = true;
194
+ await handler_start();
172
195
  }
173
196
  catch (err) {
174
- services_active.delete(path);
175
- log(`error while starting ${path}: ${err.message}`);
176
- return;
197
+ clearInterval(start_interval);
198
+ log(`[error] ${path} start: ${err.message}`);
199
+ return service_stop(service_object, false);
177
200
  }
178
201
  }
202
+ clearInterval(start_interval);
203
+
204
+ if (content_object.stop) {
205
+ log('[deprecated] service has stop method: ' + path);
206
+ service_object.handler_stop = content_object.stop;
207
+ delete content_object.stop;
208
+ }
209
+
179
210
  services_active.set(path, service_object);
180
- log('service started: ' + path);
211
+ if (log_verbose) log('started service: ' + path);
181
212
  }
182
213
  const services_shutdown = () => (
183
- log('shutdown services...'),
214
+ log_verbose && log('shutdown services...'),
184
215
  Promise.all(
185
216
  Array.from(services_active.values())
186
217
  .map(service_object => service_stop(service_object, true))
@@ -190,28 +221,39 @@ const service_stop = async (service_object, forget) => {
190
221
  service_object.stopped = true;
191
222
  if (forget) fs.unwatchFile(PATH_PUBLIC + service_object.path + '.service.js');
192
223
  await service_stop_handler(service_object);
193
- services_active.delete(service_object.path);
194
- log('service stopped: ' + service_object.path);
195
224
  }
196
225
  const service_stop_handler = async service_object => {
197
- if (service_object.stop) {
226
+ services_active.delete(service_object.path);
227
+ log('stop service: ' + service_object.path);
228
+ const handler_stop = service_object.handler_stop;
229
+ if (handler_stop) {
230
+ const stop_interval = setInterval(() => {
231
+ log('[warning] still stopping service: ' + service_object.path);
232
+ }, 1e3);
198
233
  try {
199
- await service_object.stop();
200
- service_object.stop = null;
234
+ service_object.handler_stop = null;
235
+ await handler_stop();
201
236
  }
202
237
  catch (err) {
203
- log(`error while stopping ${service_object.path}: ${err.message}`);
238
+ log(`[error] ${service_object.path} stop: ${err.message}`);
204
239
  }
240
+ clearInterval(stop_interval);
205
241
  }
242
+ if (log_verbose) log('stopped service: ' + service_object.path);
206
243
  }
207
244
  global.service_require = path => {
208
245
  const service = services_active.get(path);
209
- if (service) return service;
246
+ if (service != null) return service.content;
210
247
  throw new Error('service required: ' + path);
211
248
  }
212
- global.service_require_try = path => (
213
- services_active.get(path) || null
214
- )
249
+ global.service_require_try = path => {
250
+ const service = services_active.get(path);
251
+ return (
252
+ service != null
253
+ ? service.content
254
+ : null
255
+ );
256
+ }
215
257
 
216
258
  const map_generate_bol = (set, data) => {
217
259
  set.clear();
@@ -237,7 +279,7 @@ const map_generate_equ = (map, data) => {
237
279
 
238
280
  const file_compare = (curr, prev, path) => (
239
281
  curr.mtime > prev.mtime && (
240
- log('file changed: ' + path),
282
+ log_verbose && log('file changed: ' + path),
241
283
  true
242
284
  )
243
285
  )
@@ -251,7 +293,9 @@ const file_watch = (path, callback) => (
251
293
  )
252
294
  const file_keep_new = async (path, callback) => {
253
295
  try {
254
- await callback(await fsp.readFile(path, 'utf8'));
296
+ const data = await fsp.readFile(path, 'utf8');
297
+ if (log_verbose) log('load file: ' + path);
298
+ await callback(data);
255
299
  fs.watchFile(path, async (curr, prev) => {
256
300
  if (file_compare(curr, prev, path)) {
257
301
  await callback(
@@ -272,7 +316,7 @@ actions.log_clear = () => {
272
316
  const log = rtjscomp.log = msg => (
273
317
  console.log(msg),
274
318
  log_history.push(msg),
275
- spam('log', [msg])
319
+ spam_enabled ? spam('log', [msg]) : undefined
276
320
  )
277
321
 
278
322
  const spam_enabled = fs.existsSync('spam.csv');
@@ -281,17 +325,16 @@ actions.spam_save = async (muted = false) => {
281
325
  if (!spam_enabled) return;
282
326
 
283
327
  try {
284
- fsp.appendFile('spam.csv', rtjscomp.spam_history, 'utf8');
328
+ const tmp = rtjscomp.spam_history;
285
329
  rtjscomp.spam_history = '';
286
- muted || log('spam.csv saved');
330
+ await fsp.appendFile('spam.csv', tmp, 'utf8');
331
+ if (log_verbose && !muted) log('spam.csv saved');
287
332
  }
288
333
  catch (err) {
289
- log('error saving spam.csv: ' + err.message);
334
+ log('[error] cannot save spam.csv: ' + err.message);
290
335
  }
291
336
  }
292
337
  const spam = (type, data) => {
293
- if (!spam_enabled) return;
294
-
295
338
  rtjscomp.spam_history += (
296
339
  Date.now() +
297
340
  ',' +
@@ -315,7 +358,7 @@ const request_handle = async (request, response, https) => {
315
358
  https = request_headers['x-forwarded-proto'] === 'https';
316
359
  }
317
360
 
318
- spam('request', [https, request.url, request_ip]);
361
+ if (spam_enabled) spam('request', [https, request.url, request_ip]);
319
362
 
320
363
  try {
321
364
  const request_url_parsed = url.parse(request.url, false);
@@ -422,11 +465,11 @@ const request_handle = async (request, response, https) => {
422
465
  file_function = file_cache_functions.get(path);
423
466
  }
424
467
  else {
425
- log(`load ${
468
+ if (log_verbose) log(`load ${
426
469
  file_dyn_enabled
427
470
  ? 'dynam'
428
471
  : 'stat'
429
- }ic file: ${path}`);
472
+ }ic file: ${path_real}`);
430
473
 
431
474
  if (
432
475
  file_privates.has(path) ||
@@ -516,14 +559,14 @@ const request_handle = async (request, response, https) => {
516
559
  }
517
560
 
518
561
  try {
519
- file_function = eval(code += '}');
562
+ file_function = (0, eval)(code += '}');
520
563
  }
521
564
  catch (err) {
522
565
  throw err.message;
523
566
  }
524
567
  }
525
568
  catch (err) {
526
- log('compile error: ' + err);
569
+ log(`[error] ${path} compile: ${err}`);
527
570
  throw 500;
528
571
  }
529
572
 
@@ -578,7 +621,7 @@ const request_handle = async (request, response, https) => {
578
621
  );
579
622
  }
580
623
  catch (err) {
581
- log('request query error: ' + err.message);
624
+ log(`[error] ${path} request query: ${err.message}`);
582
625
  throw 400;
583
626
  }
584
627
  }
@@ -613,7 +656,7 @@ const request_handle = async (request, response, https) => {
613
656
  }
614
657
  }
615
658
  catch (err) {
616
- log('request body error: ' + err.message);
659
+ log(`[error] ${path} request body: ${err.message}`);
617
660
  throw 400;
618
661
  }
619
662
  }
@@ -641,7 +684,7 @@ const request_handle = async (request, response, https) => {
641
684
  file_function_output = response;
642
685
  }
643
686
 
644
- spam('execute', [
687
+ if (spam_enabled) spam('execute', [
645
688
  path,
646
689
  Object.fromEntries(
647
690
  Object.entries(file_function_input)
@@ -653,6 +696,10 @@ const request_handle = async (request, response, https) => {
653
696
  )
654
697
  ]);
655
698
 
699
+ if (services_loading.size > 0) {
700
+ await Promise.all(Array.from(services_loading));
701
+ }
702
+
656
703
  try {
657
704
  await file_function(
658
705
  file_function_input,
@@ -665,7 +712,7 @@ const request_handle = async (request, response, https) => {
665
712
  }
666
713
  catch (err) {
667
714
  if (err instanceof Error) {
668
- log(`error in file ${path}: ${err.message}`);
715
+ log(`[error] ${path}: ${err.message}`);
669
716
 
670
717
  if (err.message.startsWith('service required: ')) {
671
718
  err = 503;
@@ -698,7 +745,7 @@ const request_handle = async (request, response, https) => {
698
745
  file_data = fs.createReadStream(path_real);
699
746
  }
700
747
 
701
- spam('static_send', [path, file_gz_enabled]);
748
+ if (spam_enabled) spam('static_send', [path, file_gz_enabled]);
702
749
  response.setHeader('Cache-Control', 'public, max-age=600');
703
750
 
704
751
  if (file_gz_enabled) {
@@ -718,8 +765,8 @@ const request_handle = async (request, response, https) => {
718
765
  err = 500;
719
766
  }
720
767
 
721
- if (err >= 400) {
722
- log(`error ${err} at request: ${request_ip}; ${request.url}`);
768
+ if (err >= 400 && log_verbose) {
769
+ log(`[error] request failed: ${err}; ${request_ip}; ${request.url}`);
723
770
  }
724
771
 
725
772
  response.writeHead(err, {
@@ -733,32 +780,33 @@ const request_handle = async (request, response, https) => {
733
780
  let exiting = false;
734
781
  actions.halt = async () => {
735
782
  await Promise.all([
736
- actions.http_stop(),
783
+ actions.http_stop && actions.http_stop(),
737
784
  actions.https_stop && actions.https_stop(),
738
785
  services_shutdown(),
739
- ].filter(Boolean));
786
+ ]);
740
787
  await actions.spam_save();
741
788
  log('stopped everything');
742
789
  }
743
790
  actions.exit = async status => {
744
791
  if (exiting) return;
792
+ exiting = true;
745
793
  if (typeof status !== 'number') status = 0;
746
794
  await actions.halt();
747
795
  log('exiting...');
748
- exiting = true;
749
796
  process.exit(status);
750
797
  }
751
798
 
752
799
  process.on('uncaughtException', err => {
753
- err = err.message || err;
754
800
  if (typeof err === 'symbol') err = err.toString();
755
- log('error uncaughtException: ' + err);
756
- console.log(err);
801
+ log('[error] uncaughtException: ' + (err.message || err));
802
+ console.error(err);
803
+ if (exiting) process.exit(1);
757
804
  actions.exit(1);
758
805
  });
759
806
  process.on('unhandledRejection', err => {
760
- log('error unhandledRejection: ' + (err.message || err));
761
- console.log(err);
807
+ log('[error] unhandledRejection: ' + (err.message || err));
808
+ console.error(err);
809
+ if (exiting) process.exit(1);
762
810
  actions.exit(1);
763
811
  });
764
812
  process.on('exit', actions.exit);
@@ -776,7 +824,7 @@ await Promise.all([
776
824
  fsp.stat(PATH_PUBLIC).catch(_ => null),
777
825
  ]).then(([stat_config, stat_data, stat_public]) => {
778
826
  if (!stat_config) {
779
- log('creating config template directory');
827
+ log('create config template directory');
780
828
  fs.mkdirSync(PATH_CONFIG);
781
829
  fs.mkdirSync(PATH_CONFIG + 'ssl');
782
830
  for (const file of 'file_type_dyns,file_type_mimes,file_type_nocompress,path_aliases,port_http,port_https,services'.split(',')) {
@@ -798,32 +846,30 @@ await Promise.all([
798
846
  }
799
847
  });
800
848
 
849
+ file_keep_new(PATH_CONFIG + 'services.txt', data => (
850
+ map_generate_bol(services, data),
851
+ services_list_react()
852
+ ));
853
+
801
854
  await Promise.all([
802
855
  file_keep_new(PATH_CONFIG + 'init.js', data => {
803
856
  if (!data) return;
804
- log('[deprecated!] run global init script');
857
+ log('[deprecated] run global init script');
805
858
  try {
806
859
  var require = custom_require;
807
- eval(data);
860
+ (0, eval)(data);
808
861
  }
809
862
  catch (err) {
810
- log('error in init.js: ' + err.message);
863
+ log('[error] init.js: ' + err.message);
811
864
  }
812
865
  }),
813
- file_keep_new(PATH_CONFIG + 'services.txt', async data => {
814
- log('load service list');
815
- map_generate_bol(services, data);
816
- await services_list_react();
817
- }),
818
866
  file_keep_new(PATH_CONFIG + 'file_type_mimes.txt', data => {
819
- log('load file type map');
820
867
  map_generate_equ(file_type_mimes, data);
821
868
  if (!file_type_mimes.has('txt')) {
822
869
  file_type_mimes.set('txt', 'text/plain; charset=utf-8');
823
870
  }
824
871
  }),
825
872
  file_keep_new(PATH_CONFIG + 'path_aliases.txt', data => {
826
- log('load path aliases map');
827
873
  map_generate_equ(path_aliases, data);
828
874
  path_aliases_templates.clear();
829
875
  for (const [key, value] of path_aliases.entries()) {
@@ -843,38 +889,37 @@ await Promise.all([
843
889
  }
844
890
  }),
845
891
  file_keep_new(PATH_CONFIG + 'file_type_dyns.txt', data => {
846
- log('load dynamic file type list');
847
892
  map_generate_bol(file_type_dyns, data);
848
893
  }),
849
894
  file_keep_new(PATH_CONFIG + 'file_type_nocompress.txt', data => {
850
- log('load non-compressable file list');
851
895
  map_generate_bol(file_type_nocompress, data);
852
896
  }),
853
897
  file_keep_new(PATH_CONFIG + 'file_raws.txt', data => {
854
898
  if (!data) return;
855
- log('load static file list');
856
899
  map_generate_bol(file_raws, data);
857
900
  }),
858
901
  file_keep_new(PATH_CONFIG + 'file_privates.txt', data => {
859
902
  if (!data) return;
860
- log('load private file list');
861
903
  map_generate_bol(file_privates, data);
862
904
  }),
863
905
  file_keep_new(PATH_CONFIG + 'file_blocks.txt', data => {
864
906
  if (!data) return;
865
- log('load blocked file list');
866
907
  map_generate_bol(file_blocks, data);
867
908
  }),
868
909
  ]);
869
910
 
870
911
  let connections_count = 0;
871
- const server_http = http.createServer(
872
- (request, response) => request_handle(request, response, false)
873
- );
874
912
  let http_status = false;
875
913
  let http_status_target = false;
914
+ let http_listened_resolve = null;
876
915
  const http_connections = new Map;
877
-
916
+ const server_http = http.createServer(
917
+ (request, response) => request_handle(request, response, false)
918
+ );
919
+ server_http.on('error', err => {
920
+ log('[error] http: ' + err.message);
921
+ http_listened_resolve && http_listened_resolve();
922
+ });
878
923
  server_http.on('connection', connection => {
879
924
  const id = ++connections_count;
880
925
  http_connections.set(id, connection);
@@ -883,71 +928,67 @@ server_http.on('connection', connection => {
883
928
  });
884
929
  });
885
930
 
886
- actions.http_start = () => {
887
- if (http_status) return;
888
- try {
889
- server_http.listen(port_http);
890
- http_status = http_status_target = true;
891
- log('http started at port ' + port_http);
892
- }
893
- catch (err) {
894
- log('error while starting http: ' + err.message);
895
- }
896
- }
897
- actions.http_restart = () => {
898
- if (!http_status) actions.http_start();
899
- else if (http_status_target) {
900
- http_status_target = false;
901
- log('http is restarting...');
902
- server_http.close(() => {
903
- http_status = false;
904
- log('http stopped');
905
- actions.http_start();
906
- });
931
+ actions.http_start = async () => {
932
+ await actions.http_stop();
933
+ http_status_target = true;
934
+ log('start http: http://localhost:' + port_http);
935
+ await new Promise(resolve => server_http.listen(port_http, http_listened_resolve = resolve));
936
+ if (http_listened_resolve) http_listened_resolve = null;
937
+ else{
938
+ http_status = true;
939
+ if (log_verbose) log('started http');
907
940
  }
908
941
  }
909
942
  actions.http_stop = async () => {
910
- if (!http_status_target || !http_status) return;
943
+ if (!http_status_target) return;
911
944
  http_status_target = false;
912
- log('http is stopping...');
945
+ log('stop http');
946
+ const kill_timeout = setTimeout(actions.http_kill, 5e3);
913
947
  await new Promise(resolve => server_http.close(resolve));
948
+ clearTimeout(kill_timeout);
914
949
  http_status = false;
915
- log('http stopped');
950
+ if (log_verbose) log('stopped http');
916
951
  }
917
- actions.http_kill = () => {
918
- if (http_status_target || !http_status) return;
919
- log('killing http...');
920
- for (const connection of http_connections.values()) connection.destroy();
952
+ actions.http_kill = async () => {
953
+ if (http_status_target) return;
954
+ log('kill http');
955
+ await Promise.all(
956
+ Array.from(http_connections.values())
957
+ .map(connection => connection.destroy())
958
+ );
959
+ if (log_verbose) log('killed http');
921
960
  http_connections.clear();
922
961
  }
923
962
 
924
963
  file_keep_new(PATH_CONFIG + 'port_http.txt', data => {
925
- log('load http port number');
926
964
  if (
927
965
  !data ||
928
966
  isNaN(data = Number(data)) ||
929
967
  !number_check_uint(data)
930
968
  ) {
931
- log('error: invalid http port number');
969
+ log('[error] http: invalid port number');
932
970
  }
933
971
  else if (data !== port_http) {
934
972
  port_http = data;
935
- actions.http_restart();
973
+ actions.http_start();
936
974
  }
937
975
  });
938
976
 
939
977
  try {
940
978
  const https_key = fs.readFileSync(PATH_CONFIG + 'ssl/domain.key');
941
979
  const https_cert = fs.readFileSync(PATH_CONFIG + 'ssl/chained.pem');
980
+ let https_status = false;
981
+ let https_status_target = false;
982
+ let https_listened_resolve = null;
983
+ const https_connections = new Map;
942
984
  const server_https = require('https').createServer(
943
985
  {key: https_key, cert: https_cert},
944
986
  (request, response) => request_handle(request, response, true)
945
987
  );
946
-
947
- let https_status = false;
948
- let https_status_target = false;
949
- const https_connections = new Map;
950
-
988
+ server_https.on('error', err => {
989
+ log('[error] https: ' + err.message);
990
+ https_listened_resolve && https_listened_resolve();
991
+ });
951
992
  server_https.on('connection', connection => {
952
993
  const id = ++connections_count;
953
994
  https_connections.set(id, connection);
@@ -956,61 +997,53 @@ try {
956
997
  });
957
998
  });
958
999
 
959
- actions.https_start = () => {
960
- if (https_status) return;
961
- try {
962
- server_https.listen(port_https);
963
- https_status = https_status_target = true;
964
- log('https started at port ' + port_https);
965
- }
966
- catch (err) {
967
- log('error while starting https: ' + err.message);
968
- }
969
- }
970
- actions.https_restart = () => {
971
- if (!https_status) actions.https_start();
972
- else if (https_status_target) {
973
- https_status_target = false;
974
- log('https is restarting...');
975
- server_https.close(function () {
976
- https_status = false;
977
- log('https stopped');
978
- actions.https_start();
979
- });
1000
+ actions.https_start = async () => {
1001
+ await actions.https_stop();
1002
+ https_status_target = true;
1003
+ log('start https: https://localhost:' + port_https);
1004
+ await new Promise(resolve => server_https.listen(port_https, https_listened_resolve = resolve));
1005
+ if (https_listened_resolve) https_listened_resolve = null;
1006
+ else{
1007
+ https_status = true;
1008
+ if (log_verbose) log('started https');
980
1009
  }
981
1010
  }
982
1011
  actions.https_stop = async () => {
983
- if (!https_status_target || !https_status) return;
1012
+ if (!https_status_target) return;
984
1013
  https_status_target = false;
985
- log('https is stopping...');
1014
+ log('stop https');
1015
+ const kill_timeout = setTimeout(actions.https_kill, 5000);
986
1016
  await new Promise(resolve => server_https.close(resolve));
1017
+ clearTimeout(kill_timeout);
987
1018
  https_status = false;
988
- log('https stopped');
1019
+ if (log_verbose) log('stopped https');
989
1020
  }
990
- actions.https_kill = () => {
991
- if (https_status_target || !https_status) return;
992
- log('killing https...');
993
- for (const connection of https_connections.values()) connection.destroy();
1021
+ actions.https_kill = async () => {
1022
+ if (https_status_target) return;
1023
+ log('kill https');
1024
+ await Promise.all(
1025
+ Array.from(https_connections.values()).map(connection => connection.destroy())
1026
+ );
1027
+ if (log_verbose) log('killed https');
994
1028
  https_connections.clear();
995
1029
  }
996
1030
 
997
1031
  file_keep_new(PATH_CONFIG + 'port_https.txt', data => {
998
- log('load https port number');
999
1032
  if (
1000
1033
  !data ||
1001
1034
  isNaN(data = Number(data)) ||
1002
1035
  !number_check_uint(data)
1003
1036
  ) {
1004
- log('error: invalid https port number');
1037
+ log('[error] https: invalid port number');
1005
1038
  }
1006
1039
  else if (data !== port_https) {
1007
1040
  port_https = data;
1008
- actions.https_restart();
1041
+ actions.https_start();
1009
1042
  }
1010
1043
  });
1011
1044
  }
1012
1045
  catch (err) {
1013
- log('https is disabled');
1046
+ if (log_verbose) log('https: no cert, disabled');
1014
1047
  }
1015
1048
 
1016
1049
  })();