@maiyunnet/kebab 2.0.7 → 2.0.9
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/index.d.ts +11 -1
- package/index.js +13 -1
- package/lib/buffer.d.ts +25 -0
- package/lib/buffer.js +30 -5
- package/lib/captcha.d.ts +15 -0
- package/lib/captcha.js +20 -0
- package/lib/consistent.d.ts +51 -0
- package/lib/consistent.js +59 -0
- package/lib/core.d.ts +134 -0
- package/lib/core.js +176 -0
- package/lib/crypto.d.ts +75 -6
- package/lib/crypto.js +206 -38
- package/lib/db.d.ts +104 -0
- package/lib/db.js +126 -0
- package/lib/dns.d.ts +51 -0
- package/lib/dns.js +54 -2
- package/lib/fs.d.ts +100 -0
- package/lib/fs.js +118 -0
- package/lib/jwt.d.ts +43 -0
- package/lib/jwt.js +45 -0
- package/lib/kv.d.ts +362 -0
- package/lib/kv.js +377 -0
- package/lib/lan.d.ts +6 -0
- package/lib/lan.js +7 -0
- package/lib/net/formdata.d.ts +38 -0
- package/lib/net/formdata.js +43 -0
- package/lib/net/request.d.ts +62 -0
- package/lib/net/request.js +57 -0
- package/lib/net/response.d.ts +21 -0
- package/lib/net/response.js +16 -0
- package/lib/net.d.ts +86 -0
- package/lib/net.js +140 -0
- package/lib/s3.d.ts +52 -0
- package/lib/s3.js +51 -0
- package/lib/scan.d.ts +52 -0
- package/lib/scan.js +84 -0
- package/lib/session.d.ts +31 -0
- package/lib/session.js +52 -1
- package/lib/sql.d.ts +176 -0
- package/lib/sql.js +287 -2
- package/lib/ssh/sftp.d.ts +106 -0
- package/lib/ssh/sftp.js +106 -0
- package/lib/ssh/shell.d.ts +37 -0
- package/lib/ssh/shell.js +31 -0
- package/lib/ssh.d.ts +32 -0
- package/lib/ssh.js +32 -0
- package/lib/text.d.ts +131 -0
- package/lib/text.js +188 -0
- package/lib/time.d.ts +53 -0
- package/lib/time.js +55 -0
- package/lib/ws.d.ts +68 -0
- package/lib/ws.js +74 -0
- package/lib/zip.d.ts +53 -0
- package/lib/zip.js +73 -0
- package/lib/zlib.d.ts +76 -0
- package/lib/zlib.js +78 -0
- package/main.d.ts +5 -0
- package/main.js +12 -0
- package/package.json +3 -2
- package/sys/child.js +104 -0
- package/sys/cmd.js +28 -0
- package/sys/ctr.d.ts +166 -0
- package/sys/ctr.js +177 -0
- package/sys/master.js +63 -0
- package/sys/mod.d.ts +266 -0
- package/sys/mod.js +335 -0
- package/sys/route.d.ts +34 -0
- package/sys/route.js +164 -0
- package/www/example/ctr/test.d.ts +3 -0
- package/www/example/ctr/test.js +63 -1
- package/www/example/mod/test.js +14 -0
- package/www/example/mod/testdata.js +9 -0
- package/www/example/ws/test.js +1 -0
- package/.VSCodeCounter/2025-02-14_14-46-44/details.md +0 -82
- package/.VSCodeCounter/2025-02-14_14-46-44/diff-details.md +0 -15
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.csv +0 -2
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.md +0 -19
- package/.VSCodeCounter/2025-02-14_14-46-44/diff.txt +0 -22
- package/.VSCodeCounter/2025-02-14_14-46-44/results.csv +0 -69
- package/.VSCodeCounter/2025-02-14_14-46-44/results.json +0 -1
- package/.VSCodeCounter/2025-02-14_14-46-44/results.md +0 -48
- package/.VSCodeCounter/2025-02-14_14-46-44/results.txt +0 -118
- package/.vscode/tasks.json +0 -15
package/sys/child.js
CHANGED
|
@@ -33,16 +33,24 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
/**
|
|
37
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
38
|
+
* Date: 2019-5-3 23:54
|
|
39
|
+
* Last: 2020-3-31 15:01:07, 2020-4-9 22:28:50, 2022-07-22 14:19:46, 2022-9-29 22:11:07, 2023-5-1 18:26:57, 2024-1-12 13:32:00, 2024-3-4 16:49:19
|
|
40
|
+
*/
|
|
36
41
|
const http2 = __importStar(require("http2"));
|
|
37
42
|
const tls = __importStar(require("tls"));
|
|
38
43
|
const http = __importStar(require("http"));
|
|
39
44
|
const crypto = __importStar(require("crypto"));
|
|
45
|
+
// --- 库和定义 ---
|
|
40
46
|
const fs = __importStar(require("../lib/fs"));
|
|
41
47
|
const lCore = __importStar(require("../lib/core"));
|
|
42
48
|
const lText = __importStar(require("../lib/text"));
|
|
43
49
|
const sCtr = __importStar(require("../sys/ctr"));
|
|
44
50
|
const kebab = __importStar(require("../index"));
|
|
51
|
+
// --- 初始化 ---
|
|
45
52
|
const sRoute = __importStar(require("../sys/route"));
|
|
53
|
+
/** --- 10 秒往主线程发送一次心跳的 Timer --- */
|
|
46
54
|
const hbTimer = setInterval(function () {
|
|
47
55
|
if (!process.connected || !process.send) {
|
|
48
56
|
return;
|
|
@@ -52,25 +60,39 @@ const hbTimer = setInterval(function () {
|
|
|
52
60
|
pid: process.pid
|
|
53
61
|
});
|
|
54
62
|
}, 10_000);
|
|
63
|
+
/** --- 加载的证书列表(path: { sc, cert }) --- */
|
|
55
64
|
const certList = [];
|
|
65
|
+
/** --- server: index --- */
|
|
56
66
|
let certHostIndex = {};
|
|
67
|
+
/** --- 当前的虚拟主机配置列表 - 读取于 conf/vhost/*.json --- */
|
|
57
68
|
let vhosts = [];
|
|
69
|
+
/** --- http 服务器 --- */
|
|
58
70
|
let httpServer;
|
|
71
|
+
/** --- http2 服务器 --- */
|
|
59
72
|
let http2Server;
|
|
73
|
+
/** --- 当前使用中的连接 --- */
|
|
60
74
|
const linkCount = {};
|
|
75
|
+
/**
|
|
76
|
+
* --- 最终调用执行的函数块,创建 http 服务器等 ---
|
|
77
|
+
*/
|
|
61
78
|
async function run() {
|
|
79
|
+
// --- 加载 全局、vhosts、sni 证书 ---
|
|
62
80
|
await reload();
|
|
81
|
+
// --- 创建服务器并启动(支持 http2/https/http/websocket) ---
|
|
63
82
|
http2Server = http2.createSecureServer({
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
64
84
|
'SNICallback': (servername, cb) => {
|
|
65
85
|
const i = certHostIndex[servername];
|
|
66
86
|
if (i !== undefined) {
|
|
67
87
|
cb(null, certList[i].sc);
|
|
68
88
|
return;
|
|
69
89
|
}
|
|
90
|
+
// --- 查找 servername ---
|
|
70
91
|
for (let i = 0; i < certList.length; ++i) {
|
|
71
92
|
if (!certList[i].cert.checkHost(servername)) {
|
|
72
93
|
continue;
|
|
73
94
|
}
|
|
95
|
+
// --- 找到 ---
|
|
74
96
|
cb(null, certList[i].sc);
|
|
75
97
|
certHostIndex[servername] = i;
|
|
76
98
|
return;
|
|
@@ -213,7 +235,14 @@ async function run() {
|
|
|
213
235
|
});
|
|
214
236
|
}).listen(lCore.globalConfig.httpPort);
|
|
215
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* --- http / https / http2 请求的回调函数 ---
|
|
240
|
+
* @param req 请求对象
|
|
241
|
+
* @param res 响应对象
|
|
242
|
+
* @param https 是否是 ssl
|
|
243
|
+
*/
|
|
216
244
|
async function requestHandler(req, res, https) {
|
|
245
|
+
// --- 打开计时器 ---
|
|
217
246
|
const timer = {
|
|
218
247
|
'timer': {},
|
|
219
248
|
'timeout': 30_000,
|
|
@@ -222,6 +251,7 @@ async function requestHandler(req, res, https) {
|
|
|
222
251
|
return;
|
|
223
252
|
}
|
|
224
253
|
if (res.headersSent) {
|
|
254
|
+
// --- 已经开始输出的,需要用户自行处理 ---
|
|
225
255
|
return;
|
|
226
256
|
}
|
|
227
257
|
res.setHeader('content-length', 37);
|
|
@@ -230,7 +260,9 @@ async function requestHandler(req, res, https) {
|
|
|
230
260
|
}
|
|
231
261
|
};
|
|
232
262
|
timer.timer = setTimeout(timer.callback, timer.timeout);
|
|
263
|
+
// --- 设置服务器名版本 ---
|
|
233
264
|
res.setHeader('Server', 'Kebab/' + kebab.VER);
|
|
265
|
+
// --- 当前 uri ---
|
|
234
266
|
let host = req.headers[':authority'];
|
|
235
267
|
if (host === undefined || typeof host !== 'string') {
|
|
236
268
|
host = req.headers['host'];
|
|
@@ -240,25 +272,41 @@ async function requestHandler(req, res, https) {
|
|
|
240
272
|
}
|
|
241
273
|
}
|
|
242
274
|
const uri = lText.parseUrl(`http${https ? 's' : ''}://${host}${req.url ?? ''}`);
|
|
275
|
+
/** --- 当前的 vhost 配置文件 --- */
|
|
243
276
|
const vhost = getVhostByHostname(uri.hostname ?? '');
|
|
244
277
|
if (!vhost) {
|
|
245
278
|
req.socket.destroy();
|
|
246
279
|
return;
|
|
280
|
+
/*
|
|
281
|
+
const text = '<h1>Kebab: No permissions</h1>host: ' + (req.headers[':authority'] as string | undefined ?? req.headers['host'] ?? '') + '<br>url: ' + (lText.htmlescape(req.url ?? ''));
|
|
282
|
+
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
283
|
+
res.setHeader('content-length', Buffer.byteLength(text));
|
|
284
|
+
res.writeHead(403);
|
|
285
|
+
res.end(text);
|
|
286
|
+
return;
|
|
287
|
+
*/
|
|
247
288
|
}
|
|
248
289
|
const vhostRoot = vhost.root.replace(/\${example}/g, kebab.ROOT_PATH + 'www/example/');
|
|
290
|
+
/** --- 网站绝对根目录,末尾带 / --- */
|
|
249
291
|
let rootPath = lText.isRealPath(vhostRoot) ? vhostRoot : kebab.WWW_CWD + vhostRoot;
|
|
250
292
|
if (!rootPath.endsWith('/')) {
|
|
251
293
|
rootPath += '/';
|
|
252
294
|
}
|
|
295
|
+
/** --- 请求的路径部分,前导带 / 末尾不一定,用户怎么请求就是什么 --- */
|
|
253
296
|
let path = uri.pathname ?? '/';
|
|
254
297
|
if (path !== '/') {
|
|
298
|
+
// --- 去除 ../ ./ 之类的 ---
|
|
255
299
|
path = lText.urlResolve('/', path);
|
|
256
300
|
}
|
|
301
|
+
/** --- [''] / ['', 'abc', 'def'] --- */
|
|
257
302
|
const pathList = path.split('/');
|
|
303
|
+
/** --- 当前处理的路径,前导不带 / 末尾带 /,例如 abc/ --- */
|
|
258
304
|
let now = '';
|
|
259
305
|
for (let i = 0; i < pathList.length; ++i) {
|
|
260
306
|
const item = pathList[i];
|
|
261
307
|
if (item !== '') {
|
|
308
|
+
// --- 判断 item 是文件还是文件夹 ---
|
|
309
|
+
/** --- 'abc' / 'def.json' --- */
|
|
262
310
|
let stat = await fs.stats(rootPath + now + item);
|
|
263
311
|
if (!stat) {
|
|
264
312
|
res.setHeader('content-type', 'text/html; charset=utf-8');
|
|
@@ -269,8 +317,10 @@ async function requestHandler(req, res, https) {
|
|
|
269
317
|
}
|
|
270
318
|
if (stat.isDirectory()) {
|
|
271
319
|
now += item + '/';
|
|
320
|
+
// --- 判断是不是动态层 ---
|
|
272
321
|
stat = await fs.stats(rootPath + now + 'kebab.json');
|
|
273
322
|
if (stat) {
|
|
323
|
+
// --- 动态层,交给 Route 处理器 ---
|
|
274
324
|
try {
|
|
275
325
|
if (await sRoute.run({
|
|
276
326
|
'req': req,
|
|
@@ -303,16 +353,20 @@ async function requestHandler(req, res, https) {
|
|
|
303
353
|
}
|
|
304
354
|
}
|
|
305
355
|
else {
|
|
356
|
+
// --- 文件,直接输出并结束 ---
|
|
306
357
|
await fs.readToResponse(rootPath + now + item, req, res, stat);
|
|
307
358
|
return;
|
|
308
359
|
}
|
|
309
360
|
}
|
|
310
361
|
else {
|
|
362
|
+
// --- item 为空,但是 i 不是 0,则是最后一个空,直接 break ---
|
|
311
363
|
if (i > 0) {
|
|
312
364
|
break;
|
|
313
365
|
}
|
|
366
|
+
// --- 本层是根,判断根是不是动态层 ---
|
|
314
367
|
const stat = await fs.stats(rootPath + now + 'kebab.json');
|
|
315
368
|
if (stat) {
|
|
369
|
+
// --- 动态层,交给 Route 处理器 ---
|
|
316
370
|
try {
|
|
317
371
|
if (await sRoute.run({
|
|
318
372
|
'req': req,
|
|
@@ -345,6 +399,7 @@ async function requestHandler(req, res, https) {
|
|
|
345
399
|
}
|
|
346
400
|
}
|
|
347
401
|
}
|
|
402
|
+
// --- 最后一层是目录,且不是动态层,判断有没有主页,有则输出,没有则 403 出错 ---
|
|
348
403
|
const indexFiles = ['index.html', 'index.htm'];
|
|
349
404
|
for (const indexFile of indexFiles) {
|
|
350
405
|
const stat = await fs.isFile(rootPath + now + indexFile);
|
|
@@ -358,28 +413,43 @@ async function requestHandler(req, res, https) {
|
|
|
358
413
|
res.writeHead(403);
|
|
359
414
|
res.end('<h1>403 Forbidden</h1><hr>Kebab');
|
|
360
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* --- WebSocket 响应 handler ---
|
|
418
|
+
* @param req 请求对象
|
|
419
|
+
* @param socket socket 对象
|
|
420
|
+
* @param https 是否是 https
|
|
421
|
+
*/
|
|
361
422
|
async function upgradeHandler(req, socket, https) {
|
|
362
423
|
socket.removeAllListeners('error');
|
|
424
|
+
// --- 当前 uri ---
|
|
363
425
|
const uri = lText.parseUrl(`ws${https ? 's' : ''}://${req.headers['host'] ?? ''}${req.url ?? ''}`);
|
|
426
|
+
/** --- 当前的 vhost 配置文件 --- */
|
|
364
427
|
const vhost = getVhostByHostname(uri.hostname ?? '');
|
|
365
428
|
if (!vhost) {
|
|
366
429
|
socket.destroy();
|
|
367
430
|
return;
|
|
368
431
|
}
|
|
369
432
|
const vhostRoot = vhost.root.replace(/\${example}/g, kebab.ROOT_PATH + 'www/example/');
|
|
433
|
+
/** --- 网站绝对根目录,末尾带 / --- */
|
|
370
434
|
let rootPath = lText.isRealPath(vhostRoot) ? vhostRoot : kebab.WWW_CWD + vhostRoot;
|
|
371
435
|
if (!rootPath.endsWith('/')) {
|
|
372
436
|
rootPath += '/';
|
|
373
437
|
}
|
|
438
|
+
/** --- 请求的路径部分,前导带 / 末尾不一定,用户怎么请求就是什么 --- */
|
|
374
439
|
let path = uri.pathname ?? '/';
|
|
375
440
|
if (path !== '/') {
|
|
441
|
+
// --- 去除 ../ ./ 之类的 ---
|
|
376
442
|
path = lText.urlResolve('/', path);
|
|
377
443
|
}
|
|
444
|
+
/** --- [''] / ['', 'abc', 'def'] --- */
|
|
378
445
|
const pathList = path.split('/');
|
|
446
|
+
/** --- 当前处理的路径,前导不带 / 末尾带 /,例如 abc/ --- */
|
|
379
447
|
let now = '';
|
|
380
448
|
for (let i = 0; i < pathList.length; ++i) {
|
|
381
449
|
const item = pathList[i];
|
|
382
450
|
if (item !== '') {
|
|
451
|
+
// --- 判断 item 是文件还是文件夹 ---
|
|
452
|
+
/** --- 'abc' / 'def.json' --- */
|
|
383
453
|
let stat = await fs.stats(rootPath + now + item);
|
|
384
454
|
if (!stat) {
|
|
385
455
|
socket.destroy();
|
|
@@ -387,8 +457,10 @@ async function upgradeHandler(req, socket, https) {
|
|
|
387
457
|
}
|
|
388
458
|
if (stat.isDirectory()) {
|
|
389
459
|
now += item + '/';
|
|
460
|
+
// --- 判断是不是动态层 ---
|
|
390
461
|
stat = await fs.stats(rootPath + now + 'kebab.json');
|
|
391
462
|
if (stat) {
|
|
463
|
+
// --- 动态层,交给 Route 处理器 ---
|
|
392
464
|
if (await sRoute.run({
|
|
393
465
|
'req': req,
|
|
394
466
|
'socket': socket,
|
|
@@ -402,16 +474,20 @@ async function upgradeHandler(req, socket, https) {
|
|
|
402
474
|
}
|
|
403
475
|
}
|
|
404
476
|
else {
|
|
477
|
+
// --- 文件,报错 ---
|
|
405
478
|
socket.destroy();
|
|
406
479
|
return;
|
|
407
480
|
}
|
|
408
481
|
}
|
|
409
482
|
else {
|
|
483
|
+
// --- item 为空,但是 i 不是 0,则是最后一个空,直接 break ---
|
|
410
484
|
if (i > 0) {
|
|
411
485
|
break;
|
|
412
486
|
}
|
|
487
|
+
// --- 判断根是不是动态层 ---
|
|
413
488
|
const stat = await fs.stats(rootPath + now + 'kebab.json');
|
|
414
489
|
if (stat) {
|
|
490
|
+
// --- 动态层,交给 Route 处理器 ---
|
|
415
491
|
if (await sRoute.run({
|
|
416
492
|
'req': req,
|
|
417
493
|
'socket': socket,
|
|
@@ -425,9 +501,14 @@ async function upgradeHandler(req, socket, https) {
|
|
|
425
501
|
}
|
|
426
502
|
}
|
|
427
503
|
}
|
|
504
|
+
// --- 最后一层,又不是动态层 ---
|
|
428
505
|
socket.destroy();
|
|
429
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* --- 加载/重载 vhosts 信息、重新加载全局 config、重新加载证书。(清除动态 kebab.json 信息、data 信息、语言包信息) ---
|
|
509
|
+
*/
|
|
430
510
|
async function reload() {
|
|
511
|
+
// --- 清除全局 config,并重新加载全局信息 ---
|
|
431
512
|
const configContent = await fs.getContent(kebab.CONF_CWD + 'config.json', 'utf8');
|
|
432
513
|
if (!configContent) {
|
|
433
514
|
throw `File '${kebab.CONF_CWD}config.json' not found.`;
|
|
@@ -439,6 +520,7 @@ async function reload() {
|
|
|
439
520
|
for (const key in config) {
|
|
440
521
|
lCore.globalConfig[key] = config[key];
|
|
441
522
|
}
|
|
523
|
+
// --- 重新加载 VHOST 信息(/conf/vhost/) ---
|
|
442
524
|
const files = await fs.readDir(kebab.VHOST_CWD);
|
|
443
525
|
vhosts = [];
|
|
444
526
|
for (const file of files) {
|
|
@@ -457,6 +539,7 @@ async function reload() {
|
|
|
457
539
|
vhosts.push(item);
|
|
458
540
|
}
|
|
459
541
|
}
|
|
542
|
+
// --- 重新加载证书对 ---
|
|
460
543
|
certList.length = 0;
|
|
461
544
|
try {
|
|
462
545
|
const certConfig = await fs.getContent(kebab.CONF_CWD + 'cert.json', 'utf8');
|
|
@@ -481,32 +564,41 @@ async function reload() {
|
|
|
481
564
|
}
|
|
482
565
|
}
|
|
483
566
|
catch {
|
|
567
|
+
// --- NOTHING ---
|
|
484
568
|
}
|
|
485
569
|
certHostIndex = {};
|
|
570
|
+
// --- 其他操作 ---
|
|
486
571
|
sRoute.clearKebabConfigs();
|
|
487
572
|
sCtr.clearLocaleData();
|
|
488
573
|
}
|
|
574
|
+
// --- 接收主进程回传信号,主要用来 reload,restart ---
|
|
489
575
|
process.on('message', function (msg) {
|
|
490
576
|
(async function () {
|
|
491
577
|
switch (msg.action) {
|
|
492
578
|
case 'reload': {
|
|
493
579
|
await reload();
|
|
580
|
+
// eslint-disable-next-line no-console
|
|
494
581
|
console.log(`[child] Worker ${process.pid} reload execution succeeded.`);
|
|
495
582
|
break;
|
|
496
583
|
}
|
|
497
584
|
case 'stop': {
|
|
585
|
+
// --- 需要停止监听,等待已有连接全部断开,然后关闭线程 ---
|
|
498
586
|
httpServer.close();
|
|
499
587
|
http2Server.close();
|
|
500
588
|
clearInterval(hbTimer);
|
|
589
|
+
// --- 等待连接全部断开 ---
|
|
590
|
+
/** --- 当前已等待时间,等待不超过 1 小时 --- */
|
|
501
591
|
let waiting = 0;
|
|
502
592
|
while (true) {
|
|
503
593
|
if (!Object.keys(linkCount).length) {
|
|
504
594
|
break;
|
|
505
595
|
}
|
|
596
|
+
// --- 有长连接,等待中 ---
|
|
506
597
|
const str = [];
|
|
507
598
|
for (const key in linkCount) {
|
|
508
599
|
str.push(key + ':' + linkCount[key].toString());
|
|
509
600
|
}
|
|
601
|
+
// eslint-disable-next-line no-console
|
|
510
602
|
console.log(`[child] Worker ${process.pid} busy: ${str.join(',')}.`);
|
|
511
603
|
await lCore.log({
|
|
512
604
|
'path': '',
|
|
@@ -523,6 +615,7 @@ process.on('message', function (msg) {
|
|
|
523
615
|
break;
|
|
524
616
|
}
|
|
525
617
|
}
|
|
618
|
+
// --- 链接全部断开 ---
|
|
526
619
|
process.exit();
|
|
527
620
|
break;
|
|
528
621
|
}
|
|
@@ -532,6 +625,7 @@ process.on('message', function (msg) {
|
|
|
532
625
|
break;
|
|
533
626
|
}
|
|
534
627
|
if (msg.key === '__init__') {
|
|
628
|
+
// --- 初始化 ---
|
|
535
629
|
for (const key in msg.data) {
|
|
536
630
|
lCore.global[key] = msg.data[key];
|
|
537
631
|
}
|
|
@@ -553,20 +647,28 @@ process.on('message', function (msg) {
|
|
|
553
647
|
}, '[child][process][message]' + lText.stringifyJson(e.stack).slice(1, -1), '-error');
|
|
554
648
|
});
|
|
555
649
|
});
|
|
650
|
+
/**
|
|
651
|
+
* --- 获取匹配的 vhost 对象 ---
|
|
652
|
+
* --- 如果有精准匹配,以精准匹配为准,否则为 2 级泛匹配(vSub),最后全局泛匹配(vGlobal) ---
|
|
653
|
+
* @param hostname 当前的 hostname,不带端口
|
|
654
|
+
*/
|
|
556
655
|
function getVhostByHostname(hostname) {
|
|
557
656
|
let vGlobal, vSub;
|
|
558
657
|
for (const vhost of vhosts) {
|
|
559
658
|
for (let domain of vhost.domains) {
|
|
560
659
|
if (domain === '*') {
|
|
660
|
+
// --- 全局泛匹配 ---
|
|
561
661
|
vGlobal = vhost;
|
|
562
662
|
}
|
|
563
663
|
else if (domain.includes('*')) {
|
|
664
|
+
// --- 2 级泛匹配 ---
|
|
564
665
|
domain = domain.replace(/\*/, '^.+?').replace(/\./, '\\.');
|
|
565
666
|
if (new RegExp(domain + '$').test(hostname)) {
|
|
566
667
|
vSub = vhost;
|
|
567
668
|
}
|
|
568
669
|
}
|
|
569
670
|
else if (domain === hostname) {
|
|
671
|
+
// --- 完全匹配 ---
|
|
570
672
|
return vhost;
|
|
571
673
|
}
|
|
572
674
|
}
|
|
@@ -580,6 +682,8 @@ function getVhostByHostname(hostname) {
|
|
|
580
682
|
return null;
|
|
581
683
|
}
|
|
582
684
|
run().catch(function (e) {
|
|
685
|
+
/* eslint-disable no-console */
|
|
583
686
|
console.log('[child] ------ [Process fatal Error] ------');
|
|
584
687
|
console.log(e);
|
|
688
|
+
/* eslint-enable */
|
|
585
689
|
});
|
package/sys/cmd.js
CHANGED
|
@@ -33,6 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
/**
|
|
37
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
38
|
+
* Date: 2020-3-7 23:51:15
|
|
39
|
+
* Last: 2020-3-7 23:51:18, 2022-07-22 14:14:09, 2022-9-27 14:52:19, 2023-5-23 21:42:46, 2024-7-2 15:12:28
|
|
40
|
+
*/
|
|
36
41
|
const http = __importStar(require("http"));
|
|
37
42
|
const lFs = __importStar(require("../lib/fs"));
|
|
38
43
|
const lText = __importStar(require("../lib/text"));
|
|
@@ -40,7 +45,9 @@ const lTime = __importStar(require("../lib/time"));
|
|
|
40
45
|
const lCore = __importStar(require("../lib/core"));
|
|
41
46
|
const lCrypto = __importStar(require("../lib/crypto"));
|
|
42
47
|
const kebab = __importStar(require("../index"));
|
|
48
|
+
/** --- 解析命令 --- */
|
|
43
49
|
const cmds = process.argv.slice(2);
|
|
50
|
+
/** --- 批量创建目录 --- */
|
|
44
51
|
async function initDir(paths) {
|
|
45
52
|
for (const path of paths) {
|
|
46
53
|
if (await lFs.isDir(path)) {
|
|
@@ -59,8 +66,10 @@ async function initDir(paths) {
|
|
|
59
66
|
}
|
|
60
67
|
return true;
|
|
61
68
|
}
|
|
69
|
+
/** --- cmd 解析 --- */
|
|
62
70
|
async function run() {
|
|
63
71
|
if (cmds[0] === 'init' || cmds[0] === 'update') {
|
|
72
|
+
// --- 初始化、更新 ---
|
|
64
73
|
if (!await initDir([
|
|
65
74
|
kebab.CERT_CWD + 'default/',
|
|
66
75
|
kebab.VHOST_CWD,
|
|
@@ -73,6 +82,7 @@ async function run() {
|
|
|
73
82
|
])) {
|
|
74
83
|
return;
|
|
75
84
|
}
|
|
85
|
+
// --- /conf/cert.json ---
|
|
76
86
|
if (!await lFs.isFile(kebab.CONF_CWD + 'cert.json')) {
|
|
77
87
|
lCore.display('KEBAB', 'CREATE', 'FILE', kebab.CONF_CWD + 'cert.json');
|
|
78
88
|
if (!await lFs.putContent(kebab.CONF_CWD + 'cert.json', lText.stringifyJson([
|
|
@@ -85,6 +95,7 @@ async function run() {
|
|
|
85
95
|
return;
|
|
86
96
|
}
|
|
87
97
|
}
|
|
98
|
+
// --- /conf/config.json ---
|
|
88
99
|
let config = {};
|
|
89
100
|
if (await lFs.isFile(kebab.CONF_CWD + 'config.json')) {
|
|
90
101
|
config = lText.parseJson((await lFs.getContent(kebab.CONF_CWD + 'config.json'))?.toString() ?? '{}');
|
|
@@ -92,18 +103,21 @@ async function run() {
|
|
|
92
103
|
else {
|
|
93
104
|
lCore.display('KEBAB', 'CREATE', 'FILE', kebab.CONF_CWD + 'config.json');
|
|
94
105
|
}
|
|
106
|
+
// --- 修复 config ---
|
|
95
107
|
config.httpPort ??= 8080;
|
|
96
108
|
config.httpsPort ??= 4333;
|
|
97
109
|
config.rpcPort ??= 10630;
|
|
98
110
|
config.rpcSecret ??= 'MUSTCHANGE';
|
|
99
111
|
config.debug ??= true;
|
|
100
112
|
config.max ??= 64;
|
|
113
|
+
// --- config - set ---
|
|
101
114
|
config.set ??= {};
|
|
102
115
|
config.set.timezone ??= 8;
|
|
103
116
|
config.set.mustHttps ??= false;
|
|
104
117
|
config.set.cacheTtl ??= 0;
|
|
105
118
|
config.set.staticVer ??= '20200314174905';
|
|
106
119
|
config.set.staticPath ??= '';
|
|
120
|
+
// --- config - db ---
|
|
107
121
|
config.db ??= {};
|
|
108
122
|
config.db.host ??= '127.0.0.1';
|
|
109
123
|
config.db.port ??= 3306;
|
|
@@ -111,12 +125,14 @@ async function run() {
|
|
|
111
125
|
config.db.name ??= 'maiyun';
|
|
112
126
|
config.db.user ??= 'root';
|
|
113
127
|
config.db.pwd ??= 'DashAdmin';
|
|
128
|
+
// --- config - jwt ---
|
|
114
129
|
config.jwt ??= {};
|
|
115
130
|
config.jwt.name ??= 'KE_JWT';
|
|
116
131
|
config.jwt.ttl ??= 172800;
|
|
117
132
|
config.jwt.ssl ??= false;
|
|
118
133
|
config.jwt.secret ??= 'MUSTCHANGE';
|
|
119
134
|
config.jwt.auth ??= false;
|
|
135
|
+
// --- config - dns ---
|
|
120
136
|
config.dns ??= {};
|
|
121
137
|
config.dns['DNSPOD'] ??= {};
|
|
122
138
|
config.dns['DNSPOD'].sid ??= '';
|
|
@@ -124,6 +140,7 @@ async function run() {
|
|
|
124
140
|
config.dns['CF'] ??= {};
|
|
125
141
|
config.dns['CF'].sid ??= '';
|
|
126
142
|
config.dns['CF'].skey ??= '';
|
|
143
|
+
// --- config - kv ---
|
|
127
144
|
config.kv ??= {};
|
|
128
145
|
config.kv.host ??= '127.0.0.1';
|
|
129
146
|
config.kv.port ??= 6379;
|
|
@@ -131,12 +148,15 @@ async function run() {
|
|
|
131
148
|
config.kv.pre ??= 'm_';
|
|
132
149
|
config.kv.user ??= '';
|
|
133
150
|
config.kv.pwd ??= '';
|
|
151
|
+
// --- config - session ---
|
|
134
152
|
config.session ??= {};
|
|
135
153
|
config.session.name ??= 'KE_SESSION';
|
|
136
154
|
config.session.ttl ??= 172800;
|
|
137
155
|
config.session.ssl ??= false;
|
|
156
|
+
// --- config - sql ---
|
|
138
157
|
config.sql ??= {};
|
|
139
158
|
config.sql.pre ??= 'm_';
|
|
159
|
+
// --- config - s3 ---
|
|
140
160
|
config.s3 ??= {};
|
|
141
161
|
config.s3['CF'] ??= {};
|
|
142
162
|
config.s3['CF'].account = '';
|
|
@@ -149,11 +169,14 @@ async function run() {
|
|
|
149
169
|
config.s3['TENCENT'].skey = '';
|
|
150
170
|
config.s3['TENCENT'].region = '';
|
|
151
171
|
config.s3['TENCENT'].bucket = '';
|
|
172
|
+
// --- 保存 config.json ---
|
|
152
173
|
if (!await lFs.putContent(kebab.CONF_CWD + 'config.json', lText.stringifyJson(config, 4))) {
|
|
153
174
|
lCore.display('KEBAB', 'CREATE', 'FILE', kebab.CONF_CWD + 'config.json', '[FAILED]');
|
|
154
175
|
return;
|
|
155
176
|
}
|
|
177
|
+
// --- 只在初始化时 ---
|
|
156
178
|
if (cmds[0] === 'init') {
|
|
179
|
+
// --- /conf/vhost/default.json ---
|
|
157
180
|
if (!await lFs.isFile(kebab.VHOST_CWD + 'default.json')) {
|
|
158
181
|
lCore.display('KEBAB', 'CREATE', 'FILE', kebab.VHOST_CWD + 'default.json');
|
|
159
182
|
if (!await lFs.putContent(kebab.VHOST_CWD + 'default.json', lText.stringifyJson([
|
|
@@ -178,24 +201,29 @@ async function run() {
|
|
|
178
201
|
lCore.display('DONE');
|
|
179
202
|
process.exit();
|
|
180
203
|
}
|
|
204
|
+
// --- 读取配置文件 ---
|
|
181
205
|
const configContent = await lFs.getContent(kebab.CONF_CWD + 'config.json', 'utf8');
|
|
182
206
|
if (!configContent) {
|
|
183
207
|
throw `File '${kebab.CONF_CWD}config.json' not found.`;
|
|
184
208
|
}
|
|
209
|
+
/** --- 系统 config.json --- */
|
|
185
210
|
const config = lText.parseJson(configContent);
|
|
186
211
|
for (const key in config) {
|
|
187
212
|
lCore.globalConfig[key] = config[key];
|
|
188
213
|
}
|
|
189
214
|
if (cmds[0] === '--ind' || cmds[0] === '-i') {
|
|
215
|
+
// --- 运行独立文件,如 node ./index --ind gps ---
|
|
190
216
|
if (!await lFs.isFile(kebab.IND_CWD + cmds[1] + '/index.js')) {
|
|
191
217
|
lCore.display('CMD ERROR', 'IND FILE "' + cmds[1] + '" NOT FOUND.');
|
|
192
218
|
return;
|
|
193
219
|
}
|
|
220
|
+
// --- 载入独立文件入口 ---
|
|
194
221
|
Promise.resolve(`${'../ind/' + cmds[1] + '/index'}`).then(s => __importStar(require(s))).catch((e) => {
|
|
195
222
|
lCore.display('CMD ERROR', 'E', e);
|
|
196
223
|
});
|
|
197
224
|
}
|
|
198
225
|
else {
|
|
226
|
+
// --- 其他,如 node ./index reload 或 restart ---
|
|
199
227
|
const time = lTime.stamp();
|
|
200
228
|
http.request({
|
|
201
229
|
'hostname': '127.0.0.1',
|