@maiyunnet/kebab 2.0.7 → 2.0.8
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 +6 -1
- package/main.js +11 -1
- package/package.json +1 -1
- 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/lib/core.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as stream from 'stream';
|
|
|
4
4
|
import * as lResponse from '../lib/net/response';
|
|
5
5
|
import * as sCtr from '../sys/ctr';
|
|
6
6
|
import * as types from '../types';
|
|
7
|
+
/** --- 全局参数 --- */
|
|
7
8
|
export declare const globalConfig: types.IConfig & {
|
|
8
9
|
'httpPort': number;
|
|
9
10
|
'httpsPort': number;
|
|
@@ -12,6 +13,7 @@ export declare const globalConfig: types.IConfig & {
|
|
|
12
13
|
'debug': boolean;
|
|
13
14
|
'max': number;
|
|
14
15
|
};
|
|
16
|
+
/** --- Cookie 设置的选项 --- */
|
|
15
17
|
export interface ICookieOptions {
|
|
16
18
|
'ttl'?: number;
|
|
17
19
|
'path'?: string;
|
|
@@ -20,7 +22,20 @@ export interface ICookieOptions {
|
|
|
20
22
|
'httponly'?: boolean;
|
|
21
23
|
'samesite'?: 'None' | 'Lax' | 'Strict';
|
|
22
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* --- 设置 cookie ---
|
|
27
|
+
* @param ctr ctr 实例
|
|
28
|
+
* @param name 名
|
|
29
|
+
* @param value 值
|
|
30
|
+
* @param opt 选项,ttl, 默认和 undefined 为关闭浏览器失效
|
|
31
|
+
*/
|
|
23
32
|
export declare function setCookie(ctr: sCtr.Ctr, name: string, value: string, opt?: ICookieOptions): void;
|
|
33
|
+
/**
|
|
34
|
+
* --- 生成基础的范围随机数 ---
|
|
35
|
+
* @param min >= 最小值
|
|
36
|
+
* @param max <= 最大值
|
|
37
|
+
* @param prec 保留几位小数
|
|
38
|
+
*/
|
|
24
39
|
export declare function rand(min: number, max: number, prec?: number): number;
|
|
25
40
|
export declare const RANDOM_N = "0123456789";
|
|
26
41
|
export declare const RANDOM_U = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
@@ -31,12 +46,41 @@ export declare const RANDOM_LU: string;
|
|
|
31
46
|
export declare const RANDOM_LUN: string;
|
|
32
47
|
export declare const RANDOM_V = "ACEFGHJKLMNPRSTWXY34567";
|
|
33
48
|
export declare const RANDOM_LUNS: string;
|
|
49
|
+
/**
|
|
50
|
+
* --- 生成随机字符串 ---
|
|
51
|
+
* @param length 长度
|
|
52
|
+
* @param source 采样值
|
|
53
|
+
* @param block 排除的字符
|
|
54
|
+
*/
|
|
34
55
|
export declare function random(length?: number, source?: string, block?: string): string;
|
|
35
56
|
export declare const CONVERT62_CHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
57
|
+
/**
|
|
58
|
+
* --- 将 10 进制转换为 62 进制 ---
|
|
59
|
+
* @param n 10 进制数字最大 9223372036854775807n
|
|
60
|
+
*/
|
|
36
61
|
export declare function convert62(n: bigint | number | string): string;
|
|
62
|
+
/**
|
|
63
|
+
* --- 将 62 进制转换为 10 进制 ---
|
|
64
|
+
* @param n 62 进制数字最大 aZl8N0y58M7
|
|
65
|
+
*/
|
|
37
66
|
export declare function unconvert62(n: string): bigint;
|
|
67
|
+
/**
|
|
68
|
+
* --- 去除 html 的空白符、换行以及注释 ---
|
|
69
|
+
* @param text 要纯净的字符串
|
|
70
|
+
*/
|
|
38
71
|
export declare function purify(text: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* --- 判断一个对象是否符合示例组,返回空字符串代表校验通过,返回:应该的类型:位置:传入的类型 ---
|
|
74
|
+
* @param val 对象
|
|
75
|
+
* @param type 示例组
|
|
76
|
+
* @param tree 当前树,无需传入
|
|
77
|
+
*/
|
|
39
78
|
export declare function checkType(val: any, type: any, tree?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* --- 获取 MUID ---
|
|
81
|
+
* @param ctr Ctr 对象
|
|
82
|
+
* @param opt len: 8 - 32, 默认 8; bin: 是否含有大小写, 默认 true; key: 多样性混合, 默认空; insert: 插入指定字符, 最好不超过 2 字符,默认空,num: 是否含有数字,默认 true
|
|
83
|
+
*/
|
|
40
84
|
export declare function muid(ctr: sCtr.Ctr, opt?: {
|
|
41
85
|
'len'?: number;
|
|
42
86
|
'bin'?: boolean;
|
|
@@ -44,24 +88,84 @@ export declare function muid(ctr: sCtr.Ctr, opt?: {
|
|
|
44
88
|
'insert'?: string;
|
|
45
89
|
'num'?: boolean;
|
|
46
90
|
}): string;
|
|
91
|
+
/**
|
|
92
|
+
* --- 获取 IP(非安全 IP)---
|
|
93
|
+
* @param ctr
|
|
94
|
+
*/
|
|
47
95
|
export declare function ip(ctr: sCtr.Ctr | http.IncomingHttpHeaders, req?: http2.Http2ServerRequest | http.IncomingMessage): string;
|
|
48
96
|
export declare const REAL_IP_X = "x-forwarded-for";
|
|
49
97
|
export declare const REAL_IP_CF = "cf-connecting-ip";
|
|
98
|
+
/**
|
|
99
|
+
* --- 获取直连 IP(安全 IP) ---
|
|
100
|
+
* @param ctr
|
|
101
|
+
* @param name 输入安全的 header
|
|
102
|
+
*/
|
|
50
103
|
export declare function realIP(ctr: sCtr.Ctr, name?: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* --- 间隔一段时间 ---
|
|
106
|
+
* @param ms 间隔毫秒
|
|
107
|
+
*/
|
|
51
108
|
export declare function sleep(ms: number): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* --- 将对象进行升序排列 ---
|
|
111
|
+
* @param o 要重排的对象
|
|
112
|
+
*/
|
|
52
113
|
export declare function objectSort<T extends Record<string, any>>(o: T): T;
|
|
114
|
+
/**
|
|
115
|
+
* --- 将对象的所有属性清除包括键,不会破坏引用关系,对象变量依然保证是引用状态 ---
|
|
116
|
+
* @param obj 要清除的对象
|
|
117
|
+
* @patam deep 也将子项都清空,如果子项有独立引用的话也要清空的话则要设置为 true
|
|
118
|
+
*/
|
|
53
119
|
export declare function emptyObject(obj: Record<string, types.Json>, deep?: boolean): void;
|
|
120
|
+
/**
|
|
121
|
+
* --- 调用前自行创建 passThrough,并且调用 pipe 绑定到应该绑定的对象,然后再调用本函数 ---
|
|
122
|
+
* @param passThrough passThrough 对象
|
|
123
|
+
* @param data 数组
|
|
124
|
+
* @param end 是否关闭写入,默认是,关闭后 passThrough 不能被写入,但仍然可读
|
|
125
|
+
*/
|
|
54
126
|
export declare function passThroughAppend(passThrough: stream.PassThrough, data: Array<stream.Readable | lResponse.Response | string | Buffer>, end?: boolean): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* --- 执行命令行 ---
|
|
129
|
+
* @param command 命令字符串
|
|
130
|
+
*/
|
|
55
131
|
export declare function exec(command: string): Promise<string | false>;
|
|
132
|
+
/**
|
|
133
|
+
* --- 向主进程(或局域网同代码机子)发送广播将进行 reload 操作,等待回传 ---
|
|
134
|
+
* --- 主要作用除代码热更新以外的其他情况 ---
|
|
135
|
+
*/
|
|
56
136
|
export declare function sendReload(hosts?: string[]): Promise<string[]>;
|
|
137
|
+
/**
|
|
138
|
+
* --- 向主进程(或局域网同代码机子)发送广播将进行 restart 操作,停止监听并启动新进程,老进程在连接全部断开后自行销毁 ---
|
|
139
|
+
* --- 主要用作不间断的代码热更新 ---
|
|
140
|
+
*/
|
|
57
141
|
export declare function sendRestart(hosts?: string[]): Promise<string[]>;
|
|
142
|
+
/** --- 跨进程全局变量 --- */
|
|
58
143
|
export declare const global: Record<string, any>;
|
|
144
|
+
/**
|
|
145
|
+
* --- 设置跨线程的全局变量 ---
|
|
146
|
+
* @param key 变量名
|
|
147
|
+
* @param data 变量值
|
|
148
|
+
* @param hosts 局域网列表
|
|
149
|
+
*/
|
|
59
150
|
export declare function setGlobal(key: string, data: types.Json, hosts?: string[]): Promise<string[]>;
|
|
151
|
+
/**
|
|
152
|
+
* --- 移除某个跨线程全局变量 ---
|
|
153
|
+
* @param key 变量名
|
|
154
|
+
* @param hosts 局域网列表
|
|
155
|
+
*/
|
|
60
156
|
export declare function removeGlobal(key: string, hosts?: string[]): Promise<string[]>;
|
|
157
|
+
/**
|
|
158
|
+
* --- 上传并覆盖代码文件,config.json、kebab.json、.js.map、.ts, .gitignore 不会被覆盖和新建 ---
|
|
159
|
+
* @param sourcePath zip 文件
|
|
160
|
+
* @param path 要覆盖到的路径,无所谓是否 / 开头 / 结尾,是对方 kebab 的根据路开始算起
|
|
161
|
+
* @param hosts 局域网多机部署,不设置默认本机部署
|
|
162
|
+
* @param config 是否自动更新 config 的 set.staticVer 为最新,默认更新
|
|
163
|
+
*/
|
|
61
164
|
export declare function updateCode(sourcePath: string, path: string, hosts?: string[], config?: boolean): Promise<Record<string, {
|
|
62
165
|
'result': boolean;
|
|
63
166
|
'return': string;
|
|
64
167
|
}>>;
|
|
168
|
+
/** --- log 设置的选项 --- */
|
|
65
169
|
export interface ILogOptions {
|
|
66
170
|
'path': string;
|
|
67
171
|
'urlFull': string;
|
|
@@ -71,15 +175,45 @@ export interface ILogOptions {
|
|
|
71
175
|
'cookie': Record<string, string>;
|
|
72
176
|
'headers': http.IncomingHttpHeaders;
|
|
73
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* --- 写入文件日志 ---
|
|
180
|
+
* @param msg 自定义内容
|
|
181
|
+
* @param fend 文件名追加
|
|
182
|
+
* @param opt 选项
|
|
183
|
+
*/
|
|
74
184
|
export declare function log(opt: sCtr.Ctr | ILogOptions, msg: string, fend?: string): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* --- 获取日志内容为一个数组 ---
|
|
187
|
+
* @param opt 参数
|
|
188
|
+
*/
|
|
75
189
|
export declare function getLog(opt: {
|
|
190
|
+
/** --- 如 127.0.0.1 --- */
|
|
76
191
|
'host': string;
|
|
192
|
+
/** --- 如 2024/08/01/22 --- */
|
|
77
193
|
'path': string;
|
|
194
|
+
/** --- 如 -error --- */
|
|
78
195
|
'fend'?: string;
|
|
196
|
+
/** --- 仅显示被搜索到的行 --- */
|
|
79
197
|
'search'?: string;
|
|
198
|
+
/** --- 跳过条数 --- */
|
|
80
199
|
'offset'?: number;
|
|
200
|
+
/** --- 最大限制,默认 100 --- */
|
|
81
201
|
'limit'?: number;
|
|
82
202
|
}): Promise<string[][] | null | false>;
|
|
203
|
+
/**
|
|
204
|
+
* --- 完整的克隆一份数组/对象,Kebab: yes, Mutton: no ---
|
|
205
|
+
* @param obj 要克隆的对象
|
|
206
|
+
*/
|
|
83
207
|
export declare function clone(obj: Record<string, any> | any[]): any[] | any;
|
|
208
|
+
/**
|
|
209
|
+
* --- 打印调试信息,线上环境不会打印 ---
|
|
210
|
+
* @param message 参数
|
|
211
|
+
* @param optionalParams 参数
|
|
212
|
+
*/
|
|
84
213
|
export declare function debug(message?: any, ...optionalParams: any[]): void;
|
|
214
|
+
/**
|
|
215
|
+
* --- 向控制台直接显示内容,一般情况下禁止使用 ---
|
|
216
|
+
* @param message 参数
|
|
217
|
+
* @param optionalParams 参数
|
|
218
|
+
*/
|
|
85
219
|
export declare function display(message?: any, ...optionalParams: any[]): void;
|
package/lib/core.js
CHANGED
|
@@ -59,6 +59,11 @@ exports.getLog = getLog;
|
|
|
59
59
|
exports.clone = clone;
|
|
60
60
|
exports.debug = debug;
|
|
61
61
|
exports.display = display;
|
|
62
|
+
/**
|
|
63
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
64
|
+
* Date: 2019-5-3 23:54
|
|
65
|
+
* Last: 2020-4-11 22:34:58, 2022-10-2 14:13:06, 2022-12-28 20:33:24, 2023-12-15 11:49:02, 2024-7-2 15:23:35, 2025-6-13 19:45:53
|
|
66
|
+
*/
|
|
62
67
|
const cp = __importStar(require("child_process"));
|
|
63
68
|
const stream = __importStar(require("stream"));
|
|
64
69
|
const lTime = __importStar(require("../lib/time"));
|
|
@@ -69,12 +74,25 @@ const lCrypto = __importStar(require("../lib/crypto"));
|
|
|
69
74
|
const lResponse = __importStar(require("../lib/net/response"));
|
|
70
75
|
const sCtr = __importStar(require("../sys/ctr"));
|
|
71
76
|
const kebab = __importStar(require("../index"));
|
|
77
|
+
/** --- 全局参数 --- */
|
|
72
78
|
exports.globalConfig = {};
|
|
79
|
+
/**
|
|
80
|
+
* --- 设置 cookie ---
|
|
81
|
+
* @param ctr ctr 实例
|
|
82
|
+
* @param name 名
|
|
83
|
+
* @param value 值
|
|
84
|
+
* @param opt 选项,ttl, 默认和 undefined 为关闭浏览器失效
|
|
85
|
+
*/
|
|
73
86
|
function setCookie(ctr, name, value, opt = {}) {
|
|
74
87
|
const res = ctr.getPrototype('_res');
|
|
75
88
|
if (!res) {
|
|
76
89
|
return;
|
|
77
90
|
}
|
|
91
|
+
/*
|
|
92
|
+
const expires = lTime.get(ctr, {
|
|
93
|
+
'data': lTime.stamp() + ttl
|
|
94
|
+
}).toUTCString();
|
|
95
|
+
*/
|
|
78
96
|
const maxAge = opt.ttl === undefined ? '' : `; Max-Age=${opt.ttl}`;
|
|
79
97
|
const path = `; path=${opt.path ?? '/'}`;
|
|
80
98
|
const domain = opt.domain ? `; domain=${opt.domain}` : '';
|
|
@@ -82,9 +100,16 @@ function setCookie(ctr, name, value, opt = {}) {
|
|
|
82
100
|
const httpOnly = opt.httponly ? '; HttpOnly' : '';
|
|
83
101
|
const sameSite = opt.samesite ? '; SameSite=' + opt.samesite : '';
|
|
84
102
|
const cookies = res.getHeader('set-cookie') ?? [];
|
|
103
|
+
// cookies.push(`${name}=${encodeURIComponent(value)}; expires=${expires}; Max-Age=${ttl}${path}${domain}${secure}${httpOnly}`);
|
|
85
104
|
cookies.push(`${name}=${encodeURIComponent(value)}${maxAge}${path}${domain}${secure}${httpOnly}${sameSite}`);
|
|
86
105
|
res.setHeader('set-cookie', cookies);
|
|
87
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* --- 生成基础的范围随机数 ---
|
|
109
|
+
* @param min >= 最小值
|
|
110
|
+
* @param max <= 最大值
|
|
111
|
+
* @param prec 保留几位小数
|
|
112
|
+
*/
|
|
88
113
|
function rand(min, max, prec = 0) {
|
|
89
114
|
if (prec < 0) {
|
|
90
115
|
prec = 0;
|
|
@@ -94,6 +119,7 @@ function rand(min, max, prec = 0) {
|
|
|
94
119
|
max = max * p;
|
|
95
120
|
return Math.round(Math.random() * (max - min) + min) / p;
|
|
96
121
|
}
|
|
122
|
+
// --- 随机 ---
|
|
97
123
|
exports.RANDOM_N = '0123456789';
|
|
98
124
|
exports.RANDOM_U = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
99
125
|
exports.RANDOM_L = 'abcdefghijklmnopqrstuvwxyz';
|
|
@@ -103,7 +129,14 @@ exports.RANDOM_LU = exports.RANDOM_L + exports.RANDOM_U;
|
|
|
103
129
|
exports.RANDOM_LUN = exports.RANDOM_L + exports.RANDOM_U + exports.RANDOM_N;
|
|
104
130
|
exports.RANDOM_V = 'ACEFGHJKLMNPRSTWXY34567';
|
|
105
131
|
exports.RANDOM_LUNS = exports.RANDOM_LUN + '()`~!@#$%^&*-+=_|{}[]:;"<>,.?/]"';
|
|
132
|
+
/**
|
|
133
|
+
* --- 生成随机字符串 ---
|
|
134
|
+
* @param length 长度
|
|
135
|
+
* @param source 采样值
|
|
136
|
+
* @param block 排除的字符
|
|
137
|
+
*/
|
|
106
138
|
function random(length = 8, source = exports.RANDOM_LN, block = '') {
|
|
139
|
+
// --- 剔除 block 字符 ---
|
|
107
140
|
let len = block.length;
|
|
108
141
|
if (len > 0) {
|
|
109
142
|
for (let i = 0; i < len; ++i) {
|
|
@@ -121,6 +154,10 @@ function random(length = 8, source = exports.RANDOM_LN, block = '') {
|
|
|
121
154
|
return temp;
|
|
122
155
|
}
|
|
123
156
|
exports.CONVERT62_CHAR = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
157
|
+
/**
|
|
158
|
+
* --- 将 10 进制转换为 62 进制 ---
|
|
159
|
+
* @param n 10 进制数字最大 9223372036854775807n
|
|
160
|
+
*/
|
|
124
161
|
function convert62(n) {
|
|
125
162
|
if (typeof n !== 'bigint') {
|
|
126
163
|
n = BigInt(n);
|
|
@@ -132,6 +169,10 @@ function convert62(n) {
|
|
|
132
169
|
}
|
|
133
170
|
return res;
|
|
134
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* --- 将 62 进制转换为 10 进制 ---
|
|
174
|
+
* @param n 62 进制数字最大 aZl8N0y58M7
|
|
175
|
+
*/
|
|
135
176
|
function unconvert62(n) {
|
|
136
177
|
let res = 0n;
|
|
137
178
|
const nl = n.length;
|
|
@@ -140,6 +181,10 @@ function unconvert62(n) {
|
|
|
140
181
|
}
|
|
141
182
|
return res;
|
|
142
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* --- 去除 html 的空白符、换行以及注释 ---
|
|
186
|
+
* @param text 要纯净的字符串
|
|
187
|
+
*/
|
|
143
188
|
function purify(text) {
|
|
144
189
|
text = '>' + text + '<';
|
|
145
190
|
const keepScripts = [];
|
|
@@ -163,9 +208,17 @@ function purify(text) {
|
|
|
163
208
|
});
|
|
164
209
|
return text.slice(1, -1);
|
|
165
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* --- 判断一个对象是否符合示例组,返回空字符串代表校验通过,返回:应该的类型:位置:传入的类型 ---
|
|
213
|
+
* @param val 对象
|
|
214
|
+
* @param type 示例组
|
|
215
|
+
* @param tree 当前树,无需传入
|
|
216
|
+
*/
|
|
166
217
|
function checkType(val, type, tree = 'root') {
|
|
218
|
+
/** --- 要校验的对象 --- */
|
|
167
219
|
const vtype = typeof val;
|
|
168
220
|
if (Array.isArray(type)) {
|
|
221
|
+
// --- 数组的话 ---
|
|
169
222
|
if (!Array.isArray(val)) {
|
|
170
223
|
return 'array:' + tree + ':' + vtype;
|
|
171
224
|
}
|
|
@@ -177,8 +230,10 @@ function checkType(val, type, tree = 'root') {
|
|
|
177
230
|
}
|
|
178
231
|
return '';
|
|
179
232
|
}
|
|
233
|
+
/** --- 要符合的类型 --- */
|
|
180
234
|
const ttype = typeof type;
|
|
181
235
|
if (type instanceof RegExp) {
|
|
236
|
+
// --- 正则 ---
|
|
182
237
|
if (vtype !== 'string') {
|
|
183
238
|
return 'regexp:' + tree + ':' + vtype;
|
|
184
239
|
}
|
|
@@ -188,6 +243,7 @@ function checkType(val, type, tree = 'root') {
|
|
|
188
243
|
if (vtype !== 'string' && val !== undefined && val !== null) {
|
|
189
244
|
return 'string:' + tree + ':' + vtype;
|
|
190
245
|
}
|
|
246
|
+
// --- 是字符串、undefined、null ---
|
|
191
247
|
if (type) {
|
|
192
248
|
return val ? '' : 'require:' + tree + ':' + vtype;
|
|
193
249
|
}
|
|
@@ -206,12 +262,14 @@ function checkType(val, type, tree = 'root') {
|
|
|
206
262
|
if (!Object.keys(type).length) {
|
|
207
263
|
return '';
|
|
208
264
|
}
|
|
265
|
+
// --- 先判断每个值是否相等 ---
|
|
209
266
|
for (const key in type) {
|
|
210
267
|
const res = checkType(val[key], type[key], tree + '.' + key);
|
|
211
268
|
if (res) {
|
|
212
269
|
return res;
|
|
213
270
|
}
|
|
214
271
|
}
|
|
272
|
+
// --- 再判断是否传了类型限定中没有的值 ---
|
|
215
273
|
for (const key in val) {
|
|
216
274
|
if (type[key] !== undefined) {
|
|
217
275
|
continue;
|
|
@@ -222,6 +280,11 @@ function checkType(val, type, tree = 'root') {
|
|
|
222
280
|
}
|
|
223
281
|
return vtype === ttype ? '' : ttype + ':' + tree + ':' + vtype;
|
|
224
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* --- 获取 MUID ---
|
|
285
|
+
* @param ctr Ctr 对象
|
|
286
|
+
* @param opt len: 8 - 32, 默认 8; bin: 是否含有大小写, 默认 true; key: 多样性混合, 默认空; insert: 插入指定字符, 最好不超过 2 字符,默认空,num: 是否含有数字,默认 true
|
|
287
|
+
*/
|
|
225
288
|
function muid(ctr, opt = {}) {
|
|
226
289
|
const len = opt.len ?? 8;
|
|
227
290
|
const bin = opt.bin ?? true;
|
|
@@ -240,9 +303,14 @@ function muid(ctr, opt = {}) {
|
|
|
240
303
|
if (!char) {
|
|
241
304
|
return '';
|
|
242
305
|
}
|
|
306
|
+
// --- 生成随机数 ---
|
|
243
307
|
const over = random(len - 1 - ilen, bin ? (num ? exports.RANDOM_LUN : exports.RANDOM_LU) : (num ? exports.RANDOM_LN : exports.RANDOM_L)) + char[20];
|
|
244
308
|
return over[0] + insert + over.slice(1);
|
|
245
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* --- 获取 IP(非安全 IP)---
|
|
312
|
+
* @param ctr
|
|
313
|
+
*/
|
|
246
314
|
function ip(ctr, req) {
|
|
247
315
|
const headers = ctr instanceof sCtr.Ctr ? ctr.getPrototype('_headers') : ctr;
|
|
248
316
|
if (typeof headers['cf-connecting-ip'] === 'string') {
|
|
@@ -265,6 +333,11 @@ function ip(ctr, req) {
|
|
|
265
333
|
}
|
|
266
334
|
exports.REAL_IP_X = 'x-forwarded-for';
|
|
267
335
|
exports.REAL_IP_CF = 'cf-connecting-ip';
|
|
336
|
+
/**
|
|
337
|
+
* --- 获取直连 IP(安全 IP) ---
|
|
338
|
+
* @param ctr
|
|
339
|
+
* @param name 输入安全的 header
|
|
340
|
+
*/
|
|
268
341
|
function realIP(ctr, name = '') {
|
|
269
342
|
const headers = ctr.getPrototype('_headers');
|
|
270
343
|
if (name !== '') {
|
|
@@ -276,6 +349,11 @@ function realIP(ctr, name = '') {
|
|
|
276
349
|
const req = ctr.getPrototype('_req');
|
|
277
350
|
return req.socket.remoteAddress ?? '';
|
|
278
351
|
}
|
|
352
|
+
// --- 以下 Mutton 没有 ---
|
|
353
|
+
/**
|
|
354
|
+
* --- 间隔一段时间 ---
|
|
355
|
+
* @param ms 间隔毫秒
|
|
356
|
+
*/
|
|
279
357
|
function sleep(ms) {
|
|
280
358
|
return new Promise(function (resolve) {
|
|
281
359
|
setTimeout(function () {
|
|
@@ -283,6 +361,10 @@ function sleep(ms) {
|
|
|
283
361
|
}, ms);
|
|
284
362
|
});
|
|
285
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* --- 将对象进行升序排列 ---
|
|
366
|
+
* @param o 要重排的对象
|
|
367
|
+
*/
|
|
286
368
|
function objectSort(o) {
|
|
287
369
|
const ordered = {};
|
|
288
370
|
const list = Object.keys(o).sort();
|
|
@@ -296,6 +378,11 @@ function objectSort(o) {
|
|
|
296
378
|
}
|
|
297
379
|
return ordered;
|
|
298
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* --- 将对象的所有属性清除包括键,不会破坏引用关系,对象变量依然保证是引用状态 ---
|
|
383
|
+
* @param obj 要清除的对象
|
|
384
|
+
* @patam deep 也将子项都清空,如果子项有独立引用的话也要清空的话则要设置为 true
|
|
385
|
+
*/
|
|
299
386
|
function emptyObject(obj, deep = false) {
|
|
300
387
|
const keys = Object.keys(obj);
|
|
301
388
|
for (const key of keys) {
|
|
@@ -308,10 +395,17 @@ function emptyObject(obj, deep = false) {
|
|
|
308
395
|
delete obj[key];
|
|
309
396
|
}
|
|
310
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* --- 调用前自行创建 passThrough,并且调用 pipe 绑定到应该绑定的对象,然后再调用本函数 ---
|
|
400
|
+
* @param passThrough passThrough 对象
|
|
401
|
+
* @param data 数组
|
|
402
|
+
* @param end 是否关闭写入,默认是,关闭后 passThrough 不能被写入,但仍然可读
|
|
403
|
+
*/
|
|
311
404
|
async function passThroughAppend(passThrough, data, end = true) {
|
|
312
405
|
for (const item of data) {
|
|
313
406
|
if (item instanceof stream.Readable || item instanceof lResponse.Response) {
|
|
314
407
|
const stm = item instanceof stream.Readable ? item : item.getStream();
|
|
408
|
+
// --- 读取流、Net 库 Response 对象 ---
|
|
315
409
|
stm.pipe(passThrough, {
|
|
316
410
|
'end': false
|
|
317
411
|
});
|
|
@@ -322,6 +416,7 @@ async function passThroughAppend(passThrough, data, end = true) {
|
|
|
322
416
|
});
|
|
323
417
|
}
|
|
324
418
|
else {
|
|
419
|
+
// --- 字符串、Buffer ---
|
|
325
420
|
await new Promise((resolve) => {
|
|
326
421
|
passThrough.write(item, () => {
|
|
327
422
|
resolve();
|
|
@@ -333,6 +428,10 @@ async function passThroughAppend(passThrough, data, end = true) {
|
|
|
333
428
|
passThrough.end();
|
|
334
429
|
}
|
|
335
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* --- 执行命令行 ---
|
|
433
|
+
* @param command 命令字符串
|
|
434
|
+
*/
|
|
336
435
|
function exec(command) {
|
|
337
436
|
return new Promise(function (resolve) {
|
|
338
437
|
cp.exec(command, function (err, stdout) {
|
|
@@ -344,15 +443,23 @@ function exec(command) {
|
|
|
344
443
|
});
|
|
345
444
|
});
|
|
346
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* --- 向主进程(或局域网同代码机子)发送广播将进行 reload 操作,等待回传 ---
|
|
448
|
+
* --- 主要作用除代码热更新以外的其他情况 ---
|
|
449
|
+
*/
|
|
347
450
|
async function sendReload(hosts) {
|
|
348
451
|
if (!hosts) {
|
|
452
|
+
// --- 本地模式 ---
|
|
453
|
+
// eslint-disable-next-line no-console
|
|
349
454
|
console.log('[ Child] Sending reload request...');
|
|
350
455
|
process.send({
|
|
351
456
|
'action': 'reload'
|
|
352
457
|
});
|
|
353
458
|
return [];
|
|
354
459
|
}
|
|
460
|
+
// --- 局域网模式 ---
|
|
355
461
|
const time = lTime.stamp();
|
|
462
|
+
/** --- 返回成功的 host --- */
|
|
356
463
|
const rtn = [];
|
|
357
464
|
for (const host of hosts) {
|
|
358
465
|
const res = await lNet.get('http://' + host + ':' + exports.globalConfig.rpcPort.toString() + '/' + lCrypto.aesEncrypt(lText.stringifyJson({
|
|
@@ -372,15 +479,23 @@ async function sendReload(hosts) {
|
|
|
372
479
|
}
|
|
373
480
|
return rtn;
|
|
374
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* --- 向主进程(或局域网同代码机子)发送广播将进行 restart 操作,停止监听并启动新进程,老进程在连接全部断开后自行销毁 ---
|
|
484
|
+
* --- 主要用作不间断的代码热更新 ---
|
|
485
|
+
*/
|
|
375
486
|
async function sendRestart(hosts) {
|
|
376
487
|
if (!hosts) {
|
|
488
|
+
// --- 本地模式 ---
|
|
489
|
+
// eslint-disable-next-line no-console
|
|
377
490
|
console.log('[ Child] Sending restart request...');
|
|
378
491
|
process.send({
|
|
379
492
|
'action': 'restart'
|
|
380
493
|
});
|
|
381
494
|
return [];
|
|
382
495
|
}
|
|
496
|
+
// --- 局域网模式 ---
|
|
383
497
|
const time = lTime.stamp();
|
|
498
|
+
/** --- 返回成功的 host --- */
|
|
384
499
|
const rtn = [];
|
|
385
500
|
for (const host of hosts) {
|
|
386
501
|
const res = await lNet.get('http://' + host + ':' + exports.globalConfig.rpcPort.toString() + '/' + lCrypto.aesEncrypt(lText.stringifyJson({
|
|
@@ -400,9 +515,17 @@ async function sendRestart(hosts) {
|
|
|
400
515
|
}
|
|
401
516
|
return rtn;
|
|
402
517
|
}
|
|
518
|
+
/** --- 跨进程全局变量 --- */
|
|
403
519
|
exports.global = {};
|
|
520
|
+
/**
|
|
521
|
+
* --- 设置跨线程的全局变量 ---
|
|
522
|
+
* @param key 变量名
|
|
523
|
+
* @param data 变量值
|
|
524
|
+
* @param hosts 局域网列表
|
|
525
|
+
*/
|
|
404
526
|
async function setGlobal(key, data, hosts) {
|
|
405
527
|
if (!hosts) {
|
|
528
|
+
// --- 本地模式 ---
|
|
406
529
|
process.send({
|
|
407
530
|
'action': 'global',
|
|
408
531
|
'key': key,
|
|
@@ -410,7 +533,9 @@ async function setGlobal(key, data, hosts) {
|
|
|
410
533
|
});
|
|
411
534
|
return [];
|
|
412
535
|
}
|
|
536
|
+
// --- 局域网模式 ---
|
|
413
537
|
const time = lTime.stamp();
|
|
538
|
+
/** --- 返回成功的 host --- */
|
|
414
539
|
const rtn = [];
|
|
415
540
|
for (const host of hosts) {
|
|
416
541
|
const res = await lNet.get('http://' + host + ':' + exports.globalConfig.rpcPort.toString() + '/' + lCrypto.aesEncrypt(lText.stringifyJson({
|
|
@@ -430,11 +555,24 @@ async function setGlobal(key, data, hosts) {
|
|
|
430
555
|
}
|
|
431
556
|
return rtn;
|
|
432
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* --- 移除某个跨线程全局变量 ---
|
|
560
|
+
* @param key 变量名
|
|
561
|
+
* @param hosts 局域网列表
|
|
562
|
+
*/
|
|
433
563
|
async function removeGlobal(key, hosts) {
|
|
434
564
|
return setGlobal(key, null, hosts);
|
|
435
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* --- 上传并覆盖代码文件,config.json、kebab.json、.js.map、.ts, .gitignore 不会被覆盖和新建 ---
|
|
568
|
+
* @param sourcePath zip 文件
|
|
569
|
+
* @param path 要覆盖到的路径,无所谓是否 / 开头 / 结尾,是对方 kebab 的根据路开始算起
|
|
570
|
+
* @param hosts 局域网多机部署,不设置默认本机部署
|
|
571
|
+
* @param config 是否自动更新 config 的 set.staticVer 为最新,默认更新
|
|
572
|
+
*/
|
|
436
573
|
async function updateCode(sourcePath, path, hosts, config = true) {
|
|
437
574
|
hosts ??= ['127.0.0.1'];
|
|
575
|
+
/** --- 返回成功的 host --- */
|
|
438
576
|
const rtn = {};
|
|
439
577
|
for (const host of hosts) {
|
|
440
578
|
const fd = lNet.getFormData();
|
|
@@ -465,6 +603,12 @@ async function updateCode(sourcePath, path, hosts, config = true) {
|
|
|
465
603
|
}
|
|
466
604
|
return rtn;
|
|
467
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* --- 写入文件日志 ---
|
|
608
|
+
* @param msg 自定义内容
|
|
609
|
+
* @param fend 文件名追加
|
|
610
|
+
* @param opt 选项
|
|
611
|
+
*/
|
|
468
612
|
async function log(opt, msg, fend = '') {
|
|
469
613
|
let req;
|
|
470
614
|
let headers;
|
|
@@ -526,16 +670,24 @@ async function log(opt, msg, fend = '') {
|
|
|
526
670
|
'flag': 'a'
|
|
527
671
|
});
|
|
528
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* --- 获取日志内容为一个数组 ---
|
|
675
|
+
* @param opt 参数
|
|
676
|
+
*/
|
|
529
677
|
async function getLog(opt) {
|
|
530
678
|
const path = kebab.LOG_CWD + opt.host + (opt.fend ?? '') + '/' + opt.path + '.csv';
|
|
531
679
|
if (!await lFs.isFile(path)) {
|
|
532
680
|
return null;
|
|
533
681
|
}
|
|
682
|
+
/** --- 剩余 limit --- */
|
|
534
683
|
let limit = opt.limit ?? 100;
|
|
684
|
+
/** --- 剩余 offset --- */
|
|
535
685
|
let offset = opt.offset ?? 0;
|
|
536
686
|
return new Promise((resolve) => {
|
|
537
687
|
const list = [];
|
|
688
|
+
/** --- 当前行号 --- */
|
|
538
689
|
let line = 0;
|
|
690
|
+
/** --- 当前行数据 --- */
|
|
539
691
|
let packet = '';
|
|
540
692
|
lFs.createReadStream(path, {
|
|
541
693
|
'encoding': 'utf8'
|
|
@@ -544,17 +696,21 @@ async function getLog(opt) {
|
|
|
544
696
|
return;
|
|
545
697
|
}
|
|
546
698
|
while (true) {
|
|
699
|
+
// --- 分包 ---
|
|
547
700
|
const index = buf.indexOf('\n');
|
|
548
701
|
if (index === -1) {
|
|
702
|
+
// --- 本次包还没有结束 ---
|
|
549
703
|
packet += buf;
|
|
550
704
|
break;
|
|
551
705
|
}
|
|
706
|
+
// --- 本次行结束了 ---
|
|
552
707
|
if (limit === 0) {
|
|
553
708
|
break;
|
|
554
709
|
}
|
|
555
710
|
packet += buf.slice(0, index);
|
|
556
711
|
buf = buf.slice(index + 1);
|
|
557
712
|
++line;
|
|
713
|
+
// --- 先执行下本次完成的 ---
|
|
558
714
|
if (line > 1) {
|
|
559
715
|
if (offset === 0) {
|
|
560
716
|
if (!opt.search || packet.includes(opt.search)) {
|
|
@@ -589,10 +745,14 @@ async function getLog(opt) {
|
|
|
589
745
|
--offset;
|
|
590
746
|
}
|
|
591
747
|
}
|
|
748
|
+
// --- 处理结束 ---
|
|
592
749
|
packet = '';
|
|
750
|
+
// --- 看看还有没有后面的粘连包 ---
|
|
593
751
|
if (!buf.length) {
|
|
752
|
+
// --- 没粘连包 ---
|
|
594
753
|
break;
|
|
595
754
|
}
|
|
755
|
+
// --- 有粘连包 ---
|
|
596
756
|
}
|
|
597
757
|
}).on('end', () => {
|
|
598
758
|
resolve(list);
|
|
@@ -601,6 +761,10 @@ async function getLog(opt) {
|
|
|
601
761
|
});
|
|
602
762
|
});
|
|
603
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* --- 完整的克隆一份数组/对象,Kebab: yes, Mutton: no ---
|
|
766
|
+
* @param obj 要克隆的对象
|
|
767
|
+
*/
|
|
604
768
|
function clone(obj) {
|
|
605
769
|
let newObj = {};
|
|
606
770
|
if (obj instanceof Array) {
|
|
@@ -652,12 +816,24 @@ function clone(obj) {
|
|
|
652
816
|
}
|
|
653
817
|
return newObj;
|
|
654
818
|
}
|
|
819
|
+
/**
|
|
820
|
+
* --- 打印调试信息,线上环境不会打印 ---
|
|
821
|
+
* @param message 参数
|
|
822
|
+
* @param optionalParams 参数
|
|
823
|
+
*/
|
|
655
824
|
function debug(message, ...optionalParams) {
|
|
656
825
|
if (!exports.globalConfig.debug) {
|
|
657
826
|
return;
|
|
658
827
|
}
|
|
828
|
+
// eslint-disable-next-line no-console
|
|
659
829
|
console.debug(message, ...optionalParams);
|
|
660
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* --- 向控制台直接显示内容,一般情况下禁止使用 ---
|
|
833
|
+
* @param message 参数
|
|
834
|
+
* @param optionalParams 参数
|
|
835
|
+
*/
|
|
661
836
|
function display(message, ...optionalParams) {
|
|
837
|
+
// eslint-disable-next-line no-console
|
|
662
838
|
console.log(message, ...optionalParams);
|
|
663
839
|
}
|