rtjscomp 0.8.3 → 0.8.4

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 +1 -1
  2. package/rtjscomp.js +86 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rtjscomp",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "php-like server but with javascript",
5
5
  "repository": {
6
6
  "type": "git",
package/rtjscomp.js CHANGED
@@ -22,6 +22,7 @@ const PATH_PUBLIC = 'public/';
22
22
  const PATH_CONFIG = 'config/';
23
23
  const PATH_DATA = 'data/';
24
24
  const GZIP_OPTIONS = {level: 9};
25
+ const WATCH_OPTIONS = {persistent: true, interval: 1000};
25
26
  const AGENT_CHECK_BOT = /bot|googlebot|crawler|spider|robot|crawling|favicon/i;
26
27
  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
28
  const HTTP_LIST_REG = /,\s*/;
@@ -59,6 +60,29 @@ if (!Object.fromEntries) {
59
60
  };
60
61
  }
61
62
 
63
+ // workaround for bun: https://github.com/oven-sh/bun/issues/18919
64
+ let fs_watch = fs.watch;
65
+ if (typeof Bun !== 'undefined') {
66
+ const fs_watch_original = fs_watch;
67
+ const watch_callbacks = new Map;
68
+ fs_watch = (path, options, callback) => {
69
+ if (!watch_callbacks.has(path)) {
70
+ fs_watch_original(path, options, () => {
71
+ const callback = watch_callbacks.get(path);
72
+ if (callback) {
73
+ callback();
74
+ }
75
+ });
76
+ }
77
+ watch_callbacks.set(path, callback);
78
+ return {
79
+ close: () => (
80
+ watch_callbacks.set(path, null)
81
+ ),
82
+ };
83
+ }
84
+ }
85
+
62
86
  // legacy, will be removed soon!
63
87
  global.globals = rtjscomp;
64
88
  global.actions = rtjscomp.actions;
@@ -141,6 +165,7 @@ actions.module_cache_clear = () => {
141
165
  custom_require_cache.clear();
142
166
  custom_import_cache.clear();
143
167
  }
168
+ const AsyncFunction = custom_import.constructor;
144
169
 
145
170
  const services_active = new Map;
146
171
  const services_loading = new Set;
@@ -161,21 +186,25 @@ const service_start = async path => {
161
186
  handler_stop: null,
162
187
  path,
163
188
  stopped: false,
189
+ watcher: null,
164
190
  };
165
191
 
166
- await file_keep_new(PATH_PUBLIC + path + '.service.js', async file_content => {
167
- if (file_content === null) {
168
- log('[error] service file not found: ' + path);
169
- return service_stop(service_object, true);
170
- }
171
- if (services_loading.size > 0) {
172
- await Promise.all(Array.from(services_loading));
192
+ service_object.watcher = await file_keep_new(
193
+ PATH_PUBLIC + path + '.service.js',
194
+ async file_content => {
195
+ if (file_content === null) {
196
+ log('[error] service file not found: ' + path);
197
+ return service_stop(service_object, true);
198
+ }
199
+ if (services_loading.size > 0) {
200
+ await Promise.all(Array.from(services_loading));
201
+ }
202
+ const start_promise = service_start_inner(path, service_object, file_content);
203
+ services_loading.add(start_promise);
204
+ await start_promise;
205
+ services_loading.delete(start_promise);
173
206
  }
174
- const start_promise = service_start_inner(path, service_object, file_content);
175
- services_loading.add(start_promise);
176
- await start_promise;
177
- services_loading.delete(start_promise);
178
- });
207
+ );
179
208
  }
180
209
  const service_start_inner = async (path, service_object, file_content) => {
181
210
  if (services_active.has(path)) {
@@ -193,14 +222,15 @@ const service_start_inner = async (path, service_object, file_content) => {
193
222
  }
194
223
 
195
224
  try {
196
- const fun = (0, eval)(
197
- `(async function(require,custom_import){const log=a=>rtjscomp.log(${
225
+ const result = await (new AsyncFunction(
226
+ 'require',
227
+ 'custom_import',
228
+ `const log=a=>rtjscomp.log(${
198
229
  JSON.stringify(path + ': ')
199
230
  }+a);${
200
231
  file_content.replace(IMPORT_REG, 'custom_import(') + '\n'
201
- }})`
202
- );
203
- const result = await fun.call(content_object, custom_require, custom_import);
232
+ }`
233
+ )).call(content_object, custom_require, custom_import);
204
234
  if (service_object.stopped) {
205
235
  clearInterval(start_interval);
206
236
  return;
@@ -247,11 +277,12 @@ const services_shutdown = () => (
247
277
  .map(service_object => service_stop(service_object, true))
248
278
  )
249
279
  )
