@maiyunnet/kebab 9.20.1 → 9.21.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/doc/kebab-rag.md +472 -33
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +59 -0
- package/lib/core.js +81 -0
- package/lib/fs.d.ts +12 -1
- package/lib/fs.js +214 -159
- package/package.json +1 -1
- package/sys/master.js +54 -0
- package/sys/monitor/files.d.ts +34 -0
- package/sys/monitor/files.js +260 -0
- package/sys/monitor/watchdog.js +284 -215
- package/sys/monitor.d.ts +28 -3
- package/sys/monitor.js +527 -250
- package/www/example/ctr/test.d.ts +21 -0
- package/www/example/ctr/test.js +250 -2
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '9.
|
|
9
|
+
export const VER = '9.21.1';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/core.d.ts
CHANGED
|
@@ -331,6 +331,65 @@ export declare function getLog(opt: {
|
|
|
331
331
|
'list': string[][] | kebab.Json[];
|
|
332
332
|
'total': number;
|
|
333
333
|
} | false>;
|
|
334
|
+
/** --- 已保存监控事件的简短摘要,path 相对于 log/monitor/ --- */
|
|
335
|
+
export interface IMonitorEventSummary {
|
|
336
|
+
'path': string;
|
|
337
|
+
'pid': number;
|
|
338
|
+
'time': number;
|
|
339
|
+
'source': 'main' | 'watchdog';
|
|
340
|
+
'status': string;
|
|
341
|
+
'reasons': string[];
|
|
342
|
+
}
|
|
343
|
+
/** --- 监控文件元数据;复杂格式或超过 1 MiB 的文件不提供预览 --- */
|
|
344
|
+
export interface IMonitorFile {
|
|
345
|
+
'path': string;
|
|
346
|
+
'name': string;
|
|
347
|
+
'size': number;
|
|
348
|
+
/** --- 最后修改时间,单位 ms --- */
|
|
349
|
+
'mtime': number;
|
|
350
|
+
'preview': 'json' | 'text' | null;
|
|
351
|
+
}
|
|
352
|
+
/** --- 事件原始数据与可读取的文件;data 为 null 时可下载原始记录复盘 --- */
|
|
353
|
+
export interface IMonitorEvent {
|
|
354
|
+
'summary': IMonitorEventSummary;
|
|
355
|
+
'data': Record<string, unknown> | null;
|
|
356
|
+
'recordStatus': 'loaded' | 'missing' | 'too-large' | 'invalid' | 'unreadable';
|
|
357
|
+
'files': IMonitorFile[];
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* --- 获取某天已保存的监控事件,按目录时间倒序分页 ---
|
|
361
|
+
* @param opt path 为 YYYY/MM/DD,默认目标服务器的当天;offset 默认 0,limit 默认 20、最多 100
|
|
362
|
+
* @returns 事件列表和总数;无事件时返回空列表,参数、配置或读取错误时返回 false
|
|
363
|
+
*/
|
|
364
|
+
export declare function getMonitorEvents(opt?: {
|
|
365
|
+
'path'?: string;
|
|
366
|
+
'offset'?: number;
|
|
367
|
+
'limit'?: number;
|
|
368
|
+
/** --- 与 getLog 相同,使用目标服务器的 RPC 端口和密钥 --- */
|
|
369
|
+
'host'?: string;
|
|
370
|
+
}): Promise<{
|
|
371
|
+
'list': IMonitorEventSummary[];
|
|
372
|
+
'total': number;
|
|
373
|
+
} | false>;
|
|
374
|
+
/**
|
|
375
|
+
* --- 读取事件详情和文件清单;只解析事件记录,不解析 Profile 或堆快照 ---
|
|
376
|
+
* @param opt path 使用 getMonitorEvents 返回的事件路径;host 默认本机
|
|
377
|
+
* @returns 事件详情;不存在时返回 null,参数、配置或读取错误时返回 false
|
|
378
|
+
*/
|
|
379
|
+
export declare function getMonitorEvent(opt: {
|
|
380
|
+
'path': string;
|
|
381
|
+
'host'?: string;
|
|
382
|
+
}): Promise<IMonitorEvent | null | false>;
|
|
383
|
+
/**
|
|
384
|
+
* --- 获取监控原始文件的响应,可使用 getStream() 下载;小文件可用 getText()/getJson() 预览 ---
|
|
385
|
+
* @param opt path 使用事件 files 中的文件路径;preview=true 只允许 1 MiB 内的 JSON/调用栈文本;host 默认本机
|
|
386
|
+
* @returns 文件响应;不存在时返回 null,参数、预览限制、配置或读取错误时返回 false;流消费或销毁由调用方负责
|
|
387
|
+
*/
|
|
388
|
+
export declare function getMonitorFile(opt: {
|
|
389
|
+
'path': string;
|
|
390
|
+
'preview'?: boolean;
|
|
391
|
+
'host'?: string;
|
|
392
|
+
}): Promise<lUndiciResponse.Response | null | false>;
|
|
334
393
|
/**
|
|
335
394
|
* --- 获取目录内文件/文件夹列表 ---
|
|
336
395
|
* @param opt 参数
|
package/lib/core.js
CHANGED
|
@@ -1182,6 +1182,87 @@ export async function getLog(opt) {
|
|
|
1182
1182
|
'total': res.total,
|
|
1183
1183
|
};
|
|
1184
1184
|
}
|
|
1185
|
+
/**
|
|
1186
|
+
* --- 通过 master RPC 读取已保存的监控数据,不依赖目标 HTTP 子进程 ---
|
|
1187
|
+
* @param action 要读取的监控资源
|
|
1188
|
+
* @param opt 读取参数,host 默认本机
|
|
1189
|
+
* @returns 响应对象;配置或网络错误时返回 false
|
|
1190
|
+
*/
|
|
1191
|
+
async function requestMonitor(action, opt) {
|
|
1192
|
+
if (!Number.isInteger(globalConfig.rpcPort) || typeof globalConfig.rpcSecret !== 'string') {
|
|
1193
|
+
return false;
|
|
1194
|
+
}
|
|
1195
|
+
const command = lCrypto.aesEncrypt(lText.stringifyJson({
|
|
1196
|
+
action, 'time': lTime.stamp(), 'path': opt.path, 'offset': opt.offset,
|
|
1197
|
+
'limit': opt.limit, 'preview': opt.preview,
|
|
1198
|
+
}), globalConfig.rpcSecret);
|
|
1199
|
+
const res = await lUndici.get(`http://${opt.host ?? '127.0.0.1'}:${globalConfig.rpcPort}/${command}`, {
|
|
1200
|
+
'timeout': action === 'monitor-file' ? 300 : 5,
|
|
1201
|
+
'follow': 0,
|
|
1202
|
+
});
|
|
1203
|
+
if (res.error || !res.headers) {
|
|
1204
|
+
await res.getRawStream()?.dump({ 'limit': 4096 });
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
return res;
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* --- 获取某天已保存的监控事件,按目录时间倒序分页 ---
|
|
1211
|
+
* @param opt path 为 YYYY/MM/DD,默认目标服务器的当天;offset 默认 0,limit 默认 20、最多 100
|
|
1212
|
+
* @returns 事件列表和总数;无事件时返回空列表,参数、配置或读取错误时返回 false
|
|
1213
|
+
*/
|
|
1214
|
+
export async function getMonitorEvents(opt = {}) {
|
|
1215
|
+
const res = await requestMonitor('monitor-events', opt);
|
|
1216
|
+
if (res === false) {
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
const text = await res.getText();
|
|
1220
|
+
if (text === null) {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
const result = lText.parseJson(text);
|
|
1224
|
+
if (!result || result.result !== 1 || !Array.isArray(result.list) || !Number.isSafeInteger(result.total)) {
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
return { 'list': result.list, 'total': result.total };
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* --- 读取事件详情和文件清单;只解析事件记录,不解析 Profile 或堆快照 ---
|
|
1231
|
+
* @param opt path 使用 getMonitorEvents 返回的事件路径;host 默认本机
|
|
1232
|
+
* @returns 事件详情;不存在时返回 null,参数、配置或读取错误时返回 false
|
|
1233
|
+
*/
|
|
1234
|
+
export async function getMonitorEvent(opt) {
|
|
1235
|
+
const res = await requestMonitor('monitor-event', opt);
|
|
1236
|
+
if (res === false) {
|
|
1237
|
+
return false;
|
|
1238
|
+
}
|
|
1239
|
+
const text = await res.getText();
|
|
1240
|
+
if (text === null) {
|
|
1241
|
+
return false;
|
|
1242
|
+
}
|
|
1243
|
+
const result = lText.parseJson(text);
|
|
1244
|
+
if (!result || result.result !== 1 || result.data === undefined) {
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
return result.data;
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* --- 获取监控原始文件的响应,可使用 getStream() 下载;小文件可用 getText()/getJson() 预览 ---
|
|
1251
|
+
* @param opt path 使用事件 files 中的文件路径;preview=true 只允许 1 MiB 内的 JSON/调用栈文本;host 默认本机
|
|
1252
|
+
* @returns 文件响应;不存在时返回 null,参数、预览限制、配置或读取错误时返回 false;流消费或销毁由调用方负责
|
|
1253
|
+
*/
|
|
1254
|
+
export async function getMonitorFile(opt) {
|
|
1255
|
+
const res = await requestMonitor('monitor-file', opt);
|
|
1256
|
+
if (res === false) {
|
|
1257
|
+
return false;
|
|
1258
|
+
}
|
|
1259
|
+
if (res.headers?.['http-code'] === 200 && res.headers['x-kebab-monitor-file'] === '1') {
|
|
1260
|
+
return res;
|
|
1261
|
+
}
|
|
1262
|
+
// --- 有界丢弃错误响应;直接 destroy 未消费的 Undici 流会产生未处理的 AbortError ---
|
|
1263
|
+
await res.getRawStream()?.dump({ 'limit': 4096 });
|
|
1264
|
+
return res.headers?.['http-code'] === 404 ? null : false;
|
|
1265
|
+
}
|
|
1185
1266
|
/**
|
|
1186
1267
|
* --- 获取目录内文件/文件夹列表 ---
|
|
1187
1268
|
* @param opt 参数
|
package/lib/fs.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export declare function rmdir(path: string): Promise<boolean>;
|
|
|
74
74
|
* --- Danger 危险:危险函数,尽量不要使用 ---
|
|
75
75
|
* --- This is a danger function, please don't use it ---
|
|
76
76
|
* --- 删除一个非空目录 ---
|
|
77
|
+
* @param path 目录路径,不递归读取符号链接指向的目录
|
|
78
|
+
* @returns 删除成功或根路径不是目录返回 true,删除失败返回 false
|
|
77
79
|
*/
|
|
78
80
|
export declare function rmdirDeep(path: string): Promise<boolean>;
|
|
79
81
|
/**
|
|
@@ -140,10 +142,19 @@ export declare function createWriteStream(path: string, options?: BufferEncoding
|
|
|
140
142
|
'start'?: number;
|
|
141
143
|
}): fs.WriteStream;
|
|
142
144
|
/**
|
|
143
|
-
* --- 读取文件并输出到 http 的 response ---
|
|
145
|
+
* --- 读取文件并输出到 http 的 response,支持 GET 字节范围与条件请求 ---
|
|
146
|
+
*
|
|
147
|
+
* Range 支持 start-end、start-、-length 及最多 16 段,请求头上限 8 KiB;相邻和重叠区间合并。
|
|
148
|
+
* 有效区间返回 206,全部越界或区间过多返回 416;无效语法、未知单位和空文件忽略 Range。
|
|
149
|
+
* 部分响应按原始文件字节流式输出,不进行动态压缩。If-Range 日期须匹配 Last-Modified,
|
|
150
|
+
* 且文件不启用动态压缩、修改时间早于当前响应所在秒,否则退回完整响应;
|
|
151
|
+
* 文件元数据生成的 ETag 为弱校验值,不接受其作为 If-Range 的强校验值。
|
|
152
|
+
* HEAD 忽略 Range 且不输出响应体。
|
|
153
|
+
*
|
|
144
154
|
* @param path 文件绝对路径
|
|
145
155
|
* @param req http 请求对象
|
|
146
156
|
* @param res http 响应对象
|
|
147
157
|
* @param stat 文件的 stat(如果有)
|
|
158
|
+
* @returns 输出完成或连接终止后无返回值
|
|
148
159
|
*/
|
|
149
160
|
export declare function readToResponse(path: string, req: http2.Http2ServerRequest | http.IncomingMessage, res: http2.Http2ServerResponse | http.ServerResponse, stat?: fs.Stats | null): Promise<void>;
|