@maiyunnet/kebab 2.0.2 → 2.0.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.
- package/index.js +1 -1
- package/lib/sql.js +1 -3
- package/lib/text.js +5 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
- package/index.ts +0 -33
- package/lib/buffer.ts +0 -152
- package/lib/captcha.ts +0 -63
- package/lib/consistent.ts +0 -219
- package/lib/core.ts +0 -880
- package/lib/crypto.ts +0 -384
- package/lib/db.ts +0 -719
- package/lib/dns.ts +0 -405
- package/lib/fs.ts +0 -527
- package/lib/jwt.ts +0 -276
- package/lib/kv.ts +0 -1489
- package/lib/lan.ts +0 -87
- package/lib/net/formdata.ts +0 -166
- package/lib/net/request.ts +0 -150
- package/lib/net/response.ts +0 -59
- package/lib/net.ts +0 -662
- package/lib/s3.ts +0 -235
- package/lib/scan.ts +0 -364
- package/lib/session.ts +0 -230
- package/lib/sql.ts +0 -1151
- package/lib/ssh/sftp.ts +0 -508
- package/lib/ssh/shell.ts +0 -123
- package/lib/ssh.ts +0 -191
- package/lib/text.ts +0 -615
- package/lib/time.ts +0 -254
- package/lib/ws.ts +0 -523
- package/lib/zip.ts +0 -447
- package/lib/zlib.ts +0 -350
- package/main.ts +0 -27
- package/sys/child.ts +0 -678
- package/sys/cmd.ts +0 -225
- package/sys/ctr.ts +0 -904
- package/sys/master.ts +0 -355
- package/sys/mod.ts +0 -1871
- package/sys/route.ts +0 -1113
- package/types/index.d.ts +0 -283
- package/www/example/ctr/main.ts +0 -9
- package/www/example/ctr/middle.ts +0 -26
- package/www/example/ctr/test.ts +0 -3218
- package/www/example/mod/test.ts +0 -47
- package/www/example/mod/testdata.ts +0 -30
- package/www/example/ws/mproxy.ts +0 -16
- package/www/example/ws/rproxy.ts +0 -14
- package/www/example/ws/test.ts +0 -36
package/sys/master.ts
DELETED
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2019-5-2 21:03:42
|
|
4
|
-
* Last: 2020-3-7 10:33:17, 2022-07-22 13:40:10, 2022-09-06 22:40:58, 2024-2-7 01:44:59, 2024-7-2 15:17:09, 2025-6-13 13:06:43
|
|
5
|
-
*/
|
|
6
|
-
import * as os from 'os';
|
|
7
|
-
import * as cluster from 'cluster';
|
|
8
|
-
import * as http from 'http';
|
|
9
|
-
// --- 库和定义 ---
|
|
10
|
-
import * as kebab from '~/index';
|
|
11
|
-
import * as sRoute from '~/sys/route';
|
|
12
|
-
import * as lCore from '~/lib/core';
|
|
13
|
-
import * as lFs from '~/lib/fs';
|
|
14
|
-
import * as lText from '~/lib/text';
|
|
15
|
-
import * as lCrypto from '~/lib/crypto';
|
|
16
|
-
import * as lTime from '~/lib/time';
|
|
17
|
-
import * as lZip from '~/lib/zip';
|
|
18
|
-
|
|
19
|
-
/** --- 当前运行中的子进程列表 --- */
|
|
20
|
-
const workerList: Record<string, {
|
|
21
|
-
/** --- worker 对象 --- */
|
|
22
|
-
'worker': cluster.Worker;
|
|
23
|
-
/** --- worker 对应的 CPU 编号 --- */
|
|
24
|
-
'cpu': number;
|
|
25
|
-
/** --- 此 worker 上次心跳时间 --- */
|
|
26
|
-
'hbtime': number;
|
|
27
|
-
}> = {};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* --- 最终调用执行的函数块 ---
|
|
31
|
-
*/
|
|
32
|
-
async function run(): Promise<void> {
|
|
33
|
-
// --- 读取配置文件 ---
|
|
34
|
-
const configContent = await lFs.getContent(kebab.CONF_CWD + 'config.json', 'utf8');
|
|
35
|
-
if (!configContent) {
|
|
36
|
-
throw `File '${kebab.CONF_CWD}config.json' not found.`;
|
|
37
|
-
}
|
|
38
|
-
/** --- 系统 config.json --- */
|
|
39
|
-
const config = lText.parseJson(configContent);
|
|
40
|
-
for (const key in config) {
|
|
41
|
-
lCore.globalConfig[key] = config[key];
|
|
42
|
-
}
|
|
43
|
-
// --- 监听 RPC 命令 ---
|
|
44
|
-
createRpcListener();
|
|
45
|
-
// --- 30 秒检测一次是否有丢失的子进程 ---
|
|
46
|
-
setInterval(function() {
|
|
47
|
-
checkWorkerLost().catch(function(e) {
|
|
48
|
-
lCore.display('[master] [run] [checkWorkerLost]', e);
|
|
49
|
-
});
|
|
50
|
-
}, 30000);
|
|
51
|
-
// --- 启动进程 ---
|
|
52
|
-
const cpuLength = os.cpus().length;
|
|
53
|
-
lCore.display('[master] [run] CPU LENGTH: ' + cpuLength.toString());
|
|
54
|
-
const cpuLengthMax = cpuLength > lCore.globalConfig.max ? lCore.globalConfig.max : cpuLength;
|
|
55
|
-
for (let i = 0; i < cpuLengthMax; ++i) {
|
|
56
|
-
await createChildProcess(i);
|
|
57
|
-
}
|
|
58
|
-
cluster.default.on('listening', function(worker, address) {
|
|
59
|
-
// --- 子进程开始监听 ---
|
|
60
|
-
lCore.display(`[master] Listening: worker ${worker.process.pid ?? 'undefined'}, Address: ${address.address}:${address.port}.`);
|
|
61
|
-
}).on('exit', function(worker, code) {
|
|
62
|
-
(async function() {
|
|
63
|
-
if (!worker.process.pid) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
// --- 有子线程退出 ---
|
|
67
|
-
if (code === 0) {
|
|
68
|
-
// --- 正常关闭,证明关闭前主进程已经重启新进程了,这里无需在 fork ---
|
|
69
|
-
lCore.display(`[master] Worker ${worker.process.pid} has been disconnected.`);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
// --- 中断,致命错误,需要重新启动一个新线程 ---
|
|
73
|
-
lCore.display(`[master] Worker ${worker.process.pid} has collapsed.`);
|
|
74
|
-
const cpu = workerList[worker.process.pid].cpu;
|
|
75
|
-
delete workerList[worker.process.pid];
|
|
76
|
-
await createChildProcess(cpu);
|
|
77
|
-
}
|
|
78
|
-
})().catch(function(e) {
|
|
79
|
-
lCore.display('[master] [cluster] [exit]', e);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* --- 创建 RPC 监听,用来监听 cmd 或局域网传递过来的数据,并广播给所有子进程,cmd 部分代码在 cmd 中实现 ---
|
|
86
|
-
*/
|
|
87
|
-
function createRpcListener(): void {
|
|
88
|
-
http.createServer(function(req: http.IncomingMessage, res: http.ServerResponse) {
|
|
89
|
-
(async function() {
|
|
90
|
-
/** --- 当前时间戳 --- */
|
|
91
|
-
const time = lTime.stamp();
|
|
92
|
-
/** --- cmd 数据对象 --- */
|
|
93
|
-
const cmd = lCrypto.aesDecrypt((req.url ?? '').slice(1), lCore.globalConfig.rpcSecret);
|
|
94
|
-
if (!cmd) {
|
|
95
|
-
res.end('Error');
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const msg = lText.parseJson(cmd);
|
|
99
|
-
if (!msg) {
|
|
100
|
-
res.end('Failed');
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (msg.time < time - 5) {
|
|
104
|
-
res.end('Timeout');
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (lCore.globalConfig.rpcSecret === 'MUSTCHANGE') {
|
|
108
|
-
res.end('rpcSecret need be "' + lCore.random(32, lCore.RANDOM_LUN) + '"');
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
switch (msg.action) {
|
|
112
|
-
case 'reload': {
|
|
113
|
-
// --- 为所有子线程发送 reload 信息 ---
|
|
114
|
-
for (const pid in workerList) {
|
|
115
|
-
workerList[pid].worker.send({
|
|
116
|
-
'action': 'reload'
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
case 'restart': {
|
|
122
|
-
// --- 为所有子线程发送 stop 信息 ---
|
|
123
|
-
for (const pid in workerList) {
|
|
124
|
-
workerList[pid].worker.send({
|
|
125
|
-
'action': 'stop'
|
|
126
|
-
});
|
|
127
|
-
// --- 开启新线程 ---
|
|
128
|
-
await createChildProcess(workerList[pid].cpu);
|
|
129
|
-
// --- 删除记录 ---
|
|
130
|
-
delete workerList[pid];
|
|
131
|
-
}
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
case 'global': {
|
|
135
|
-
// --- 为所有子进程更新 global 变量 ---
|
|
136
|
-
for (const pid in workerList) {
|
|
137
|
-
workerList[pid].worker.send({
|
|
138
|
-
'action': 'global',
|
|
139
|
-
'key': msg.key,
|
|
140
|
-
'data': msg.data
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
// --- 更新 master 的数据 ---
|
|
144
|
-
if (msg.data === undefined || msg.data === null) {
|
|
145
|
-
delete lCore.global[msg.key];
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
lCore.global[msg.key] = msg.data;
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
case 'code': {
|
|
152
|
-
// --- 更新 code 代码包 ---
|
|
153
|
-
const rtn = await sRoute.getFormData(req);
|
|
154
|
-
if (!rtn) {
|
|
155
|
-
res.end('Abnormal');
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const file = rtn.files['file'];
|
|
159
|
-
if (!file || Array.isArray(file)) {
|
|
160
|
-
res.end('Abnormal');
|
|
161
|
-
await sRoute.unlinkUploadFiles(rtn.files);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
let path = rtn.post['path'];
|
|
165
|
-
if (path.startsWith('/')) {
|
|
166
|
-
path = path.slice(1);
|
|
167
|
-
}
|
|
168
|
-
if (path.endsWith('/')) {
|
|
169
|
-
path = path.slice(0, -1);
|
|
170
|
-
}
|
|
171
|
-
/** --- 最终更新的根目录,以 / 结尾,但用户传入的无所谓 --- */
|
|
172
|
-
let to = kebab.ROOT_CWD + path;
|
|
173
|
-
if (!to.endsWith('/')) {
|
|
174
|
-
to += '/';
|
|
175
|
-
}
|
|
176
|
-
if (!await lFs.isDir(to)) {
|
|
177
|
-
res.end('Path not found: ' + to);
|
|
178
|
-
await sRoute.unlinkUploadFiles(rtn.files);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const buf = await lFs.getContent(file.path);
|
|
182
|
-
if (!buf) {
|
|
183
|
-
res.end('System error');
|
|
184
|
-
await sRoute.unlinkUploadFiles(rtn.files);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const zip = await lZip.get(buf);
|
|
188
|
-
if (!zip) {
|
|
189
|
-
res.end('Zip error');
|
|
190
|
-
await sRoute.unlinkUploadFiles(rtn.files);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
const ls = await zip.getList();
|
|
194
|
-
for (const path in ls) {
|
|
195
|
-
/** --- 带 / 开头的 zip 中文件完整路径 --- */
|
|
196
|
-
const fpath = path.startsWith('/') ? path : '/' + path;
|
|
197
|
-
/** --- 最后一个 / 的所在位置 --- */
|
|
198
|
-
const lio = fpath.lastIndexOf('/');
|
|
199
|
-
/** --- 纯路径,不以 / 开头,以 / 结尾,若是根路径就是空字符串 --- */
|
|
200
|
-
const pat = fpath.slice(1, lio + 1);
|
|
201
|
-
/** --- 纯文件名 --- */
|
|
202
|
-
const fname = fpath.slice(lio + 1);
|
|
203
|
-
if ((pat === 'conf/' && fname === 'config.json') || fname === 'kebab.json') {
|
|
204
|
-
// --- 特殊文件不能覆盖 ---
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
if (fname.endsWith('.js.map') || fname.endsWith('.ts') || fname.endsWith('.gitignore')) {
|
|
208
|
-
// --- 测试或开发文件不覆盖 ---
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
// --- 看文件夹是否存在 ---
|
|
212
|
-
if (pat && !await lFs.isDir(to + pat)) {
|
|
213
|
-
await lFs.mkdir(to + pat);
|
|
214
|
-
}
|
|
215
|
-
// --- 覆盖或创建文件 ---
|
|
216
|
-
await lFs.putContent(to + pat + fname, ls[path]);
|
|
217
|
-
}
|
|
218
|
-
await sRoute.unlinkUploadFiles(rtn.files);
|
|
219
|
-
// --- 检查是否更新 config ---
|
|
220
|
-
if (rtn.post['config'] === '1') {
|
|
221
|
-
const configContent = await lFs.getContent(kebab.CONF_CWD + 'config.json', 'utf8');
|
|
222
|
-
if (configContent) {
|
|
223
|
-
await lFs.putContent(kebab.CONF_CWD + 'config.json', configContent.replace(/"staticVer": ".+?"/, `"staticVer": "${lTime.format(null, 'YmdHis')}"`), {
|
|
224
|
-
'encoding': 'utf8'
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
default: {
|
|
231
|
-
res.end('Not command: ' + msg.action);
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
res.end('Done');
|
|
236
|
-
})().catch(function(e) {
|
|
237
|
-
lCore.display('[master] [createRpcListener]', e);
|
|
238
|
-
});
|
|
239
|
-
}).listen(lCore.globalConfig.rpcPort);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* --- 检测是否有死掉丢失的子进程,复活之 ---
|
|
244
|
-
*/
|
|
245
|
-
async function checkWorkerLost(): Promise<void> {
|
|
246
|
-
const now = Date.now();
|
|
247
|
-
for (const pid in workerList) {
|
|
248
|
-
if (now - workerList[pid].hbtime < 30000) {
|
|
249
|
-
// --- 距离上次心跳,小于 30 秒,正常 ---
|
|
250
|
-
// --- 子线程 10 秒发送一次心跳 ---
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
// --- 异常,也可能主线程因为各种原因休眠,不过无论如何都要将原线程关闭,要不然原线程又发心跳包,就捕获不到了 ---
|
|
254
|
-
lCore.display(`[master] Worker ${pid} lost.`);
|
|
255
|
-
workerList[pid].worker.send({
|
|
256
|
-
'action': 'stop'
|
|
257
|
-
});
|
|
258
|
-
await createChildProcess(workerList[pid].cpu);
|
|
259
|
-
delete workerList[pid];
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* --- 创建一个新的子进程 ---
|
|
265
|
-
* @param cpu CPU ID
|
|
266
|
-
*/
|
|
267
|
-
async function createChildProcess(cpu: number): Promise<void> {
|
|
268
|
-
const worker = cluster.default.fork();
|
|
269
|
-
if (!worker.process.pid) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
workerList[worker.process.pid] = {
|
|
273
|
-
'worker': worker,
|
|
274
|
-
'cpu': cpu,
|
|
275
|
-
'hbtime': Date.now()
|
|
276
|
-
};
|
|
277
|
-
// --- 如果是支持将线程放到对应的 CPU,则执行相关操作 ---
|
|
278
|
-
if (!os.type().toLowerCase().includes('windows')) {
|
|
279
|
-
// --- 非 Windows ---
|
|
280
|
-
const cpr = await lCore.exec(`taskset -cp ${cpu} ${worker.process.pid}`);
|
|
281
|
-
lCore.display(cpr);
|
|
282
|
-
lCore.display(`[master] Worker ${worker.process.pid} start on cpu #${cpu}.`);
|
|
283
|
-
}
|
|
284
|
-
// --- 监听子进程发来的讯息,并扩散给所有子进程 ---
|
|
285
|
-
worker.on('message', function(msg) {
|
|
286
|
-
(async function() {
|
|
287
|
-
switch (msg.action) {
|
|
288
|
-
case 'reload': {
|
|
289
|
-
// --- 为所有子线程发送 reload 信息 ---
|
|
290
|
-
for (const pid in workerList) {
|
|
291
|
-
workerList[pid].worker.send({
|
|
292
|
-
'action': msg.action
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
break;
|
|
296
|
-
}
|
|
297
|
-
case 'restart': {
|
|
298
|
-
// --- 为所有子进程发送 restart 信息 ---
|
|
299
|
-
for (const pid in workerList) {
|
|
300
|
-
workerList[pid].worker.send({
|
|
301
|
-
'action': 'stop'
|
|
302
|
-
});
|
|
303
|
-
// --- 开启新线程 ---
|
|
304
|
-
await createChildProcess(workerList[pid].cpu);
|
|
305
|
-
// --- 删除记录 ---
|
|
306
|
-
delete workerList[pid];
|
|
307
|
-
}
|
|
308
|
-
break;
|
|
309
|
-
}
|
|
310
|
-
case 'global': {
|
|
311
|
-
// --- 为所有子进程更新 global 变量 ---
|
|
312
|
-
for (const pid in workerList) {
|
|
313
|
-
workerList[pid].worker.send({
|
|
314
|
-
'action': 'global',
|
|
315
|
-
'key': msg.key,
|
|
316
|
-
'data': msg.data
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
// --- 更新 master 的数据 ---
|
|
320
|
-
if (msg.data === undefined || msg.data === null) {
|
|
321
|
-
delete lCore.global[msg.key];
|
|
322
|
-
break;
|
|
323
|
-
}
|
|
324
|
-
lCore.global[msg.key] = msg.data;
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
case 'hbtime': {
|
|
328
|
-
// --- 获得子进程发来的 10 秒一次的心跳 ---
|
|
329
|
-
if (!workerList[msg.pid]) {
|
|
330
|
-
// --- 线程存在,主进程记录里没找到 ---
|
|
331
|
-
lCore.display(`[master] Worker ${msg.pid} not found.`);
|
|
332
|
-
break;
|
|
333
|
-
}
|
|
334
|
-
workerList[msg.pid].hbtime = Date.now();
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
})().catch(function(e) {
|
|
339
|
-
lCore.display('[createChildProcess] [message]', e);
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
// --- 将主线程的全局变量传给这个新建的子线程 ---
|
|
343
|
-
if (Object.keys(lCore.global).length) {
|
|
344
|
-
worker.send({
|
|
345
|
-
'action': 'global',
|
|
346
|
-
'key': '__init__',
|
|
347
|
-
'data': lCore.global
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
run().catch(function(e): void {
|
|
353
|
-
lCore.display('[master] ------ [Process fatal Error] ------');
|
|
354
|
-
lCore.display(e);
|
|
355
|
-
});
|