250
- const service_stop = async (service_object, forget) => {
251
- service_object.stopped = true;
252
- if (forget) fs.unwatchFile(PATH_PUBLIC + service_object.path + '.service.js');
253
- await service_stop_handler(service_object);
254
- }
280
+ const service_stop = (service_object, forget) => (
281
+ service_object.stopped = true,
282
+ forget && service_object.watcher &&
283
+ service_object.watcher.close(),
284
+ service_stop_handler(service_object)
285
+ )
255
286
  const service_stop_handler = async service_object => {
256
287
  services_active.delete(service_object.path);
257
288
  log('stop service: ' + service_object.path);
@@ -307,36 +338,34 @@ const map_generate_equ = (map, data) => {
307
338
  }
308
339
  }
309
340
 
310
- const file_compare = (curr, prev, path) => (
311
- curr.mtime > prev.mtime && (
312
- log_verbose && log('file changed: ' + path),
313
- true
314
- )
315
- )
316
- const file_watch = (path, callback) => (
317
- fs.watchFile(path, (curr, prev) => {
318
- if (file_compare(curr, prev, path)) {
319
- fs.unwatchFile(path);
320
- callback();
321
- }
322
- })
323
- )
341
+ const file_watch_once = (path, callback) => {
342
+ const watcher = fs_watch(path, WATCH_OPTIONS, () => (
343
+ watcher.close(),
344
+ log_verbose && log('file updated: ' + path),
345
+ callback()
346
+ ));
347
+ };
324
348
  const file_keep_new = async (path, callback) => {
325
349
  try {
326
350
  const data = await fsp.readFile(path, 'utf8');
327
351
  if (log_verbose) log('load file: ' + path);
328
352
  await callback(data);
329
- fs.watchFile(path, async (curr, prev) => {
330
- if (file_compare(curr, prev, path)) {
331
- await callback(
332
- await fsp.readFile(path, 'utf8').catch(() => null)
333
- );
334
- }
335
- });
336
353
  }
337
354
  catch (err) {
338
355
  await callback(null);
356
+ return null;
339
357
  }
358
+
359
+ let timeout = 0;
360
+ return fs_watch(path, WATCH_OPTIONS, () => (
361
+ clearTimeout(timeout),
362
+ timeout = setTimeout(() => (
363
+ log_verbose && log('file updated: ' + path),
364
+ fsp.readFile(path, 'utf8')
365
+ .catch(() => null)
366
+ .then(callback)
367
+ ), 50)
368
+ ));
340
369
  }
341
370
 
342
371
  let log_history = rtjscomp.log_history = [];
@@ -510,7 +539,7 @@ const request_handle = async (request, response, https) => {
510
539
  if (file_stat.isDirectory()) throw 403;
511
540
 
512
541
  if (file_dyn_enabled) { // compile file
513
- const file_content = fs.readFileSync(path_real, 'utf8');
542
+ const file_content = await fsp.readFile(path_real, 'utf8');
514
543
  try {
515
544
  if (file_content.includes('\r')) {
516
545
  throw 'illegal line break, must be unix';
@@ -520,7 +549,7 @@ const request_handle = async (request, response, https) => {
520
549
  }
521
550
  const file_content_length = file_content.length;
522
551
 
523
- let code = `async (input,output,request,response,require,custom_import)=>{const log=a=>rtjscomp.log(${
552
+ let code = `const log=a=>rtjscomp.log(${
524
553
  JSON.stringify(path + ': ')
525
554
  }+a);`;
526
555
 
@@ -596,7 +625,15 @@ const request_handle = async (request, response, https) => {
596
625
  }
597
626
 
598
627
  try {
599
- file_function = (0, eval)(code += '}');
628
+ file_function = new AsyncFunction(
629
+ 'input',
630
+ 'output',
631
+ 'request',
632
+ 'response',
633
+ 'require',
634
+ 'custom_import',
635
+ code
636
+ );
600
637
  }
601
638
  catch (err) {
602
639
  throw err.message;
@@ -608,9 +645,9 @@ const request_handle = async (request, response, https) => {
608
645
  }
609
646
 
610
647
  file_cache_functions.set(path, file_function);
611
- file_watch(path_real, () => {
612
- file_cache_functions.delete(path);
613
- });
648
+ file_watch_once(path_real, () => (
649
+ file_cache_functions.delete(path)
650
+ ));
614
651
  }
615
652
  }
616
653