rtjscomp 0.8.8 → 0.9.1
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.
- package/README.md +68 -13
- package/package.json +1 -1
- package/public/index.html +16 -4
- package/rtjscomp.js +403 -191
- package/changes_before_git.txt +0 -58
- package/config/file_type_dyns.txt +0 -7
- package/config/file_type_mimes.txt +0 -21
- package/config/file_type_nocompress.txt +0 -8
- package/config/path_aliases.txt +0 -5
- package/config/port_http.txt +0 -1
- package/config/port_https.txt +0 -0
- package/config/services.txt +0 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ easy to use http server that allows for using javascript just as php was used ba
|
|
|
6
6
|
> as the issues indicate, a lot of breaking changes are ahead.
|
|
7
7
|
> make sure to check for these in future until version 1.0.0 is relessed.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## usage
|
|
10
10
|
|
|
11
11
|
go into the directory where you want to have your project and run
|
|
12
12
|
|
|
@@ -29,23 +29,78 @@ $ npm install
|
|
|
29
29
|
$ npm start
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## rtjscomp.json (optional)
|
|
33
|
+
|
|
34
|
+
it is only needed if you want to change default settings. it has the following properties:
|
|
35
|
+
|
|
36
|
+
- `path_aliases`: object where the key is the url path and the value is the file path
|
|
37
|
+
- `path_ghosts`: array of paths that are simply ignored, no response is sent
|
|
38
|
+
- `path_hiddens`: array of paths that give 404
|
|
39
|
+
- `path_statics`: array of paths in which nothing is transpiled, but the file is sent as is
|
|
40
|
+
- `port_http`: port for http server, default is 8080
|
|
41
|
+
- `port_https`: port for https server
|
|
42
|
+
- `services`: paths to (enabled) service files, prepend an entry with # to disable it
|
|
43
|
+
- `type_dynamics`: dynamic file types, see [api](#api)
|
|
44
|
+
- `type_mimes`: file type to mime type map (most common are already set, only overrides)
|
|
45
|
+
- `type_raws`: array of file types that are sent uncompressed
|
|
46
|
+
|
|
47
|
+
here is an example for a customized setup:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"path_aliases": {
|
|
52
|
+
"": "index.html",
|
|
53
|
+
"blog": "modules/blog/index.html",
|
|
54
|
+
"blog/*id": "modules/blog/article.html"
|
|
55
|
+
},
|
|
56
|
+
"path_ghosts": [ "admin", "wp-admin" ],
|
|
57
|
+
"path_hiddens": [ "secrets.html" ],
|
|
58
|
+
"path_statics": [ "rawtruth.html" ],
|
|
59
|
+
"port_http": 8080,
|
|
60
|
+
"services": [
|
|
61
|
+
"modules/blog/blog",
|
|
62
|
+
"#modules/not/needed"
|
|
63
|
+
],
|
|
64
|
+
"type_dynamics": [ "html", "js" ],
|
|
65
|
+
"type_mimes": {
|
|
66
|
+
"html": "text/html; charset=UTF-8",
|
|
67
|
+
"js": "application/javascript; charset=UTF-8",
|
|
68
|
+
"custom": "application/custom"
|
|
69
|
+
},
|
|
70
|
+
"type_raws": [ "png", "jpg", "pdf" ]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
33
73
|
|
|
34
|
-
|
|
74
|
+
## directories
|
|
35
75
|
|
|
36
|
-
|
|
76
|
+
on first run, they will be created with some defaults.
|
|
37
77
|
|
|
38
|
-
-
|
|
39
|
-
- data dir, services store their data here
|
|
78
|
+
- data dir, services store their data or read custom config files here
|
|
40
79
|
- public dir, containing dynamic and static offerings and also services
|
|
41
80
|
|
|
42
|
-
|
|
81
|
+
## files in public dir
|
|
43
82
|
|
|
44
|
-
- static files like .png in public dir are sent to requests 1:1
|
|
45
|
-
- dynamic files like .html are transpiled
|
|
83
|
+
- static files like .png in public dir are sent to requests 1:1, maybe compressed
|
|
84
|
+
- dynamic files like .html are internally transpiled/compiled and executed -> "rtjscomp"
|
|
46
85
|
- .service.js files are executed and their `this` can be accessed by other files, they are not accessible to outside
|
|
47
86
|
|
|
48
|
-
|
|
87
|
+
example:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
public
|
|
91
|
+
├── index.html
|
|
92
|
+
├── modules
|
|
93
|
+
│ ├── blog
|
|
94
|
+
│ │ ├── article.html
|
|
95
|
+
│ │ ├── blog.service.js
|
|
96
|
+
│ │ └── index.html
|
|
97
|
+
│ └── not
|
|
98
|
+
│ └── needed.service.js
|
|
99
|
+
├── rawtruth.html
|
|
100
|
+
└── secrets.html
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## api
|
|
49
104
|
|
|
50
105
|
in every served dynamic file (like .html), you can insert `<?` and `?>` tags to insert javascript code that is executed server-side. `<?= ... ?>` can be used to insert the result of an expression.
|
|
51
106
|
request-independent services can be created using .service.js files referenced in services.txt.
|
|
@@ -54,14 +109,14 @@ in both file types (dynamic served and services), you can use all node/bun metho
|
|
|
54
109
|
- `service_require(service path)`: returns the matching service object
|
|
55
110
|
- `service_require_try(service path)`: returns the matching service object or null if not found or if disabled
|
|
56
111
|
- `rtjscomp`: has these properties/methods:
|
|
57
|
-
- `actions`: an object with methods for server control (http[s]_[start|stop|
|
|
112
|
+
- `actions`: an object with methods for server control (http[s]_[start|stop|kill], log_clear, halt, exit)
|
|
58
113
|
- `async data_load(path)`: reads the file in data directory and returns its content or null
|
|
59
114
|
- `async data_load_watch(path, callback(content))`: executes callback first and on every change
|
|
60
115
|
- `async data_save(path, content)`: writes the content to the file in data directory
|
|
61
116
|
|
|
62
|
-
##
|
|
117
|
+
## supported environments
|
|
63
118
|
|
|
64
|
-
- node
|
|
119
|
+
- node 8.0.0 or higher
|
|
65
120
|
- bun
|
|
66
121
|
|
|
67
122
|
any os
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<!DOCTYPE html><?
|
|
2
|
+
|
|
3
|
+
const code = Number(input.code || 42);
|
|
4
|
+
// this is not php but javascript!!!!!!!!!!!!!
|
|
5
|
+
// but for better syntax highlighting, set ide language to php.
|
|
6
|
+
// open your local website and look into its source code. this script will be gone.
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
<html>
|
|
10
|
+
<body>
|
|
11
|
+
<h1>Hello, World!</h1>
|
|
12
|
+
<p>Current reason: <?= code ?></p>
|
|
13
|
+
<p><a href="/?code=<?= code + 1 ?>">One more</a></p>
|
|
14
|
+
<p>See <a href="https://github.com/L3P3/rtjscomp">the readme</a>!</p>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
package/rtjscomp.js
CHANGED
|
@@ -7,52 +7,102 @@
|
|
|
7
7
|
|
|
8
8
|
(async () => {
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const url = require('url');
|
|
10
|
+
// node libs
|
|
12
11
|
const fs = require('fs');
|
|
13
12
|
const fsp = require('fs/promises');
|
|
14
|
-
const
|
|
13
|
+
const http = require('http');
|
|
14
|
+
const url = require('url');
|
|
15
15
|
const zlib = require('zlib');
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
// external libs
|
|
18
|
+
const multipart_parse = require('parse-multipart-data').parse;
|
|
17
19
|
const querystring_parse = require('querystring').decode;
|
|
18
|
-
const
|
|
20
|
+
const request_ip_get = require('ipware')().get_ip;
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
const PATH_PUBLIC = 'public/';
|
|
22
|
-
const PATH_CONFIG = 'config/';
|
|
23
|
-
const PATH_DATA = 'data/';
|
|
24
|
-
const GZIP_OPTIONS = {level: 9};
|
|
25
|
-
const WATCH_OPTIONS = {persistent: true, interval: 1000};
|
|
22
|
+
// constants
|
|
26
23
|
const AGENT_CHECK_BOT = /bot|googlebot|crawler|spider|robot|crawling|favicon/i;
|
|
27
24
|
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;
|
|
25
|
+
const GZIP_OPTIONS = {level: 9};
|
|
28
26
|
const HTTP_LIST_REG = /,\s*/;
|
|
29
27
|
const IMPORT_REG = /import\(/g;
|
|
28
|
+
const IS_BUN = typeof Bun !== 'undefined';
|
|
29
|
+
const PATH_CONFIG = 'config/';
|
|
30
|
+
const PATH_DATA = 'data/';
|
|
31
|
+
const PATH_PUBLIC = 'public/';
|
|
32
|
+
const RESOLVE_OPTIONS = {paths: [require('path').resolve()]};
|
|
33
|
+
const VERSION = require('./package.json').version;
|
|
34
|
+
const WATCH_OPTIONS = {persistent: true, interval: 1000};
|
|
30
35
|
|
|
36
|
+
// config
|
|
31
37
|
let log_verbose = process.argv.includes('-v');
|
|
32
38
|
let port_http = 0;
|
|
33
39
|
let port_https = 0;
|
|
34
|
-
const file_type_mimes = new Map;
|
|
35
|
-
const file_type_dyns = new Set;
|
|
36
|
-
const file_type_nocompress = new Set;
|
|
37
|
-
/// forced static files
|
|
38
|
-
const file_raws = new Set;
|
|
39
|
-
/// hidden files
|
|
40
|
-
const file_privates = new Set;
|
|
41
|
-
/// files where requests should be totally ignored
|
|
42
|
-
const file_blocks = new Set;
|
|
43
40
|
/// any path -> file
|
|
44
|
-
const path_aliases = new Map
|
|
45
|
-
|
|
41
|
+
const path_aliases = new Map([
|
|
42
|
+
['', 'index.html'],
|
|
43
|
+
]);
|
|
44
|
+
const path_aliases_reverse = new Map([
|
|
45
|
+
['index.html', '/'],
|
|
46
|
+
]);
|
|
46
47
|
const path_aliases_templates = new Map;
|
|
47
|
-
|
|
48
|
+
/// files where requests should be totally ignored
|
|
49
|
+
const path_ghosts = new Set;
|
|
50
|
+
/// hidden files
|
|
51
|
+
const path_hiddens = new Set;
|
|
52
|
+
/// forced static files
|
|
53
|
+
const path_statics = new Set;
|
|
54
|
+
const type_dynamics = new Set([
|
|
55
|
+
'events',
|
|
56
|
+
'html',
|
|
57
|
+
'json',
|
|
58
|
+
'txt',
|
|
59
|
+
]);
|
|
60
|
+
const type_mimes = new Map([
|
|
61
|
+
['apk', 'application/zip'],
|
|
62
|
+
['bpg', 'image/bpg'],
|
|
63
|
+
['css', 'text/css; charset=utf-8'],
|
|
64
|
+
['events', 'text/event-stream'],
|
|
65
|
+
['flac', 'audio/flac'],
|
|
66
|
+
['gz', 'application/gzip'],
|
|
67
|
+
['hta', 'application/hta'],
|
|
68
|
+
['html', 'text/html; charset=utf-8'],
|
|
69
|
+
['ico', 'image/x-icon'],
|
|
70
|
+
['jpg', 'image/jpeg'],
|
|
71
|
+
['js', 'text/javascript; charset=utf-8'],
|
|
72
|
+
['json', 'application/json; charset=utf-8'],
|
|
73
|
+
['mid', 'audio/midi'],
|
|
74
|
+
['mp3', 'audio/mpeg3'],
|
|
75
|
+
['pdf', 'application/pdf'],
|
|
76
|
+
['png', 'image/png'],
|
|
77
|
+
['rss', 'application/rss+xml; charset=utf-8'],
|
|
78
|
+
['txt', 'text/plain; charset=utf-8'],
|
|
79
|
+
['xml', 'application/xml; charset=utf-8'],
|
|
80
|
+
['xz', 'application/x-xz'],
|
|
81
|
+
['zip', 'application/zip'],
|
|
82
|
+
]);
|
|
83
|
+
const type_raws = new Set([
|
|
84
|
+
'apk',
|
|
85
|
+
'bpg',
|
|
86
|
+
'flac',
|
|
87
|
+
'gz',
|
|
88
|
+
'jpg',
|
|
89
|
+
'mp3',
|
|
90
|
+
'pdf',
|
|
91
|
+
'png',
|
|
92
|
+
'xz',
|
|
93
|
+
'zip',
|
|
94
|
+
]);
|
|
95
|
+
|
|
48
96
|
/// compiled file handlers
|
|
49
97
|
const file_cache_functions = new Map;
|
|
98
|
+
|
|
50
99
|
const actions = {};
|
|
51
100
|
const rtjscomp = global.rtjscomp = {
|
|
52
101
|
actions,
|
|
53
102
|
version: VERSION,
|
|
54
103
|
};
|
|
55
104
|
|
|
105
|
+
// polyfills
|
|
56
106
|
if (!Object.fromEntries) {
|
|
57
107
|
Object.fromEntries = entries => {
|
|
58
108
|
const object = {};
|
|
@@ -63,7 +113,7 @@ if (!Object.fromEntries) {
|
|
|
63
113
|
|
|
64
114
|
// workaround for bun: https://github.com/oven-sh/bun/issues/18919
|
|
65
115
|
let fs_watch = fs.watch;
|
|
66
|
-
if (
|
|
116
|
+
if (IS_BUN) {
|
|
67
117
|
const fs_watch_original = fs_watch;
|
|
68
118
|
const watch_callbacks = new Map;
|
|
69
119
|
fs_watch = (path, options, callback) => {
|
|
@@ -88,7 +138,7 @@ if (typeof Bun !== 'undefined') {
|
|
|
88
138
|
global.globals = rtjscomp;
|
|
89
139
|
global.actions = rtjscomp.actions;
|
|
90
140
|
global.data_load = name => {
|
|
91
|
-
log('[deprecated] synchronous load: ' + PATH_DATA + name);
|
|
141
|
+
log('[deprecated] synchronous load file: ' + PATH_DATA + name);
|
|
92
142
|
try {
|
|
93
143
|
return fs.readFileSync(PATH_DATA + name, 'utf8');
|
|
94
144
|
}
|
|
@@ -97,7 +147,7 @@ global.data_load = name => {
|
|
|
97
147
|
}
|
|
98
148
|
}
|
|
99
149
|
global.data_save = (name, data) => (
|
|
100
|
-
log('[deprecated] synchronous save: ' + PATH_DATA + name),
|
|
150
|
+
log('[deprecated] synchronous save file: ' + PATH_DATA + name),
|
|
101
151
|
fs.writeFileSync(PATH_DATA + name, data, 'utf8')
|
|
102
152
|
)
|
|
103
153
|
global.number_check_int = number => (
|
|
@@ -108,7 +158,7 @@ global.number_check_uint = number => (
|
|
|
108
158
|
)
|
|
109
159
|
|
|
110
160
|
rtjscomp.data_load = async name => {
|
|
111
|
-
if (log_verbose) log('load: ' + PATH_DATA + name);
|
|
161
|
+
if (log_verbose) log('load file: ' + PATH_DATA + name);
|
|
112
162
|
const data = await fsp.readFile(PATH_DATA + name, 'utf8').catch(() => null);
|
|
113
163
|
return name.endsWith('.json') ? JSON.parse(data || null) : data;
|
|
114
164
|
}
|
|
@@ -122,7 +172,7 @@ rtjscomp.data_load_watch = (name, callback) => (
|
|
|
122
172
|
))
|
|
123
173
|
)
|
|
124
174
|
rtjscomp.data_save = (name, data) => (
|
|
125
|
-
log_verbose && log('save: ' + PATH_DATA + name),
|
|
175
|
+
log_verbose && log('save file: ' + PATH_DATA + name),
|
|
126
176
|
fsp.writeFile(
|
|
127
177
|
PATH_DATA + name,
|
|
128
178
|
name.endsWith('.json') ? JSON.stringify(data) : data,
|
|
@@ -137,8 +187,8 @@ const custom_require = path => {
|
|
|
137
187
|
let result = custom_require_cache.get(path);
|
|
138
188
|
if (result != null) return result;
|
|
139
189
|
|
|
140
|
-
log_verbose && log('require: ' + path);
|
|
141
|
-
const path_real = require.resolve(path,
|
|
190
|
+
log_verbose && log('require module: ' + path);
|
|
191
|
+
const path_real = require.resolve(path, RESOLVE_OPTIONS);
|
|
142
192
|
custom_require_paths.add(path_real);
|
|
143
193
|
custom_require_cache.set(
|
|
144
194
|
path,
|
|
@@ -150,11 +200,11 @@ const custom_import = async path => {
|
|
|
150
200
|
let result = custom_import_cache.get(path);
|
|
151
201
|
if (result != null) return result;
|
|
152
202
|
|
|
153
|
-
log_verbose && log('import: ' + path);
|
|
203
|
+
log_verbose && log('import module: ' + path);
|
|
154
204
|
custom_import_cache.set(
|
|
155
205
|
path,
|
|
156
206
|
result = await import(
|
|
157
|
-
'file://' + require.resolve(path,
|
|
207
|
+
'file://' + require.resolve(path, RESOLVE_OPTIONS)
|
|
158
208
|
)
|
|
159
209
|
);
|
|
160
210
|
return result;
|
|
@@ -170,14 +220,17 @@ const AsyncFunction = custom_import.constructor;
|
|
|
170
220
|
|
|
171
221
|
const services_active = new Map;
|
|
172
222
|
const services_loading = new Set;
|
|
173
|
-
const services_list_react = async
|
|
223
|
+
const services_list_react = async list => {
|
|
174
224
|
await Promise.all(
|
|
175
225
|
Array.from(services_active.entries())
|
|
176
|
-
.filter(([path, _]) => !
|
|
226
|
+
.filter(([path, _]) => !list.includes(path))
|
|
177
227
|
.map(([_, service_object]) => service_stop(service_object, true))
|
|
178
228
|
);
|
|
179
|
-
for (const path of
|
|
180
|
-
if (
|
|
229
|
+
for (const path of list)
|
|
230
|
+
if (
|
|
231
|
+
path.charCodeAt(0) !== 35 &&
|
|
232
|
+
!services_active.has(path)
|
|
233
|
+
) {
|
|
181
234
|
await service_start(path);
|
|
182
235
|
}
|
|
183
236
|
}
|
|
@@ -272,7 +325,6 @@ const service_start_inner = async (path, service_object, file_content) => {
|
|
|
272
325
|
if (log_verbose) log('started service: ' + path);
|
|
273
326
|
}
|
|
274
327
|
const services_shutdown = () => (
|
|
275
|
-
log_verbose && log('shutdown services...'),
|
|
276
328
|
Promise.all(
|
|
277
329
|
Array.from(services_active.values())
|
|
278
330
|
.map(service_object => service_stop(service_object, true))
|
|
@@ -317,28 +369,6 @@ global.service_require_try = path => {
|
|
|
317
369
|
);
|
|
318
370
|
}
|
|
319
371
|
|
|
320
|
-
const map_generate_bol = (set, data) => {
|
|
321
|
-
set.clear();
|
|
322
|
-
for (const key of data.split('\n'))
|
|
323
|
-
if (
|
|
324
|
-
key.length > 0 &&
|
|
325
|
-
key.charCodeAt(0) !== 35
|
|
326
|
-
) {
|
|
327
|
-
set.add(key);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
const map_generate_equ = (map, data) => {
|
|
331
|
-
map.clear();
|
|
332
|
-
for (const entry of data.split('\n'))
|
|
333
|
-
if (
|
|
334
|
-
entry.length > 0 &&
|
|
335
|
-
entry.charCodeAt(0) !== 35
|
|
336
|
-
) {
|
|
337
|
-
const equ = entry.split(':');
|
|
338
|
-
map.set(equ[0], equ[1] || '');
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
372
|
const file_watch_once = (path, callback) => {
|
|
343
373
|
const watcher = fs_watch(path, WATCH_OPTIONS, () => (
|
|
344
374
|
watcher.close(),
|
|
@@ -369,6 +399,75 @@ const file_keep_new = async (path, callback) => {
|
|
|
369
399
|
));
|
|
370
400
|
}
|
|
371
401
|
|
|
402
|
+
const get_prop_uint = (obj, prop, fallback) => {
|
|
403
|
+
if (
|
|
404
|
+
obj === null ||
|
|
405
|
+
!(prop in obj)
|
|
406
|
+
) return fallback;
|
|
407
|
+
const value = obj[prop];
|
|
408
|
+
if (
|
|
409
|
+
typeof value !== 'number' ||
|
|
410
|
+
value < 0 ||
|
|
411
|
+
value % 1 > 0
|
|
412
|
+
) {
|
|
413
|
+
throw prop + ' must be positive integer';
|
|
414
|
+
}
|
|
415
|
+
delete obj[prop];
|
|
416
|
+
return value;
|
|
417
|
+
}
|
|
418
|
+
const get_prop_list = (obj, prop) => {
|
|
419
|
+
if (
|
|
420
|
+
obj === null ||
|
|
421
|
+
!(prop in obj)
|
|
422
|
+
) return null;
|
|
423
|
+
const value = obj[prop];
|
|
424
|
+
if (
|
|
425
|
+
typeof value !== 'object' ||
|
|
426
|
+
value.length == null ||
|
|
427
|
+
value.some(item => typeof item !== 'string')
|
|
428
|
+
) {
|
|
429
|
+
throw prop + ' must be array of strings';
|
|
430
|
+
}
|
|
431
|
+
delete obj[prop];
|
|
432
|
+
return value;
|
|
433
|
+
}
|
|
434
|
+
const get_prop_map = (obj, prop) => {
|
|
435
|
+
if (
|
|
436
|
+
obj === null ||
|
|
437
|
+
!(prop in obj)
|
|
438
|
+
) return null;
|
|
439
|
+
let value = obj[prop];
|
|
440
|
+
if (
|
|
441
|
+
typeof value !== 'object' ||
|
|
442
|
+
(
|
|
443
|
+
value = Object.entries(value)
|
|
444
|
+
).some(([_, item]) => typeof item !== 'string')
|
|
445
|
+
) {
|
|
446
|
+
throw prop + ' must be object of strings';
|
|
447
|
+
}
|
|
448
|
+
delete obj[prop];
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
const parse_old_list = data => (
|
|
452
|
+
data
|
|
453
|
+
.split('\n')
|
|
454
|
+
.filter(entry =>
|
|
455
|
+
entry.length > 0 &&
|
|
456
|
+
entry.charCodeAt(0) !== 35
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
const parse_old_map = data => (
|
|
460
|
+
Object.fromEntries(
|
|
461
|
+
data
|
|
462
|
+
.split('\n')
|
|
463
|
+
.filter(entry =>
|
|
464
|
+
entry.length > 0 &&
|
|
465
|
+
entry.charCodeAt(0) !== 35
|
|
466
|
+
)
|
|
467
|
+
.map(entry => entry.split(':'))
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
|
|
372
471
|
let log_history = rtjscomp.log_history = [];
|
|
373
472
|
actions.log_clear = () => {
|
|
374
473
|
log_history = rtjscomp.log_history = [];
|
|
@@ -429,8 +528,12 @@ const request_handle = async (request, response, https) => {
|
|
|
429
528
|
path.includes('//')
|
|
430
529
|
) throw 404;
|
|
431
530
|
if (path.length > 1 && path.endsWith('/')) {
|
|
432
|
-
|
|
433
|
-
|
|
531
|
+
path = path.slice(0, -1);
|
|
532
|
+
// is file with extension?
|
|
533
|
+
if (path.lastIndexOf('/') < path.lastIndexOf('.')) {
|
|
534
|
+
response.setHeader('Location', path);
|
|
535
|
+
throw 301;
|
|
536
|
+
}
|
|
434
537
|
}
|
|
435
538
|
path = path.slice(1);
|
|
436
539
|
|
|
@@ -438,7 +541,7 @@ const request_handle = async (request, response, https) => {
|
|
|
438
541
|
if (
|
|
439
542
|
path.includes('php') ||
|
|
440
543
|
path.includes('sql') ||
|
|
441
|
-
|
|
544
|
+
path_ghosts.has(path)
|
|
442
545
|
) return;
|
|
443
546
|
|
|
444
547
|
response.setHeader('Server', 'l3p3 rtjscomp v' + VERSION);
|
|
@@ -496,13 +599,13 @@ const request_handle = async (request, response, https) => {
|
|
|
496
599
|
|
|
497
600
|
let file_gz_enabled = (
|
|
498
601
|
'accept-encoding' in request_headers &&
|
|
499
|
-
!
|
|
602
|
+
!type_raws.has(file_type) &&
|
|
500
603
|
request_headers['accept-encoding'].split(HTTP_LIST_REG).includes('gzip')
|
|
501
604
|
);
|
|
502
605
|
|
|
503
606
|
const file_dyn_enabled = (
|
|
504
|
-
|
|
505
|
-
!
|
|
607
|
+
type_dynamics.has(file_type) &&
|
|
608
|
+
!path_statics.has(path)
|
|
506
609
|
);
|
|
507
610
|
|
|
508
611
|
if (request_method !== 'GET') {
|
|
@@ -539,7 +642,7 @@ const request_handle = async (request, response, https) => {
|
|
|
539
642
|
}ic file: ${path_real}`);
|
|
540
643
|
|
|
541
644
|
if (
|
|
542
|
-
|
|
645
|
+
path_hiddens.has(path) ||
|
|
543
646
|
path.endsWith('.service.js')
|
|
544
647
|
) throw 403;
|
|
545
648
|
if (!fs.existsSync(path_real)) throw 404;
|
|
@@ -662,7 +765,7 @@ const request_handle = async (request, response, https) => {
|
|
|
662
765
|
response.statusCode = 200;
|
|
663
766
|
response.setHeader(
|
|
664
767
|
'Content-Type',
|
|
665
|
-
|
|
768
|
+
type_mimes.get(file_type) || type_mimes.get('txt')
|
|
666
769
|
);
|
|
667
770
|
|
|
668
771
|
if (file_dyn_enabled) { // dynamic file
|
|
@@ -848,7 +951,10 @@ const request_handle = async (request, response, https) => {
|
|
|
848
951
|
err = 500;
|
|
849
952
|
}
|
|
850
953
|
|
|
851
|
-
if (
|
|
954
|
+
if (
|
|
955
|
+
err >= 500 ||
|
|
956
|
+
log_verbose && err >= 400
|
|
957
|
+
) {
|
|
852
958
|
log(`[error] request failed: ${err}; ${request_ip}; ${request.url}`);
|
|
853
959
|
}
|
|
854
960
|
|
|
@@ -862,20 +968,21 @@ const request_handle = async (request, response, https) => {
|
|
|
862
968
|
|
|
863
969
|
let exiting = false;
|
|
864
970
|
actions.halt = async () => {
|
|
971
|
+
if (log_verbose) log('stop all');
|
|
865
972
|
await Promise.all([
|
|
866
973
|
actions.http_stop && actions.http_stop(),
|
|
867
974
|
actions.https_stop && actions.https_stop(),
|
|
868
975
|
services_shutdown(),
|
|
869
976
|
]);
|
|
870
977
|
await actions.spam_save();
|
|
871
|
-
log('stopped
|
|
978
|
+
log('stopped all');
|
|
872
979
|
}
|
|
873
980
|
actions.exit = async status => {
|
|
874
981
|
if (exiting) return;
|
|
875
982
|
exiting = true;
|
|
876
983
|
if (typeof status !== 'number') status = 0;
|
|
877
984
|
await actions.halt();
|
|
878
|
-
log('
|
|
985
|
+
if (log_verbose) log('exit');
|
|
879
986
|
process.exit(status);
|
|
880
987
|
}
|
|
881
988
|
|
|
@@ -898,25 +1005,43 @@ process.on('SIGINT', actions.exit);
|
|
|
898
1005
|
process.on('SIGUSR2', actions.exit);
|
|
899
1006
|
process.on('SIGTERM', actions.exit);
|
|
900
1007
|
|
|
901
|
-
log(`rtjscomp v${
|
|
1008
|
+
log(`rtjscomp v${
|
|
1009
|
+
VERSION
|
|
1010
|
+
} in ${
|
|
1011
|
+
IS_BUN ? 'bun' : 'node'
|
|
1012
|
+
} on ${
|
|
1013
|
+
process.platform
|
|
1014
|
+
}`);
|
|
1015
|
+
|
|
1016
|
+
await file_keep_new(PATH_CONFIG + 'init.js', async data => {
|
|
1017
|
+
if (!data) return;
|
|
1018
|
+
log('[deprecated] run global init script');
|
|
1019
|
+
try {
|
|
1020
|
+
await (
|
|
1021
|
+
new AsyncFunction('require', data)
|
|
1022
|
+
)(custom_require);
|
|
1023
|
+
}
|
|
1024
|
+
catch (err) {
|
|
1025
|
+
log('[error] init.js: ' + err.message);
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
902
1028
|
|
|
903
1029
|
// initial
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
1030
|
+
{
|
|
1031
|
+
const [
|
|
1032
|
+
stat_data,
|
|
1033
|
+
stat_public,
|
|
1034
|
+
...files_config
|
|
1035
|
+
] = await Promise.all([
|
|
1036
|
+
fsp.stat(PATH_DATA).catch(_ => null),
|
|
1037
|
+
fsp.stat(PATH_PUBLIC).catch(_ => null),
|
|
1038
|
+
...(
|
|
1039
|
+
'file_blocks,file_privates,file_raws,file_type_dyns,file_type_mimes,file_type_nocompress,path_aliases,port_http,port_https,services'
|
|
1040
|
+
.split(',')
|
|
1041
|
+
.map(name => fsp.readFile(PATH_CONFIG + name + '.txt', 'utf8').catch(_ => null))
|
|
1042
|
+
),
|
|
1043
|
+
]);
|
|
1044
|
+
|
|
920
1045
|
if (!stat_data) {
|
|
921
1046
|
fs.mkdirSync(PATH_DATA);
|
|
922
1047
|
}
|
|
@@ -927,79 +1052,74 @@ await Promise.all([
|
|
|
927
1052
|
{recursive: true}
|
|
928
1053
|
);
|
|
929
1054
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
)
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1055
|
+
if (
|
|
1056
|
+
files_config.some(file => file !== null)
|
|
1057
|
+
) {
|
|
1058
|
+
const json = JSON.parse(
|
|
1059
|
+
await fsp.readFile('rtjscomp.json', 'utf8').catch(_ => null)
|
|
1060
|
+
) || {};
|
|
1061
|
+
|
|
1062
|
+
const [
|
|
1063
|
+
old_file_blocks,
|
|
1064
|
+
old_file_privates,
|
|
1065
|
+
old_file_raws,
|
|
1066
|
+
old_file_type_dyns,
|
|
1067
|
+
old_file_type_mimes,
|
|
1068
|
+
old_file_type_nocompress,
|
|
1069
|
+
old_path_aliases,
|
|
1070
|
+
old_port_http,
|
|
1071
|
+
old_port_https,
|
|
1072
|
+
old_services,
|
|
1073
|
+
] = files_config;
|
|
1074
|
+
|
|
1075
|
+
if (old_file_blocks) {
|
|
1076
|
+
json['path_ghosts'] = parse_old_list(old_file_blocks);
|
|
945
1077
|
}
|
|
946
|
-
|
|
947
|
-
|
|
1078
|
+
if (old_file_privates) {
|
|
1079
|
+
json['path_hiddens'] = parse_old_list(old_file_privates);
|
|
948
1080
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
map_generate_equ(file_type_mimes, data);
|
|
952
|
-
if (!file_type_mimes.has('txt')) {
|
|
953
|
-
file_type_mimes.set('txt', 'text/plain; charset=utf-8');
|
|
1081
|
+
if (old_file_raws) {
|
|
1082
|
+
json['path_statics'] = parse_old_list(old_file_raws);
|
|
954
1083
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
path_aliases_templates.set(first, [
|
|
972
|
-
{path_split, value},
|
|
973
|
-
]);
|
|
974
|
-
}
|
|
1084
|
+
if (old_file_type_dyns) {
|
|
1085
|
+
json['type_dynamics'] = parse_old_list(old_file_type_dyns);
|
|
1086
|
+
}
|
|
1087
|
+
if (old_file_type_mimes) {
|
|
1088
|
+
json['type_mimes'] = parse_old_map(old_file_type_mimes);
|
|
1089
|
+
}
|
|
1090
|
+
if (old_file_type_nocompress) {
|
|
1091
|
+
json['type_raws'] = parse_old_list(old_file_type_nocompress);
|
|
1092
|
+
}
|
|
1093
|
+
if (old_path_aliases) {
|
|
1094
|
+
json['path_aliases'] = parse_old_map(old_path_aliases);
|
|
1095
|
+
}
|
|
1096
|
+
if (old_port_http) {
|
|
1097
|
+
const number = parseInt(old_port_http);
|
|
1098
|
+
if (!isNaN(number)) {
|
|
1099
|
+
json['port_http'] = number;
|
|
975
1100
|
}
|
|
976
|
-
|
|
977
|
-
|
|
1101
|
+
}
|
|
1102
|
+
if (old_port_https) {
|
|
1103
|
+
const number = parseInt(old_port_https);
|
|
1104
|
+
if (!isNaN(number)) {
|
|
1105
|
+
json['port_https'] = number;
|
|
978
1106
|
}
|
|
979
1107
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
if (!data) return;
|
|
993
|
-
map_generate_bol(file_privates, data);
|
|
994
|
-
}),
|
|
995
|
-
file_keep_new(PATH_CONFIG + 'file_blocks.txt', data => {
|
|
996
|
-
if (!data) return;
|
|
997
|
-
map_generate_bol(file_blocks, data);
|
|
998
|
-
}),
|
|
999
|
-
]);
|
|
1108
|
+
if (old_services) {
|
|
1109
|
+
json['services'] = old_services.split('\n').filter(path => path.length > 0);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
await fsp.writeFile(
|
|
1113
|
+
'rtjscomp.json',
|
|
1114
|
+
JSON.stringify(json, null, '\t') + '\n',
|
|
1115
|
+
'utf8'
|
|
1116
|
+
);
|
|
1117
|
+
log('[deprecated] config files found, rtjscomp.json written, please delete config files');
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1000
1120
|
|
|
1121
|
+
// http(s)
|
|
1001
1122
|
let connections_count = 0;
|
|
1002
|
-
let http_status = false;
|
|
1003
1123
|
let http_status_target = false;
|
|
1004
1124
|
let http_listened_resolve = null;
|
|
1005
1125
|
const http_connections = new Map;
|
|
@@ -1020,14 +1140,12 @@ server_http.on('connection', connection => {
|
|
|
1020
1140
|
|
|
1021
1141
|
actions.http_start = async () => {
|
|
1022
1142
|
await actions.http_stop();
|
|
1143
|
+
if (!port_http) return;
|
|
1023
1144
|
http_status_target = true;
|
|
1024
1145
|
log('start http: http://localhost:' + port_http);
|
|
1025
1146
|
await new Promise(resolve => server_http.listen(port_http, http_listened_resolve = resolve));
|
|
1026
1147
|
if (http_listened_resolve) http_listened_resolve = null;
|
|
1027
|
-
else
|
|
1028
|
-
http_status = true;
|
|
1029
|
-
if (log_verbose) log('started http');
|
|
1030
|
-
}
|
|
1148
|
+
else if (log_verbose) log('started http');
|
|
1031
1149
|
}
|
|
1032
1150
|
actions.http_stop = async () => {
|
|
1033
1151
|
if (!http_status_target) return;
|
|
@@ -1036,7 +1154,6 @@ actions.http_stop = async () => {
|
|
|
1036
1154
|
const kill_timeout = setTimeout(actions.http_kill, 5e3);
|
|
1037
1155
|
await new Promise(resolve => server_http.close(resolve));
|
|
1038
1156
|
clearTimeout(kill_timeout);
|
|
1039
|
-
http_status = false;
|
|
1040
1157
|
if (log_verbose) log('stopped http');
|
|
1041
1158
|
}
|
|
1042
1159
|
actions.http_kill = async () => {
|
|
@@ -1050,24 +1167,9 @@ actions.http_kill = async () => {
|
|
|
1050
1167
|
http_connections.clear();
|
|
1051
1168
|
}
|
|
1052
1169
|
|
|
1053
|
-
file_keep_new(PATH_CONFIG + 'port_http.txt', data => {
|
|
1054
|
-
if (
|
|
1055
|
-
!data ||
|
|
1056
|
-
isNaN(data = Number(data)) ||
|
|
1057
|
-
!number_check_uint(data)
|
|
1058
|
-
) {
|
|
1059
|
-
log('[error] http: invalid port number');
|
|
1060
|
-
}
|
|
1061
|
-
else if (data !== port_http) {
|
|
1062
|
-
port_http = data;
|
|
1063
|
-
actions.http_start();
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
1170
|
try {
|
|
1068
1171
|
const https_key = fs.readFileSync(PATH_CONFIG + 'ssl/domain.key');
|
|
1069
1172
|
const https_cert = fs.readFileSync(PATH_CONFIG + 'ssl/chained.pem');
|
|
1070
|
-
let https_status = false;
|
|
1071
1173
|
let https_status_target = false;
|
|
1072
1174
|
let https_listened_resolve = null;
|
|
1073
1175
|
const https_connections = new Map;
|
|
@@ -1089,14 +1191,12 @@ try {
|
|
|
1089
1191
|
|
|
1090
1192
|
actions.https_start = async () => {
|
|
1091
1193
|
await actions.https_stop();
|
|
1194
|
+
if (!port_https) return;
|
|
1092
1195
|
https_status_target = true;
|
|
1093
1196
|
log('start https: https://localhost:' + port_https);
|
|
1094
1197
|
await new Promise(resolve => server_https.listen(port_https, https_listened_resolve = resolve));
|
|
1095
1198
|
if (https_listened_resolve) https_listened_resolve = null;
|
|
1096
|
-
else
|
|
1097
|
-
https_status = true;
|
|
1098
|
-
if (log_verbose) log('started https');
|
|
1099
|
-
}
|
|
1199
|
+
else if (log_verbose) log('started https');
|
|
1100
1200
|
}
|
|
1101
1201
|
actions.https_stop = async () => {
|
|
1102
1202
|
if (!https_status_target) return;
|
|
@@ -1105,7 +1205,6 @@ try {
|
|
|
1105
1205
|
const kill_timeout = setTimeout(actions.https_kill, 5000);
|
|
1106
1206
|
await new Promise(resolve => server_https.close(resolve));
|
|
1107
1207
|
clearTimeout(kill_timeout);
|
|
1108
|
-
https_status = false;
|
|
1109
1208
|
if (log_verbose) log('stopped https');
|
|
1110
1209
|
}
|
|
1111
1210
|
actions.https_kill = async () => {
|
|
@@ -1117,23 +1216,136 @@ try {
|
|
|
1117
1216
|
if (log_verbose) log('killed https');
|
|
1118
1217
|
https_connections.clear();
|
|
1119
1218
|
}
|
|
1120
|
-
|
|
1121
|
-
file_keep_new(PATH_CONFIG + 'port_https.txt', data => {
|
|
1122
|
-
if (
|
|
1123
|
-
!data ||
|
|
1124
|
-
isNaN(data = Number(data)) ||
|
|
1125
|
-
!number_check_uint(data)
|
|
1126
|
-
) {
|
|
1127
|
-
log('[error] https: invalid port number');
|
|
1128
|
-
}
|
|
1129
|
-
else if (data !== port_https) {
|
|
1130
|
-
port_https = data;
|
|
1131
|
-
actions.https_start();
|
|
1132
|
-
}
|
|
1133
|
-
});
|
|
1134
1219
|
}
|
|
1135
1220
|
catch (err) {
|
|
1136
1221
|
if (log_verbose) log('https: no cert, disabled');
|
|
1137
1222
|
}
|
|
1138
1223
|
|
|
1224
|
+
// config
|
|
1225
|
+
await file_keep_new('rtjscomp.json', data => {
|
|
1226
|
+
try {
|
|
1227
|
+
data = JSON.parse(data);
|
|
1228
|
+
if (typeof data !== 'object') {
|
|
1229
|
+
throw 'must contain {}';
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
const path_aliases_new = get_prop_map(data, 'path_aliases');
|
|
1233
|
+
const path_ghosts_new = get_prop_list(data, 'path_ghosts');
|
|
1234
|
+
const path_hiddens_new = get_prop_list(data, 'path_hiddens');
|
|
1235
|
+
const path_statics_new = get_prop_list(data, 'path_statics');
|
|
1236
|
+
const port_http_new = get_prop_uint(data, 'port_http', 8080);
|
|
1237
|
+
const port_https_new = get_prop_uint(data, 'port_https', 0);
|
|
1238
|
+
const services_new = get_prop_list(data, 'services') || [];
|
|
1239
|
+
const type_dynamics_new = get_prop_list(data, 'type_dynamics');
|
|
1240
|
+
const type_mimes_new = get_prop_map(data, 'type_mimes');
|
|
1241
|
+
const type_raws_new = get_prop_list(data, 'type_raws');
|
|
1242
|
+
|
|
1243
|
+
if (data) {
|
|
1244
|
+
const keys_left = Object.keys(data);
|
|
1245
|
+
if (keys_left.length > 0) {
|
|
1246
|
+
throw 'unknown: ' + keys_left.join(', ');
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (path_ghosts_new) {
|
|
1251
|
+
path_ghosts.clear();
|
|
1252
|
+
for (const key of path_ghosts_new) {
|
|
1253
|
+
path_ghosts.add(key);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (path_hiddens_new) {
|
|
1257
|
+
path_hiddens.clear();
|
|
1258
|
+
for (const key of path_hiddens_new) {
|
|
1259
|
+
path_hiddens.add(key);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
if (path_statics_new) {
|
|
1263
|
+
path_statics.clear();
|
|
1264
|
+
for (const key of path_statics_new) {
|
|
1265
|
+
path_statics.add(key);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
if (path_aliases_new) {
|
|
1269
|
+
path_aliases.clear();
|
|
1270
|
+
path_aliases_reverse.clear();
|
|
1271
|
+
path_aliases_templates.clear();
|
|
1272
|
+
for (const [key, value] of path_aliases_new) {
|
|
1273
|
+
if (key.includes('*')) {
|
|
1274
|
+
const path_split = key.split('/');
|
|
1275
|
+
const first = path_split.shift();
|
|
1276
|
+
if (path_aliases_templates.has(first)) {
|
|
1277
|
+
path_aliases_templates.get(first).push(
|
|
1278
|
+
{path_split, value}
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
else {
|
|
1282
|
+
path_aliases_templates.set(first, [
|
|
1283
|
+
{path_split, value},
|
|
1284
|
+
]);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
else {
|
|
1288
|
+
path_aliases.set(key, value);
|
|
1289
|
+
const existing = path_aliases_reverse.get(value);
|
|
1290
|
+
if (
|
|
1291
|
+
existing == null ||
|
|
1292
|
+
existing.length - 1 > value.length
|
|
1293
|
+
) {
|
|
1294
|
+
path_aliases_reverse.set(value, '/' + key);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (type_dynamics_new) {
|
|
1300
|
+
type_dynamics.clear();
|
|
1301
|
+
for (const key of type_dynamics_new) {
|
|
1302
|
+
type_dynamics.add(key);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (type_mimes_new) {
|
|
1306
|
+
for (const [key, value] of type_mimes_new) {
|
|
1307
|
+
type_mimes.set(key, value);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
if (type_raws_new) {
|
|
1311
|
+
type_raws.clear();
|
|
1312
|
+
for (const key of type_raws_new) {
|
|
1313
|
+
type_raws.add(key);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
const promises = [
|
|
1318
|
+
services_list_react(services_new),
|
|
1319
|
+
];
|
|
1320
|
+
|
|
1321
|
+
if (port_http_new !== port_http) {
|
|
1322
|
+
port_http = port_http_new;
|
|
1323
|
+
promises.push(
|
|
1324
|
+
port_http_new > 0
|
|
1325
|
+
? actions.http_start()
|
|
1326
|
+
: actions.http_stop()
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
if (
|
|
1331
|
+
actions.https_stop != null &&
|
|
1332
|
+
port_https_new !== port_https
|
|
1333
|
+
) {
|
|
1334
|
+
port_https = port_https_new;
|
|
1335
|
+
promises.push(
|
|
1336
|
+
port_https_new > 0
|
|
1337
|
+
? actions.https_start()
|
|
1338
|
+
: actions.https_stop()
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
return Promise.all(promises);
|
|
1343
|
+
}
|
|
1344
|
+
catch (err) {
|
|
1345
|
+
log('[error] rtjscomp.json: ' + (err.message || err));
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
if (log_verbose) log('started all');
|
|
1350
|
+
|
|
1139
1351
|
})();
|
package/changes_before_git.txt
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
add compression of dynamic data
|
|
2
|
-
add https
|
|
3
|
-
add actions
|
|
4
|
-
0.5
|
|
5
|
-
add shutdown action
|
|
6
|
-
prefer gzip over lzma
|
|
7
|
-
move public files into separate dir
|
|
8
|
-
0.51
|
|
9
|
-
add list of raw files
|
|
10
|
-
0.52
|
|
11
|
-
ignore empty areas (<??> or ?><?)
|
|
12
|
-
0.53
|
|
13
|
-
move configuration data to separate files
|
|
14
|
-
0.54
|
|
15
|
-
add path aliases
|
|
16
|
-
block accessing directories
|
|
17
|
-
0.55
|
|
18
|
-
add http-header Content-Location
|
|
19
|
-
0.56
|
|
20
|
-
add list of file types not to compress
|
|
21
|
-
keep raw files in ram
|
|
22
|
-
remove lzma
|
|
23
|
-
add compression of raw files
|
|
24
|
-
load already compressed files
|
|
25
|
-
just compress when at least 100 bytes of data
|
|
26
|
-
0.57
|
|
27
|
-
cleanup code
|
|
28
|
-
execute and send file in parallel
|
|
29
|
-
add services
|
|
30
|
-
0.58
|
|
31
|
-
add analytic logger
|
|
32
|
-
use compressed file even if file type is not intended as being compressed
|
|
33
|
-
0.59
|
|
34
|
-
remove static files from cache when precompressed files got changed
|
|
35
|
-
0.591
|
|
36
|
-
set gzip level to 9
|
|
37
|
-
save automatically compressed files
|
|
38
|
-
0.592
|
|
39
|
-
block requests with invalid hostname
|
|
40
|
-
0.593
|
|
41
|
-
add user data storage
|
|
42
|
-
0.594
|
|
43
|
-
remove custom file init
|
|
44
|
-
asynchronize request handling
|
|
45
|
-
temporarily disable chaching of static files
|
|
46
|
-
0.595
|
|
47
|
-
send partial files
|
|
48
|
-
load and interpret file in parallel
|
|
49
|
-
optimize source codes of sent files
|
|
50
|
-
0.596
|
|
51
|
-
stop services before replacing them
|
|
52
|
-
service_require return service object
|
|
53
|
-
0.597
|
|
54
|
-
stop services on exit
|
|
55
|
-
0.598
|
|
56
|
-
read request body
|
|
57
|
-
0.599
|
|
58
|
-
???
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
html:text/html; charset=utf-8
|
|
2
|
-
txt:text/plain; charset=utf-8
|
|
3
|
-
xml:application/xml; charset=utf-8
|
|
4
|
-
rss:application/rss+xml; charset=utf-8
|
|
5
|
-
js:text/javascript; charset=utf-8
|
|
6
|
-
json:application/json; charset=utf-8
|
|
7
|
-
hta:application/hta
|
|
8
|
-
css:text/css; charset=utf-8
|
|
9
|
-
ico:image/x-icon
|
|
10
|
-
jpg:image/jpeg
|
|
11
|
-
png:image/png
|
|
12
|
-
bpg:image/bpg
|
|
13
|
-
zip:application/zip
|
|
14
|
-
apk:application/zip
|
|
15
|
-
gz:application/gzip
|
|
16
|
-
xz:application/x-xz
|
|
17
|
-
mp3:audio/mpeg3
|
|
18
|
-
mid:audio/midi
|
|
19
|
-
flac:audio/flac
|
|
20
|
-
pdf:application/pdf
|
|
21
|
-
events:text/event-stream
|
package/config/path_aliases.txt
DELETED
package/config/port_http.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
8080
|
package/config/port_https.txt
DELETED
|
File without changes
|
package/config/services.txt
DELETED