xshell 1.1.15 → 1.1.17
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/{stdin.d.ts → development.d.ts} +2 -0
- package/{stdin.js → development.js} +11 -1
- package/net.browser.js +2 -2
- package/net.js +3 -3
- package/package.json +1 -1
- package/path.d.ts +2 -2
- package/process.d.ts +65 -20
- package/process.js +128 -32
- package/server.d.ts +1 -1
- package/server.js +38 -38
- package/utils.browser.d.ts +6 -4
- package/utils.browser.js +5 -3
- package/utils.d.ts +8 -6
- package/utils.js +7 -5
|
@@ -2,3 +2,5 @@
|
|
|
2
2
|
- on_key: 按键处理函数
|
|
3
3
|
- on_exit?: ctrl + c 会退出进程,可加入退出前自定义处理逻辑 */
|
|
4
4
|
export declare function process_stdin(on_key: (key: string) => void | Promise<void>, on_exit?: () => void | Promise<void>): void;
|
|
5
|
+
/** 自动配置项目 vscode 设置 */
|
|
6
|
+
export declare function setup_vscode_settings(fpd_root: string): Promise<void>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import process from 'process';
|
|
2
|
+
import { fcopy, fexists, ramdisk } from "./file.js";
|
|
3
|
+
import { noprint } from "./process.js";
|
|
2
4
|
/** 监听终端按键 (输入),并调用 key_processor 处理
|
|
3
5
|
- on_key: 按键处理函数
|
|
4
6
|
- on_exit?: ctrl + c 会退出进程,可加入退出前自定义处理逻辑 */
|
|
@@ -22,4 +24,12 @@ export function process_stdin(on_key, on_exit) {
|
|
|
22
24
|
await on_key(key);
|
|
23
25
|
});
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
/** 自动配置项目 vscode 设置 */
|
|
28
|
+
export async function setup_vscode_settings(fpd_root) {
|
|
29
|
+
if (!ramdisk) {
|
|
30
|
+
const fp_settings = `${fpd_root}.vscode/settings.json`;
|
|
31
|
+
if (!fexists(fp_settings, noprint))
|
|
32
|
+
await fcopy(`${fp_settings.strip_end('json')}template.json`, fp_settings);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=development.js.map
|
package/net.browser.js
CHANGED
|
@@ -384,7 +384,7 @@ export class Remote {
|
|
|
384
384
|
this.reconnecting = false;
|
|
385
385
|
if (!this.disconnected)
|
|
386
386
|
try {
|
|
387
|
-
await timeout(3000,
|
|
387
|
+
await timeout(3000, this.connect(), undefined, this.print);
|
|
388
388
|
this.first_error = true;
|
|
389
389
|
}
|
|
390
390
|
catch (error) {
|
|
@@ -451,7 +451,7 @@ export class Remote {
|
|
|
451
451
|
break;
|
|
452
452
|
if (!this.reconnecting)
|
|
453
453
|
try {
|
|
454
|
-
await timeout(1000 * 2,
|
|
454
|
+
await timeout(1000 * 2, this.call('echo'), undefined, this.print);
|
|
455
455
|
}
|
|
456
456
|
catch (error) {
|
|
457
457
|
if (this.print)
|
package/net.js
CHANGED
|
@@ -46,7 +46,7 @@ async function request_retry(url, options, _timeout, retries = 0, count = 0, pri
|
|
|
46
46
|
// 设置给 undici 设置 timeout, signal 不一定管用,还是得自己兜底
|
|
47
47
|
options.signal = AbortSignal.timeout(_timeout);
|
|
48
48
|
return await timeout(_timeout + 300, // 为 undici 兜底
|
|
49
|
-
|
|
49
|
+
undici.request(url, options), undefined, print.timeout && count >= retries // 只打印最后一次超时的错误,避免太多冗余输出
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
else
|
|
@@ -569,7 +569,7 @@ export class Remote {
|
|
|
569
569
|
this.reconnecting = false;
|
|
570
570
|
if (!this.disconnected)
|
|
571
571
|
try {
|
|
572
|
-
await timeout(3000,
|
|
572
|
+
await timeout(3000, this.connect(), undefined, this.print);
|
|
573
573
|
this.first_error = true;
|
|
574
574
|
}
|
|
575
575
|
catch (error) {
|
|
@@ -636,7 +636,7 @@ export class Remote {
|
|
|
636
636
|
break;
|
|
637
637
|
if (!this.reconnecting)
|
|
638
638
|
try {
|
|
639
|
-
await timeout(1000 * 2,
|
|
639
|
+
await timeout(1000 * 2, this.call('echo'), undefined, this.print);
|
|
640
640
|
}
|
|
641
641
|
catch (error) {
|
|
642
642
|
if (this.print)
|
package/package.json
CHANGED
package/path.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export declare function extname(path: string): string;
|
|
|
54
54
|
/** `/` */
|
|
55
55
|
export declare const sep = "/";
|
|
56
56
|
/** The platform-specific file delimiter. ';' or ':'. */
|
|
57
|
-
export declare const delimiter: "
|
|
57
|
+
export declare const delimiter: ":" | ";";
|
|
58
58
|
/** Returns an object from a path string - the opposite of format().
|
|
59
59
|
@param path path to evaluate.
|
|
60
60
|
@throws {TypeError} if `path` is not a string. */
|
|
@@ -81,7 +81,7 @@ export declare let path: {
|
|
|
81
81
|
basename: typeof basename;
|
|
82
82
|
extname: typeof extname;
|
|
83
83
|
sep: string;
|
|
84
|
-
delimiter: "
|
|
84
|
+
delimiter: ":" | ";";
|
|
85
85
|
parse: typeof parse;
|
|
86
86
|
format: typeof format;
|
|
87
87
|
toNamespacedPath: typeof toNamespacedPath;
|
package/process.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ interface BaseOptions {
|
|
|
49
49
|
|
|
50
50
|
具体有什么用还不清楚 */
|
|
51
51
|
window?: boolean;
|
|
52
|
+
/** 由创建进程的调用者设置的,用于区分、识别、记忆的可选名称 */
|
|
53
|
+
title?: string;
|
|
52
54
|
}
|
|
53
55
|
export interface StartOptions extends BaseOptions {
|
|
54
56
|
/** `true` 是否打印启动命令行 */
|
|
@@ -60,7 +62,25 @@ export interface StartOptions extends BaseOptions {
|
|
|
60
62
|
/** 使用文件作为标准错误 */
|
|
61
63
|
fp_stderr?: string;
|
|
62
64
|
}
|
|
63
|
-
|
|
65
|
+
export declare function get_command(exe: string, args?: string[]): string;
|
|
66
|
+
export interface SubProcess<TOutput extends string | Buffer = string> extends ChildProcess {
|
|
67
|
+
/** 由创建进程的调用者设置的,用于区分、识别、记忆的可选名称 */
|
|
68
|
+
title?: string;
|
|
69
|
+
/** 启动的 exe 路径,等于传入 call, start 的 exe */
|
|
70
|
+
exe: string;
|
|
71
|
+
/** 启动参数, 无参数时确保为 `[ ]` */
|
|
72
|
+
args: string[];
|
|
73
|
+
/** 启动命令 */
|
|
74
|
+
command: string;
|
|
75
|
+
/** 调用 call 的 Promise 结果,call, launch 都有,start 创建的进程没有 */
|
|
76
|
+
presult: Promise<CallResult<TOutput>>;
|
|
77
|
+
/** 是否还在运行 */
|
|
78
|
+
get running(): boolean;
|
|
79
|
+
/** 是否已结束,等价于 !running */
|
|
80
|
+
get finished(): boolean;
|
|
81
|
+
}
|
|
82
|
+
/** 启动独立 (detached) 的进程,不受当前 node.js 进程退出的影响,重定向 stdio 到文件或直接忽略
|
|
83
|
+
使用 windowsHide 选项避免创建命令行窗口
|
|
64
84
|
- exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高)
|
|
65
85
|
- args?: `[ ]` 参数列表
|
|
66
86
|
- options?:
|
|
@@ -72,7 +92,7 @@ export interface StartOptions extends BaseOptions {
|
|
|
72
92
|
- fp_stdin?: 使用文件作为标准输入,设置 stdio 中对应的值
|
|
73
93
|
- fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
|
|
74
94
|
- fp_stderr?: 使用文件作为标准错误,设置 stdio 中对应的值 */
|
|
75
|
-
export declare function start(exe: string, args?: string[], options?: StartOptions): Promise<
|
|
95
|
+
export declare function start(exe: string, args?: string[], options?: StartOptions): Promise<SubProcess>;
|
|
76
96
|
export interface CallOptions extends BaseOptions {
|
|
77
97
|
/** `true` print 选项,支持设置细项 */
|
|
78
98
|
print?: boolean | FullPrintOptions;
|
|
@@ -80,8 +100,11 @@ export interface CallOptions extends BaseOptions {
|
|
|
80
100
|
throw_code?: boolean;
|
|
81
101
|
/** `'utf-8'` 子进程输出编码 */
|
|
82
102
|
encoding?: 'binary' | Encoding;
|
|
83
|
-
/** `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 */
|
|
103
|
+
/** `[stdin ? 'pipe' : 'ignore', 'pipe', 'pipe']` 设置为 'ignore' 时忽略 stdio 处理 */
|
|
84
104
|
stdio?: 'pipe' | 'ignore' | [StdioType, StdioType, StdioType];
|
|
105
|
+
/** `false` 子进程是否可能会读取 stdin
|
|
106
|
+
设置为 true 时会设置子进程 stdin 为 'pipe', 否则为 'ignore' */
|
|
107
|
+
stdin?: boolean;
|
|
85
108
|
/** 启动子进程之后写入到子进程 stdin 中的内容,写完后关闭子进程 stdin */
|
|
86
109
|
input?: string;
|
|
87
110
|
/** 实时处理 stdout 和 stderr 的每个 chunk,启用后子进程输出不会自动 print */
|
|
@@ -90,7 +113,7 @@ export interface CallOptions extends BaseOptions {
|
|
|
90
113
|
stderr?: (chunk: string) => void;
|
|
91
114
|
};
|
|
92
115
|
/** 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
|
|
93
|
-
on_child?: (child:
|
|
116
|
+
on_child?: (child: SubProcess) => void;
|
|
94
117
|
}
|
|
95
118
|
export interface CallResult<TOutput extends string | Buffer = string> {
|
|
96
119
|
pid: number;
|
|
@@ -100,7 +123,7 @@ export interface CallResult<TOutput extends string | Buffer = string> {
|
|
|
100
123
|
signal: NodeJS.Signals | null;
|
|
101
124
|
command: string;
|
|
102
125
|
message: string;
|
|
103
|
-
child:
|
|
126
|
+
child: SubProcess<TOutput>;
|
|
104
127
|
print: FullPrintOptions;
|
|
105
128
|
}
|
|
106
129
|
export interface CallError<TOutput extends string | Buffer = string> extends Error {
|
|
@@ -110,7 +133,7 @@ export interface CallError<TOutput extends string | Buffer = string> extends Err
|
|
|
110
133
|
code: number;
|
|
111
134
|
signal: NodeJS.Signals;
|
|
112
135
|
command: string;
|
|
113
|
-
child:
|
|
136
|
+
child: SubProcess<TOutput>;
|
|
114
137
|
print: FullPrintOptions;
|
|
115
138
|
}
|
|
116
139
|
export declare class CallError<TOutput extends string | Buffer = string> extends Error {
|
|
@@ -118,7 +141,7 @@ export declare class CallError<TOutput extends string | Buffer = string> extends
|
|
|
118
141
|
constructor({ message, pid, stdout, stderr, code, signal, command, child, print }: CallResult<TOutput>);
|
|
119
142
|
[inspect.custom](depth: number, options: InspectOptions, inspect: Function): string;
|
|
120
143
|
}
|
|
121
|
-
/**
|
|
144
|
+
/** 调用 exe 启动子进程,等待并获取返回结果,错误时抛出 CallError
|
|
122
145
|
- exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
|
|
123
146
|
- args: `[ ]` 参数列表
|
|
124
147
|
- options?:
|
|
@@ -135,14 +158,26 @@ export declare function call(exe: string, args: string[], options: CallOptions &
|
|
|
135
158
|
encoding: 'binary';
|
|
136
159
|
}): Promise<CallResult<Buffer>>;
|
|
137
160
|
export declare function call(exe: string, args?: string[], options?: CallOptions): Promise<CallResult<string>>;
|
|
138
|
-
|
|
161
|
+
/** 调用 exe 启动子进程(通常是长期在后台运行的,或者可交互的,需要能控制)
|
|
162
|
+
返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
|
|
163
|
+
其中有 presult 属性,是调用 call 的 Promise 结果
|
|
164
|
+
- exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
|
|
165
|
+
- args: `[ ]` 参数列表
|
|
166
|
+
- options?: 见 {@link CallOptions} */
|
|
167
|
+
export declare function launch(exe: string, args: string[], options: CallOptions & {
|
|
168
|
+
encoding: 'binary';
|
|
169
|
+
}): Promise<SubProcess<Buffer>>;
|
|
170
|
+
export declare function launch(exe: string, args?: string[], options?: CallOptions): Promise<SubProcess<string>>;
|
|
171
|
+
export interface NodeJsOptions {
|
|
139
172
|
inspect?: number | true;
|
|
140
173
|
break?: boolean;
|
|
141
174
|
}
|
|
175
|
+
export interface CallNodeJsOptions extends CallOptions, NodeJsOptions {
|
|
176
|
+
}
|
|
142
177
|
/** 调用 node <js> 并等待结果
|
|
143
178
|
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
144
179
|
- args?: `[ ]` 参数列表
|
|
145
|
-
- options?:
|
|
180
|
+
- options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
|
|
146
181
|
- cwd?: `'T:/'`
|
|
147
182
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
148
183
|
- encoding?: `'utf-8'` 子进程输出编码
|
|
@@ -151,19 +186,29 @@ export interface CallNodeJsOptions extends CallOptions {
|
|
|
151
186
|
- throw_code?: `true` code 不为 0 时是否抛出异常
|
|
152
187
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
153
188
|
- break?: break at first line */
|
|
154
|
-
export declare function call_nodejs(js: string, args?: string[],
|
|
155
|
-
export interface StartNodeJsOptions extends StartOptions {
|
|
156
|
-
inspect?: number | true;
|
|
157
|
-
break?: boolean;
|
|
189
|
+
export declare function call_nodejs(js: string, args?: string[], options?: CallNodeJsOptions): Promise<CallResult<string>>;
|
|
190
|
+
export interface StartNodeJsOptions extends StartOptions, NodeJsOptions {
|
|
158
191
|
}
|
|
159
|
-
/**
|
|
192
|
+
/** 启动独立的 node.js 进程 (detached),执行某个 js 文件
|
|
160
193
|
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
161
194
|
- args: `[]` 参数列表
|
|
162
|
-
- options
|
|
163
|
-
- cwd?: `'T:/'`
|
|
164
|
-
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
165
|
-
- print?: `true` print 选项,支持设置细项
|
|
195
|
+
- options?: {@link StartNodeJsOptions} 继承自 {@link StartOptions} 和 {@link NodeJsOptions}
|
|
166
196
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
167
|
-
- break?:
|
|
168
|
-
export declare function start_nodejs(js: string, args?: string[],
|
|
197
|
+
- break?: 在第一行停止 */
|
|
198
|
+
export declare function start_nodejs(js: string, args?: string[], options?: StartNodeJsOptions): Promise<SubProcess<string>>;
|
|
199
|
+
/** 启动子 node.js 进程(通常是长期在后台运行的,或者可交互的,需要能控制),执行某个 js 文件,
|
|
200
|
+
返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
|
|
201
|
+
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
202
|
+
- args: `[]` 参数列表
|
|
203
|
+
- options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
|
|
204
|
+
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
205
|
+
- break?: 在第一行停止 */
|
|
206
|
+
export declare function launch_nodejs(js: string, args?: string[], options?: CallNodeJsOptions): Promise<SubProcess<string>>;
|
|
207
|
+
/** 可选的向子进程输入内容,并等待子进程输出特定的内容,类似一次无返回值,仅有完成状态的 rpc 调用
|
|
208
|
+
根据文本内容匹配其实不太好,实在是没有别的 rpc 方法再使用吧
|
|
209
|
+
- ps: 子进程
|
|
210
|
+
- pattern: 匹配内容,支持 string 和 RegExp
|
|
211
|
+
- input?: 要输入的内容
|
|
212
|
+
- timeout?: 等待超时时间 */
|
|
213
|
+
export declare function wait_output(ps: SubProcess, pattern: string | RegExp, input?: string, _timeout?: number): Promise<void>;
|
|
169
214
|
export {};
|
package/process.js
CHANGED
|
@@ -2,16 +2,24 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import node_sea from 'node:sea';
|
|
4
4
|
import "./prototype.js";
|
|
5
|
-
import { inspect, DecoderStream, filter_values, check, colored } from "./utils.js";
|
|
5
|
+
import { inspect, DecoderStream, filter_values, check, colored, timeout } from "./utils.js";
|
|
6
6
|
export const sea = node_sea.isSea();
|
|
7
7
|
export const exe_nodejs = process.execPath.fp;
|
|
8
8
|
export const platform = os.platform();
|
|
9
9
|
export const username = os.userInfo().username;
|
|
10
10
|
export const noprint = { print: false };
|
|
11
11
|
export const print_no_command = { print: { command: false, code: false, stdout: true, stderr: true } };
|
|
12
|
+
export function get_command(exe, args) {
|
|
13
|
+
return (short_exe_names[exe] || exe.quote_if_space()) +
|
|
14
|
+
(args?.length
|
|
15
|
+
? ` ${args.map(arg => arg.quote_if_space()).join(' ')}`
|
|
16
|
+
: '');
|
|
17
|
+
}
|
|
12
18
|
async function prepare_spawn(detached, exe, args, { cwd, window: _window, envs,
|
|
13
19
|
// @ts-ignore
|
|
14
|
-
input,
|
|
20
|
+
input,
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
stdin, fp_stdin, fp_stdout, fp_stderr, print = true, proxy,
|
|
15
23
|
// @ts-ignore
|
|
16
24
|
stdio }) {
|
|
17
25
|
// --- 处理 proxy, envs
|
|
@@ -46,7 +54,12 @@ stdio }) {
|
|
|
46
54
|
else if (detached)
|
|
47
55
|
stdio = ['ignore', 'ignore', 'ignore'];
|
|
48
56
|
else
|
|
49
|
-
stdio = [
|
|
57
|
+
stdio = [
|
|
58
|
+
// 当子进程 stdin 为 'ignore' 时,python 会报错 [WinError 6] 句柄无效,cmd / powershell 都会立即结束退出
|
|
59
|
+
(stdin || input) ? 'pipe' : 'ignore',
|
|
60
|
+
'pipe',
|
|
61
|
+
'pipe'
|
|
62
|
+
];
|
|
50
63
|
if (fp_stdin || fp_stdout || fp_stderr) {
|
|
51
64
|
const { fopen } = await import("./file.js");
|
|
52
65
|
async function open(fp, flags) {
|
|
@@ -71,6 +84,7 @@ stdio }) {
|
|
|
71
84
|
}
|
|
72
85
|
if (detached)
|
|
73
86
|
check(stdio.every((x) => x === 'ignore' || typeof x === 'number'), '调用 start 时 stdio 只能是 fd 或者 ignore');
|
|
87
|
+
// --- 处理 stdio 结束
|
|
74
88
|
if (typeof print === 'boolean')
|
|
75
89
|
print = {
|
|
76
90
|
command: print,
|
|
@@ -78,13 +92,7 @@ stdio }) {
|
|
|
78
92
|
stdout: print,
|
|
79
93
|
stderr: print
|
|
80
94
|
};
|
|
81
|
-
const command = (
|
|
82
|
-
(args.length
|
|
83
|
-
? ' ' +
|
|
84
|
-
args
|
|
85
|
-
.map(arg => arg.quote_if_space())
|
|
86
|
-
.join(' ')
|
|
87
|
-
: '');
|
|
95
|
+
const command = get_command(exe, args);
|
|
88
96
|
if (print.command)
|
|
89
97
|
console.log(command.blue);
|
|
90
98
|
return {
|
|
@@ -102,7 +110,40 @@ stdio }) {
|
|
|
102
110
|
close_all_handles: opened_handles.length ? close_all_handles : undefined
|
|
103
111
|
};
|
|
104
112
|
}
|
|
105
|
-
|
|
113
|
+
function to_subprocess(child, { title, exe, args, command, }) {
|
|
114
|
+
if (title)
|
|
115
|
+
child.title = title;
|
|
116
|
+
child.exe = exe;
|
|
117
|
+
child.args = args || [];
|
|
118
|
+
child.command = command;
|
|
119
|
+
child[inspect.custom] = () => {
|
|
120
|
+
const { title, command, running, exitCode, presult } = child;
|
|
121
|
+
return {
|
|
122
|
+
...title ? { title } : {},
|
|
123
|
+
command,
|
|
124
|
+
running,
|
|
125
|
+
...running ? {} : {
|
|
126
|
+
code: exitCode,
|
|
127
|
+
presult
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
Object.defineProperties(child, {
|
|
132
|
+
finished: {
|
|
133
|
+
get() {
|
|
134
|
+
return this.exitCode !== null;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
running: {
|
|
138
|
+
get() {
|
|
139
|
+
return this.exitCode === null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return child;
|
|
144
|
+
}
|
|
145
|
+
/** 启动独立 (detached) 的进程,不受当前 node.js 进程退出的影响,重定向 stdio 到文件或直接忽略
|
|
146
|
+
使用 windowsHide 选项避免创建命令行窗口
|
|
106
147
|
- exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高)
|
|
107
148
|
- args?: `[ ]` 参数列表
|
|
108
149
|
- options?:
|
|
@@ -115,9 +156,9 @@ stdio }) {
|
|
|
115
156
|
- fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
|
|
116
157
|
- fp_stderr?: 使用文件作为标准错误,设置 stdio 中对应的值 */
|
|
117
158
|
export async function start(exe, args = [], options = {}) {
|
|
118
|
-
const { spawn_options, close_all_handles } = await prepare_spawn(true, exe, args, options);
|
|
159
|
+
const { spawn_options, close_all_handles, command } = await prepare_spawn(true, exe, args, options);
|
|
119
160
|
try {
|
|
120
|
-
let child = spawn(exe, args, spawn_options);
|
|
161
|
+
let child = to_subprocess(spawn(exe, args, spawn_options), { exe, command, args, title: options.title });
|
|
121
162
|
child.unref();
|
|
122
163
|
return child;
|
|
123
164
|
}
|
|
@@ -157,7 +198,7 @@ export async function call(exe, args = [], options = {}) {
|
|
|
157
198
|
const { print, spawn_options, close_all_handles, command } = await prepare_spawn(false, exe, args, options);
|
|
158
199
|
let child;
|
|
159
200
|
try {
|
|
160
|
-
child = spawn(exe, args, spawn_options);
|
|
201
|
+
child = to_subprocess(spawn(exe, args, spawn_options), { exe, args, command, title: options.title });
|
|
161
202
|
}
|
|
162
203
|
finally {
|
|
163
204
|
if (close_all_handles)
|
|
@@ -253,14 +294,30 @@ export async function call(exe, args = [], options = {}) {
|
|
|
253
294
|
});
|
|
254
295
|
}
|
|
255
296
|
};
|
|
256
|
-
if (throw_code &&
|
|
297
|
+
if (throw_code && code)
|
|
257
298
|
throw new CallError(result);
|
|
258
299
|
return result;
|
|
259
300
|
}
|
|
301
|
+
export async function launch(exe, args, options) {
|
|
302
|
+
let presult;
|
|
303
|
+
let ps = await new Promise((resolve, reject) => {
|
|
304
|
+
try {
|
|
305
|
+
presult = call(exe, args, {
|
|
306
|
+
on_child: resolve,
|
|
307
|
+
...options,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
reject(error);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
ps.presult = presult;
|
|
315
|
+
return ps;
|
|
316
|
+
}
|
|
260
317
|
/** 调用 node <js> 并等待结果
|
|
261
318
|
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
262
319
|
- args?: `[ ]` 参数列表
|
|
263
|
-
- options?:
|
|
320
|
+
- options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
|
|
264
321
|
- cwd?: `'T:/'`
|
|
265
322
|
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
266
323
|
- encoding?: `'utf-8'` 子进程输出编码
|
|
@@ -269,30 +326,69 @@ export async function call(exe, args = [], options = {}) {
|
|
|
269
326
|
- throw_code?: `true` code 不为 0 时是否抛出异常
|
|
270
327
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
271
328
|
- break?: break at first line */
|
|
272
|
-
export async function call_nodejs(js, args
|
|
273
|
-
return call(exe_nodejs,
|
|
274
|
-
'--enable-source-maps',
|
|
275
|
-
...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect === true ? 9229 : inspect}`] : [],
|
|
276
|
-
js,
|
|
277
|
-
...args
|
|
278
|
-
], options);
|
|
329
|
+
export async function call_nodejs(js, args, options) {
|
|
330
|
+
return call(exe_nodejs, get_nodejs_args(js, args, options), options);
|
|
279
331
|
}
|
|
280
|
-
/**
|
|
332
|
+
/** 启动独立的 node.js 进程 (detached),执行某个 js 文件
|
|
281
333
|
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
282
334
|
- args: `[]` 参数列表
|
|
283
|
-
- options
|
|
284
|
-
- cwd?: `'T:/'`
|
|
285
|
-
- envs?: `process.env` 覆盖/添加到 process.env 的环境变量
|
|
286
|
-
- print?: `true` print 选项,支持设置细项
|
|
335
|
+
- options?: {@link StartNodeJsOptions} 继承自 {@link StartOptions} 和 {@link NodeJsOptions}
|
|
287
336
|
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
288
|
-
- break?:
|
|
289
|
-
export async function start_nodejs(js, args
|
|
290
|
-
return start(exe_nodejs,
|
|
337
|
+
- break?: 在第一行停止 */
|
|
338
|
+
export async function start_nodejs(js, args, options) {
|
|
339
|
+
return start(exe_nodejs, get_nodejs_args(js, args, options), options);
|
|
340
|
+
}
|
|
341
|
+
/** 启动子 node.js 进程(通常是长期在后台运行的,或者可交互的,需要能控制),执行某个 js 文件,
|
|
342
|
+
返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
|
|
343
|
+
- js: .js 路径 (相对路径根据 cwd 解析)
|
|
344
|
+
- args: `[]` 参数列表
|
|
345
|
+
- options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
|
|
346
|
+
- inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
|
|
347
|
+
- break?: 在第一行停止 */
|
|
348
|
+
export async function launch_nodejs(js, args, options) {
|
|
349
|
+
return launch(exe_nodejs, get_nodejs_args(js, args, options), options);
|
|
350
|
+
}
|
|
351
|
+
function get_nodejs_args(js, args = [], { inspect, break: _break } = {}) {
|
|
352
|
+
return [
|
|
291
353
|
'--enable-source-maps',
|
|
292
354
|
...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect === true ? 9229 : inspect}`] : [],
|
|
293
355
|
js,
|
|
294
356
|
...args
|
|
295
|
-
]
|
|
357
|
+
];
|
|
358
|
+
}
|
|
359
|
+
/** 可选的向子进程输入内容,并等待子进程输出特定的内容,类似一次无返回值,仅有完成状态的 rpc 调用
|
|
360
|
+
根据文本内容匹配其实不太好,实在是没有别的 rpc 方法再使用吧
|
|
361
|
+
- ps: 子进程
|
|
362
|
+
- pattern: 匹配内容,支持 string 和 RegExp
|
|
363
|
+
- input?: 要输入的内容
|
|
364
|
+
- timeout?: 等待超时时间 */
|
|
365
|
+
export async function wait_output(ps, pattern, input, _timeout) {
|
|
366
|
+
const { stdin, stdout } = ps;
|
|
367
|
+
const matcher = typeof pattern === 'string'
|
|
368
|
+
? (chunk) => chunk.includes(pattern)
|
|
369
|
+
: (chunk) => pattern.test(chunk);
|
|
370
|
+
let on_data;
|
|
371
|
+
let pfound = new Promise(resolve => {
|
|
372
|
+
on_data = (chunk) => {
|
|
373
|
+
if (matcher(chunk)) {
|
|
374
|
+
stdout.off('data', on_data);
|
|
375
|
+
resolve();
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
stdout.on('data', on_data);
|
|
379
|
+
if (input)
|
|
380
|
+
stdin.write(input);
|
|
381
|
+
});
|
|
382
|
+
if (_timeout)
|
|
383
|
+
try {
|
|
384
|
+
await timeout(_timeout, pfound);
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
stdout.off('data', on_data);
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
else
|
|
391
|
+
await pfound;
|
|
296
392
|
}
|
|
297
393
|
const short_exe_names = {
|
|
298
394
|
[exe_nodejs]: 'node',
|
package/server.d.ts
CHANGED
|
@@ -53,7 +53,6 @@ export declare class Server {
|
|
|
53
53
|
websocket_server?: WebSocketServer;
|
|
54
54
|
/** 设置后会启用 websocket rpc */
|
|
55
55
|
remote?: Remote;
|
|
56
|
-
colors: boolean;
|
|
57
56
|
/** 输出日志时包含日期 */
|
|
58
57
|
log_date: boolean;
|
|
59
58
|
/** 启用后增加 stdio 订阅相关的 remote.funcs */
|
|
@@ -65,6 +64,7 @@ export declare class Server {
|
|
|
65
64
|
/** 原始 process.stdout.write 函数 bind 后的备份 */
|
|
66
65
|
stdout_write: Function;
|
|
67
66
|
stderr_write: Function;
|
|
67
|
+
url_width: 52;
|
|
68
68
|
constructor({ name, print, http, http2, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, log_date }: {
|
|
69
69
|
name: string;
|
|
70
70
|
print?: boolean | {
|
package/server.js
CHANGED
|
@@ -4,7 +4,6 @@ import { createSecureContext } from 'tls';
|
|
|
4
4
|
import zlib from 'zlib';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { buffer as stream_to_buffer } from 'stream/consumers';
|
|
7
|
-
import util from 'util';
|
|
8
7
|
import node_sea from 'node:sea';
|
|
9
8
|
import { default as Koa } from 'koa';
|
|
10
9
|
import KoaCors from '@koa/cors';
|
|
@@ -15,7 +14,7 @@ import { contentType as get_content_type } from 'mime-types';
|
|
|
15
14
|
// --- my libs
|
|
16
15
|
import { t } from "./i18n/instance.js";
|
|
17
16
|
import { request as _request, Remote } from "./net.js";
|
|
18
|
-
import { inspect,
|
|
17
|
+
import { inspect, check, range_to_numbers, encode, filter_keys, filter_values, consume_stream } from "./utils.js";
|
|
19
18
|
import { flist, fread, fstat } from "./file.js";
|
|
20
19
|
import { exe_nodejs, sea } from "./process.js";
|
|
21
20
|
// ------------ my server
|
|
@@ -57,7 +56,6 @@ export class Server {
|
|
|
57
56
|
websocket_server;
|
|
58
57
|
/** 设置后会启用 websocket rpc */
|
|
59
58
|
remote;
|
|
60
|
-
colors = util.inspect.defaultOptions.colors;
|
|
61
59
|
/** 输出日志时包含日期 */
|
|
62
60
|
log_date = false;
|
|
63
61
|
/** 启用后增加 stdio 订阅相关的 remote.funcs */
|
|
@@ -66,6 +64,7 @@ export class Server {
|
|
|
66
64
|
/** 原始 process.stdout.write 函数 bind 后的备份 */
|
|
67
65
|
stdout_write;
|
|
68
66
|
stderr_write;
|
|
67
|
+
url_width = 52;
|
|
69
68
|
constructor({ name, print, http, http2, http_port, http2_port, fpd_certs, default_hostnames, remote, funcs, stdio_subscribable, log_date }) {
|
|
70
69
|
this.name = name;
|
|
71
70
|
if (print !== undefined) {
|
|
@@ -278,22 +277,23 @@ export class Server {
|
|
|
278
277
|
// url 只有路径部分
|
|
279
278
|
const { url, headers, headers: { host = '' }, } = request;
|
|
280
279
|
if (this.print.logs) {
|
|
281
|
-
|
|
282
|
-
console.log(
|
|
280
|
+
let s =
|
|
283
281
|
// 时间
|
|
284
282
|
`${this.log_date ? new Date().to_str() : new Date().to_time_str()} ` +
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
// ua
|
|
288
|
-
this.format_ua(headers).limit(56) + ' ' +
|
|
289
|
-
// https/2.0
|
|
290
|
-
`${this.colors ? 'websocket'.limit(10).magenta : 'websocket'.limit(10)} ` +
|
|
291
|
-
// method
|
|
292
|
-
''.limit(6) + ' ' +
|
|
283
|
+
// wss://
|
|
284
|
+
`${`ws${socket.encrypted ? 's' : ''}`.yellow}://` +
|
|
293
285
|
// host
|
|
294
|
-
|
|
286
|
+
host +
|
|
295
287
|
// path
|
|
296
|
-
|
|
288
|
+
url;
|
|
289
|
+
s = s.pad(this.url_width);
|
|
290
|
+
// ip
|
|
291
|
+
s += ` <- ${request.socket.remoteAddress.strip_if_start('::ffff:')}`;
|
|
292
|
+
// ua
|
|
293
|
+
const ua = this.format_ua(headers);
|
|
294
|
+
if (ua)
|
|
295
|
+
s += `/${ua}`;
|
|
296
|
+
console.log(s);
|
|
297
297
|
}
|
|
298
298
|
switch (url) {
|
|
299
299
|
case '/':
|
|
@@ -304,7 +304,7 @@ export class Server {
|
|
|
304
304
|
return;
|
|
305
305
|
default:
|
|
306
306
|
if (this.print.logs)
|
|
307
|
-
console.log(
|
|
307
|
+
console.log(`未知路径的 upgrade 请求: ${url}`.red);
|
|
308
308
|
socket.destroy();
|
|
309
309
|
}
|
|
310
310
|
}
|
|
@@ -381,7 +381,6 @@ export class Server {
|
|
|
381
381
|
return true;
|
|
382
382
|
}
|
|
383
383
|
logger(ctx) {
|
|
384
|
-
const { colors } = this;
|
|
385
384
|
const { request } = ctx;
|
|
386
385
|
const { query: queries, body, path, _path, protocol, host, req: { httpVersion: http_version }, ip, headers, } = request;
|
|
387
386
|
let { method } = request;
|
|
@@ -390,28 +389,22 @@ export class Server {
|
|
|
390
389
|
let s = '';
|
|
391
390
|
// 时间
|
|
392
391
|
s += `${this.log_date ? new Date().to_str() : new Date().to_time_str()} `;
|
|
393
|
-
// ip(位置)
|
|
394
|
-
s += (ip || '').limit(40) + ' ';
|
|
395
|
-
// ua
|
|
396
|
-
s += this.process_ua(ctx).limit(56) + ' ';
|
|
397
|
-
// https/2.0
|
|
398
|
-
s += `${`${protocol.limit(5)} ${http_version}`.limit(10)} `;
|
|
399
392
|
// method
|
|
400
393
|
method = method.toLowerCase();
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
s +=
|
|
394
|
+
if (method !== 'get')
|
|
395
|
+
s += `${method.yellow} `;
|
|
396
|
+
// http, https, http2, websocket
|
|
397
|
+
s += `${http_version === '2.0' ? 'https'.magenta : protocol}://`;
|
|
405
398
|
// host
|
|
406
|
-
s +=
|
|
399
|
+
s += host;
|
|
407
400
|
// path
|
|
408
|
-
s += (
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
401
|
+
s += path.toLowerCase() !== _path.toLowerCase()
|
|
402
|
+
? _path === '/'
|
|
403
|
+
? '/'.blue
|
|
404
|
+
: `${_path} -> ${path}`
|
|
405
|
+
: path.includes('.')
|
|
406
|
+
? path
|
|
407
|
+
: path.yellow;
|
|
415
408
|
// range
|
|
416
409
|
let range = headers.range;
|
|
417
410
|
if (headers.range) {
|
|
@@ -422,14 +415,21 @@ export class Server {
|
|
|
422
415
|
end = Number(end).to_fsize_str();
|
|
423
416
|
s += ` (${start} - ${end || ''})`;
|
|
424
417
|
}
|
|
418
|
+
s += ' ';
|
|
425
419
|
// queries
|
|
426
420
|
if (Object.keys(queries).length) {
|
|
427
|
-
|
|
421
|
+
s += inspect(queries, { compact: true })
|
|
428
422
|
.replace('[Object: null prototype] ', '')
|
|
429
423
|
.strip_if_end('\n');
|
|
430
|
-
s +=
|
|
431
|
-
s += t;
|
|
424
|
+
s += ' ';
|
|
432
425
|
}
|
|
426
|
+
s = s.pad(this.url_width);
|
|
427
|
+
// ip
|
|
428
|
+
s += ` <- ${ip.strip_if_start('::ffff:')}`;
|
|
429
|
+
// ua
|
|
430
|
+
const ua = this.process_ua(ctx);
|
|
431
|
+
if (ua)
|
|
432
|
+
s += `/${ua}`;
|
|
433
433
|
// body
|
|
434
434
|
if (body && Object.keys(body).length)
|
|
435
435
|
s += '\n' + inspect(body).replace('[Object: null prototype] ', '');
|
package/utils.browser.d.ts
CHANGED
|
@@ -25,10 +25,12 @@ export declare class TimeoutError extends Error {
|
|
|
25
25
|
name: "TimeoutError";
|
|
26
26
|
}
|
|
27
27
|
/** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
|
|
28
|
-
-
|
|
29
|
-
-
|
|
28
|
+
- action?: 要等待运行的任务, async function 或 promise
|
|
29
|
+
- on_timeout?: 超时后调用的函数
|
|
30
|
+
- 如果传入了 on_timeout 参数: 调用 on_timeout,然后 timeout 函数正常返回 null
|
|
31
|
+
- 如果没传入 on_timeout 参数: 抛出 TimeoutError
|
|
30
32
|
- print?: 打印已超时任务的错误 */
|
|
31
|
-
export declare function timeout<TReturn>(milliseconds: number, action: () => Promise<TReturn
|
|
33
|
+
export declare function timeout<TReturn>(milliseconds: number, action: Promise<TReturn> | (() => Promise<TReturn>), on_timeout?: () => void | Promise<void>, print?: boolean): Promise<TReturn>;
|
|
32
34
|
/** https://stackoverflow.com/questions/63297164/how-to-only-accept-arraybuffer-as-parameter */
|
|
33
35
|
export type StrictArrayBuffer = ArrayBuffer & {
|
|
34
36
|
buffer?: undefined;
|
|
@@ -79,7 +81,7 @@ export declare function encode(str: string): Uint8Array<ArrayBufferLike>;
|
|
|
79
81
|
在流式处理 (buffer 可能不完整) 时,应使用独立的 TextDecoder 实例调用 decode(buffer, { stream: true }) */
|
|
80
82
|
export declare function decode(buffer: Uint8Array): string;
|
|
81
83
|
/** 字符串字典序比较 */
|
|
82
|
-
export declare function strcmp(l: string, r: string):
|
|
84
|
+
export declare function strcmp(l: string, r: string): 0 | 1 | -1;
|
|
83
85
|
/** 比较 1.10.02 这种版本号
|
|
84
86
|
- l, r: 两个版本号字符串
|
|
85
87
|
- loose?: 宽松模式,允许两个版本号格式(位数)不一致 */
|
package/utils.browser.js
CHANGED
|
@@ -77,8 +77,10 @@ export class TimeoutError extends Error {
|
|
|
77
77
|
name = 'TimeoutError';
|
|
78
78
|
}
|
|
79
79
|
/** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
|
|
80
|
-
-
|
|
81
|
-
-
|
|
80
|
+
- action?: 要等待运行的任务, async function 或 promise
|
|
81
|
+
- on_timeout?: 超时后调用的函数
|
|
82
|
+
- 如果传入了 on_timeout 参数: 调用 on_timeout,然后 timeout 函数正常返回 null
|
|
83
|
+
- 如果没传入 on_timeout 参数: 抛出 TimeoutError
|
|
82
84
|
- print?: 打印已超时任务的错误 */
|
|
83
85
|
export async function timeout(milliseconds, action, on_timeout, print = true) {
|
|
84
86
|
const error = new TimeoutError();
|
|
@@ -108,7 +110,7 @@ export async function timeout(milliseconds, action, on_timeout, print = true) {
|
|
|
108
110
|
})();
|
|
109
111
|
(async () => {
|
|
110
112
|
try {
|
|
111
|
-
resolve(await action());
|
|
113
|
+
resolve(await (typeof action === 'function' ? action() : action));
|
|
112
114
|
}
|
|
113
115
|
catch (error) {
|
|
114
116
|
if (rejected) {
|
package/utils.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import util from 'util';
|
|
|
3
3
|
import type { TimerOptions } from 'timers';
|
|
4
4
|
import type Vinyl from 'vinyl';
|
|
5
5
|
import { type Mapper } from './prototype.ts';
|
|
6
|
-
/** `
|
|
7
|
-
export declare const output_width =
|
|
6
|
+
/** `180` 输出字符宽度 */
|
|
7
|
+
export declare const output_width = 180;
|
|
8
8
|
export declare function set_inspect_options(colors?: boolean): void;
|
|
9
9
|
export declare function assert<T>(assertion: T, message?: string): T;
|
|
10
10
|
/** 做参数校验,逻辑检查 */
|
|
@@ -40,7 +40,7 @@ export declare function filter_values<TObj extends Record<string, any>>(obj: TOb
|
|
|
40
40
|
/** 忽略对象中的 keys, 返回新对象 */
|
|
41
41
|
export declare function omit<TObj>(obj: TObj, omit_keys: string[]): TObj;
|
|
42
42
|
/** 字符串字典序比较 */
|
|
43
|
-
export declare function strcmp(l: string, r: string):
|
|
43
|
+
export declare function strcmp(l: string, r: string): 0 | 1 | -1;
|
|
44
44
|
/** 比较 1.10.02 这种版本号
|
|
45
45
|
- l, r: 两个版本号字符串
|
|
46
46
|
- loose?: 宽松模式,允许两个版本号格式(位数)不一致 */
|
|
@@ -91,10 +91,12 @@ export declare class TimeoutError extends Error {
|
|
|
91
91
|
name: "TimeoutError";
|
|
92
92
|
}
|
|
93
93
|
/** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
|
|
94
|
-
-
|
|
95
|
-
-
|
|
94
|
+
- action?: 要等待运行的任务, async function 或 promise
|
|
95
|
+
- on_timeout?: 超时后调用的函数
|
|
96
|
+
- 如果传入了 on_timeout 参数: 调用 on_timeout,然后 timeout 函数正常返回 null
|
|
97
|
+
- 如果没传入 on_timeout 参数: 抛出 TimeoutError
|
|
96
98
|
- print?: 打印已超时任务的错误 */
|
|
97
|
-
export declare function timeout<TReturn>(milliseconds: number, action: () => Promise<TReturn
|
|
99
|
+
export declare function timeout<TReturn>(milliseconds: number, action: Promise<TReturn> | (() => Promise<TReturn>), on_timeout?: () => void | Promise<void>, print?: boolean): Promise<TReturn>;
|
|
98
100
|
/** https://stackoverflow.com/questions/63297164/how-to-only-accept-arraybuffer-as-parameter */
|
|
99
101
|
export type StrictArrayBuffer = ArrayBuffer & {
|
|
100
102
|
buffer?: undefined;
|
package/utils.js
CHANGED
|
@@ -3,8 +3,8 @@ import util from 'util';
|
|
|
3
3
|
import timers from 'timers/promises';
|
|
4
4
|
import { t } from "./i18n/instance.js";
|
|
5
5
|
import { build_mapper, not_empty, is_key_type, noop, ident } from "./prototype.js";
|
|
6
|
-
/** `
|
|
7
|
-
export const output_width =
|
|
6
|
+
/** `180` 输出字符宽度 */
|
|
7
|
+
export const output_width = 180;
|
|
8
8
|
export function set_inspect_options(colors = true) {
|
|
9
9
|
util.inspect.defaultOptions.maxArrayLength = 40;
|
|
10
10
|
util.inspect.defaultOptions.maxStringLength = 10000;
|
|
@@ -281,8 +281,10 @@ export class TimeoutError extends Error {
|
|
|
281
281
|
name = 'TimeoutError';
|
|
282
282
|
}
|
|
283
283
|
/** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
|
|
284
|
-
-
|
|
285
|
-
-
|
|
284
|
+
- action?: 要等待运行的任务, async function 或 promise
|
|
285
|
+
- on_timeout?: 超时后调用的函数
|
|
286
|
+
- 如果传入了 on_timeout 参数: 调用 on_timeout,然后 timeout 函数正常返回 null
|
|
287
|
+
- 如果没传入 on_timeout 参数: 抛出 TimeoutError
|
|
286
288
|
- print?: 打印已超时任务的错误 */
|
|
287
289
|
export async function timeout(milliseconds, action, on_timeout, print = true) {
|
|
288
290
|
const error = new TimeoutError();
|
|
@@ -312,7 +314,7 @@ export async function timeout(milliseconds, action, on_timeout, print = true) {
|
|
|
312
314
|
})();
|
|
313
315
|
(async () => {
|
|
314
316
|
try {
|
|
315
|
-
resolve(await action());
|
|
317
|
+
resolve(await (typeof action === 'function' ? action() : action));
|
|
316
318
|
}
|
|
317
319
|
catch (error) {
|
|
318
320
|
if (rejected) {
|