xshell 1.1.14 → 1.1.16

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.
@@ -0,0 +1,6 @@
1
+ /** 监听终端按键 (输入),并调用 key_processor 处理
2
+ - on_key: 按键处理函数
3
+ - on_exit?: ctrl + c 会退出进程,可加入退出前自定义处理逻辑 */
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>;
package/development.js ADDED
@@ -0,0 +1,35 @@
1
+ import process from 'process';
2
+ import { fcopy, fexists, ramdisk } from "./file.js";
3
+ import { noprint } from "./process.js";
4
+ /** 监听终端按键 (输入),并调用 key_processor 处理
5
+ - on_key: 按键处理函数
6
+ - on_exit?: ctrl + c 会退出进程,可加入退出前自定义处理逻辑 */
7
+ export function process_stdin(on_key, on_exit) {
8
+ // https://stackoverflow.com/a/12506613/7609214
9
+ let { stdin } = process;
10
+ if (stdin.isTTY) {
11
+ stdin.setRawMode(true);
12
+ stdin.resume();
13
+ }
14
+ stdin.setEncoding('utf-8');
15
+ // on any data into stdin
16
+ stdin.on('data', async (key) => {
17
+ // ctrl-c ( end of text )
18
+ if (key === '\u0003') {
19
+ await on_exit?.();
20
+ process.exit();
21
+ }
22
+ // write the key to stdout all normal like
23
+ console.log(key);
24
+ await on_key(key);
25
+ });
26
+ }
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, async () => { await this.connect(); }, undefined, this.print);
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, async () => { await this.call('echo', []); }, undefined, this.print);
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
- async () => undici.request(url, options), undefined, print.timeout && count >= retries // 只打印最后一次超时的错误,避免太多冗余输出
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, async () => { await this.connect(); }, undefined, this.print);
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, async () => { await this.call('echo', []); }, undefined, this.print);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
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
- /** 启动独立的进程,不受当前 node.js 进程退出的影响
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<ChildProcess>;
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;
@@ -90,7 +110,7 @@ export interface CallOptions extends BaseOptions {
90
110
  stderr?: (chunk: string) => void;
91
111
  };
92
112
  /** 可以传入回调函数及时获取通过 start 创建的子进程,便于执行 kill、获得 pid 等操作 */
93
- on_child?: (child: ChildProcess) => void;
113
+ on_child?: (child: SubProcess) => void;
94
114
  }
95
115
  export interface CallResult<TOutput extends string | Buffer = string> {
96
116
  pid: number;
@@ -100,7 +120,7 @@ export interface CallResult<TOutput extends string | Buffer = string> {
100
120
  signal: NodeJS.Signals | null;
101
121
  command: string;
102
122
  message: string;
103
- child: ChildProcess;
123
+ child: SubProcess<TOutput>;
104
124
  print: FullPrintOptions;
105
125
  }
106
126
  export interface CallError<TOutput extends string | Buffer = string> extends Error {
@@ -110,7 +130,7 @@ export interface CallError<TOutput extends string | Buffer = string> extends Err
110
130
  code: number;
111
131
  signal: NodeJS.Signals;
112
132
  command: string;
113
- child: ChildProcess;
133
+ child: SubProcess<TOutput>;
114
134
  print: FullPrintOptions;
115
135
  }
116
136
  export declare class CallError<TOutput extends string | Buffer = string> extends Error {
@@ -118,7 +138,7 @@ export declare class CallError<TOutput extends string | Buffer = string> extends
118
138
  constructor({ message, pid, stdout, stderr, code, signal, command, child, print }: CallResult<TOutput>);
119
139
  [inspect.custom](depth: number, options: InspectOptions, inspect: Function): string;
120
140
  }
121
- /** 调用可执行文件,获取返回结果,错误时抛出 CallError
141
+ /** 调用 exe 启动子进程,等待并获取返回结果,错误时抛出 CallError
122
142
  - exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
123
143
  - args: `[ ]` 参数列表
124
144
  - options?:
@@ -135,14 +155,26 @@ export declare function call(exe: string, args: string[], options: CallOptions &
135
155
  encoding: 'binary';
136
156
  }): Promise<CallResult<Buffer>>;
137
157
  export declare function call(exe: string, args?: string[], options?: CallOptions): Promise<CallResult<string>>;
138
- export interface CallNodeJsOptions extends CallOptions {
158
+ /** 调用 exe 启动子进程(通常是长期在后台运行的,或者可交互的,需要能控制)
159
+ 返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
160
+ 其中有 presult 属性,是调用 call 的 Promise 结果
161
+ - exe: .exe 路径或文件名 (建议使用路径,跳过 path 搜索,性能更高)
162
+ - args: `[ ]` 参数列表
163
+ - options?: 见 {@link CallOptions} */
164
+ export declare function launch(exe: string, args: string[], options: CallOptions & {
165
+ encoding: 'binary';
166
+ }): Promise<SubProcess<Buffer>>;
167
+ export declare function launch(exe: string, args?: string[], options?: CallOptions): Promise<SubProcess<string>>;
168
+ export interface NodeJsOptions {
139
169
  inspect?: number | true;
140
170
  break?: boolean;
141
171
  }
172
+ export interface CallNodeJsOptions extends CallOptions, NodeJsOptions {
173
+ }
142
174
  /** 调用 node <js> 并等待结果
143
175
  - js: .js 路径 (相对路径根据 cwd 解析)
144
176
  - args?: `[ ]` 参数列表
145
- - options?:
177
+ - options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
146
178
  - cwd?: `'T:/'`
147
179
  - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
148
180
  - encoding?: `'utf-8'` 子进程输出编码
@@ -151,19 +183,29 @@ export interface CallNodeJsOptions extends CallOptions {
151
183
  - throw_code?: `true` code 不为 0 时是否抛出异常
152
184
  - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
153
185
  - break?: break at first line */
154
- export declare function call_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: CallNodeJsOptions): Promise<CallResult<string>>;
155
- export interface StartNodeJsOptions extends StartOptions {
156
- inspect?: number | true;
157
- break?: boolean;
186
+ export declare function call_nodejs(js: string, args?: string[], options?: CallNodeJsOptions): Promise<CallResult<string>>;
187
+ export interface StartNodeJsOptions extends StartOptions, NodeJsOptions {
158
188
  }
159
- /** 启动 node <js>
189
+ /** 启动独立的 node.js 进程 (detached),执行某个 js 文件
160
190
  - js: .js 路径 (相对路径根据 cwd 解析)
161
191
  - args: `[]` 参数列表
162
- - options
163
- - cwd?: `'T:/'`
164
- - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
165
- - print?: `true` print 选项,支持设置细项
192
+ - options?: {@link StartNodeJsOptions} 继承自 {@link StartOptions} 和 {@link NodeJsOptions}
166
193
  - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
167
- - break?: break at first line */
168
- export declare function start_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: StartNodeJsOptions): Promise<ChildProcess>;
194
+ - break?: 在第一行停止 */
195
+ export declare function start_nodejs(js: string, args?: string[], options?: StartNodeJsOptions): Promise<SubProcess<string>>;
196
+ /** 启动子 node.js 进程(通常是长期在后台运行的,或者可交互的,需要能控制),执行某个 js 文件,
197
+ 返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
198
+ - js: .js 路径 (相对路径根据 cwd 解析)
199
+ - args: `[]` 参数列表
200
+ - options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
201
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
202
+ - break?: 在第一行停止 */
203
+ export declare function launch_nodejs(js: string, args?: string[], options?: CallNodeJsOptions): Promise<SubProcess<string>>;
204
+ /** 可选的向子进程输入内容,并等待子进程输出特定的内容,类似一次无返回值,仅有完成状态的 rpc 调用
205
+ 根据文本内容匹配其实不太好,实在是没有别的 rpc 方法再使用吧
206
+ - ps: 子进程
207
+ - pattern: 匹配内容,支持 string 和 RegExp
208
+ - input?: 要输入的内容
209
+ - timeout?: 等待超时时间 */
210
+ export declare function wait_output(ps: SubProcess, pattern: string | RegExp, input?: string, _timeout?: number): Promise<void>;
169
211
  export {};
package/process.js CHANGED
@@ -2,13 +2,19 @@ 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
20
  input, fp_stdin, fp_stdout, fp_stderr, print = true, proxy,
@@ -78,13 +84,7 @@ stdio }) {
78
84
  stdout: print,
79
85
  stderr: print
80
86
  };
81
- const command = (short_exe_names[exe] || exe.quote_if_space()) +
82
- (args.length
83
- ? ' ' +
84
- args
85
- .map(arg => arg.quote_if_space())
86
- .join(' ')
87
- : '');
87
+ const command = get_command(exe, args);
88
88
  if (print.command)
89
89
  console.log(command.blue);
90
90
  return {
@@ -102,7 +102,28 @@ stdio }) {
102
102
  close_all_handles: opened_handles.length ? close_all_handles : undefined
103
103
  };
104
104
  }
105
- /** 启动独立的进程,不受当前 node.js 进程退出的影响
105
+ function to_subprocess(child, { title, exe, args, command, }) {
106
+ if (title)
107
+ child.title = title;
108
+ child.exe = exe;
109
+ child.args = args || [];
110
+ child.command = command;
111
+ Object.defineProperties(child, {
112
+ finished: {
113
+ get() {
114
+ return this.exitCode !== null;
115
+ }
116
+ },
117
+ running: {
118
+ get() {
119
+ return this.exitCode === null;
120
+ }
121
+ }
122
+ });
123
+ return child;
124
+ }
125
+ /** 启动独立 (detached) 的进程,不受当前 node.js 进程退出的影响,重定向 stdio 到文件或直接忽略
126
+ 使用 windowsHide 选项避免创建命令行窗口
106
127
  - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高)
107
128
  - args?: `[ ]` 参数列表
108
129
  - options?:
@@ -115,9 +136,9 @@ stdio }) {
115
136
  - fp_stdout?: 使用文件作为标准输出,设置 stdio 中对应的值
116
137
  - fp_stderr?: 使用文件作为标准错误,设置 stdio 中对应的值 */
117
138
  export async function start(exe, args = [], options = {}) {
118
- const { spawn_options, close_all_handles } = await prepare_spawn(true, exe, args, options);
139
+ const { spawn_options, close_all_handles, command } = await prepare_spawn(true, exe, args, options);
119
140
  try {
120
- let child = spawn(exe, args, spawn_options);
141
+ let child = to_subprocess(spawn(exe, args, spawn_options), { exe, command, args, title: options.title });
121
142
  child.unref();
122
143
  return child;
123
144
  }
@@ -157,7 +178,7 @@ export async function call(exe, args = [], options = {}) {
157
178
  const { print, spawn_options, close_all_handles, command } = await prepare_spawn(false, exe, args, options);
158
179
  let child;
159
180
  try {
160
- child = spawn(exe, args, spawn_options);
181
+ child = to_subprocess(spawn(exe, args, spawn_options), { exe, args, command, title: options.title });
161
182
  }
162
183
  finally {
163
184
  if (close_all_handles)
@@ -253,14 +274,30 @@ export async function call(exe, args = [], options = {}) {
253
274
  });
254
275
  }
255
276
  };
256
- if (throw_code && (code || signal))
277
+ if (throw_code && signal)
257
278
  throw new CallError(result);
258
279
  return result;
259
280
  }
281
+ export async function launch(exe, args, options) {
282
+ let presult;
283
+ let ps = await new Promise((resolve, reject) => {
284
+ try {
285
+ presult = call(exe, args, {
286
+ on_child: resolve,
287
+ ...options,
288
+ });
289
+ }
290
+ catch (error) {
291
+ reject(error);
292
+ }
293
+ });
294
+ ps.presult = presult;
295
+ return ps;
296
+ }
260
297
  /** 调用 node <js> 并等待结果
261
298
  - js: .js 路径 (相对路径根据 cwd 解析)
262
299
  - args?: `[ ]` 参数列表
263
- - options?:
300
+ - options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
264
301
  - cwd?: `'T:/'`
265
302
  - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
266
303
  - encoding?: `'utf-8'` 子进程输出编码
@@ -269,30 +306,69 @@ export async function call(exe, args = [], options = {}) {
269
306
  - throw_code?: `true` code 不为 0 时是否抛出异常
270
307
  - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
271
308
  - break?: break at first line */
272
- export async function call_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
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);
309
+ export async function call_nodejs(js, args, options) {
310
+ return call(exe_nodejs, get_nodejs_args(js, args, options), options);
279
311
  }
280
- /** 启动 node <js>
312
+ /** 启动独立的 node.js 进程 (detached),执行某个 js 文件
281
313
  - js: .js 路径 (相对路径根据 cwd 解析)
282
314
  - args: `[]` 参数列表
283
- - options
284
- - cwd?: `'T:/'`
285
- - envs?: `process.env` 覆盖/添加到 process.env 的环境变量
286
- - print?: `true` print 选项,支持设置细项
315
+ - options?: {@link StartNodeJsOptions} 继承自 {@link StartOptions} 和 {@link NodeJsOptions}
287
316
  - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
288
- - break?: break at first line */
289
- export async function start_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
290
- return start(exe_nodejs, [
317
+ - break?: 在第一行停止 */
318
+ export async function start_nodejs(js, args, options) {
319
+ return start(exe_nodejs, get_nodejs_args(js, args, options), options);
320
+ }
321
+ /** 启动子 node.js 进程(通常是长期在后台运行的,或者可交互的,需要能控制),执行某个 js 文件,
322
+ 返回 {@link SubProcess} 对象 (继承自 ChildProcess),可以做 .kill() 等操作
323
+ - js: .js 路径 (相对路径根据 cwd 解析)
324
+ - args: `[]` 参数列表
325
+ - options?: {@link CallNodeJsOptions} 继承自 {@link CallOptions} 和 {@link NodeJsOptions}
326
+ - inspect?: nodejs debugger port, 填 9229 端口 (或者传 true) 可以用临时配置来调试
327
+ - break?: 在第一行停止 */
328
+ export async function launch_nodejs(js, args, options) {
329
+ return launch(exe_nodejs, get_nodejs_args(js, args, options), options);
330
+ }
331
+ function get_nodejs_args(js, args = [], { inspect, break: _break } = {}) {
332
+ return [
291
333
  '--enable-source-maps',
292
334
  ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect === true ? 9229 : inspect}`] : [],
293
335
  js,
294
336
  ...args
295
- ], options);
337
+ ];
338
+ }
339
+ /** 可选的向子进程输入内容,并等待子进程输出特定的内容,类似一次无返回值,仅有完成状态的 rpc 调用
340
+ 根据文本内容匹配其实不太好,实在是没有别的 rpc 方法再使用吧
341
+ - ps: 子进程
342
+ - pattern: 匹配内容,支持 string 和 RegExp
343
+ - input?: 要输入的内容
344
+ - timeout?: 等待超时时间 */
345
+ export async function wait_output(ps, pattern, input, _timeout) {
346
+ const { stdin, stdout } = ps;
347
+ const matcher = typeof pattern === 'string'
348
+ ? (chunk) => chunk.includes(pattern)
349
+ : (chunk) => pattern.test(chunk);
350
+ let on_data;
351
+ let pfound = new Promise(resolve => {
352
+ on_data = (chunk) => {
353
+ if (matcher(chunk)) {
354
+ stdout.off('data', on_data);
355
+ resolve();
356
+ }
357
+ };
358
+ stdout.on('data', on_data);
359
+ if (input)
360
+ stdin.write(input);
361
+ });
362
+ if (_timeout)
363
+ try {
364
+ await timeout(_timeout, pfound);
365
+ }
366
+ catch (error) {
367
+ stdout.off('data', on_data);
368
+ throw error;
369
+ }
370
+ else
371
+ await pfound;
296
372
  }
297
373
  const short_exe_names = {
298
374
  [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, output_width, check, range_to_numbers, encode, filter_keys, filter_values, consume_stream } from "./utils.js";
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
- const ip = request.socket.remoteAddress.replace(/^::ffff:/, '');
282
- console.log(
280
+ let s =
283
281
  // 时间
284
282
  `${this.log_date ? new Date().to_str() : new Date().to_time_str()} ` +
285
- // ip(位置)
286
- (ip || '').limit(40) + ' ' +
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
- `${host.limit(24)} ` +
286
+ host +
295
287
  // path
296
- (this.colors ? url.yellow : url));
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(`${' '.repeat(13)} connect 404: ${url}`.red);
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
- let t = method.limit(6) + ' ';
402
- if (colors && method !== 'get')
403
- method = t.yellow;
404
- s += t;
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 += `${host.limit(24)} `;
399
+ s += host;
407
400
  // path
408
- s += (() => {
409
- if (path.toLowerCase() !== _path.toLowerCase())
410
- return `${_path.blue} -> ${path}`;
411
- if (!path.includes('.'))
412
- return colors ? path.yellow : path;
413
- return path;
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
- let t = inspect(queries, { compact: true })
421
+ s += inspect(queries, { compact: true })
428
422
  .replace('[Object: null prototype] ', '')
429
423
  .strip_if_end('\n');
430
- s += (s + t).width > output_width ? '\n' : ' ';
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/stdin.js CHANGED
@@ -5,8 +5,10 @@ import process from 'process';
5
5
  export function process_stdin(on_key, on_exit) {
6
6
  // https://stackoverflow.com/a/12506613/7609214
7
7
  let { stdin } = process;
8
- stdin.setRawMode(true);
9
- stdin.resume();
8
+ if (stdin.isTTY) {
9
+ stdin.setRawMode(true);
10
+ stdin.resume();
11
+ }
10
12
  stdin.setEncoding('utf-8');
11
13
  // on any data into stdin
12
14
  stdin.on('data', async (key) => {
@@ -25,10 +25,12 @@ export declare class TimeoutError extends Error {
25
25
  name: "TimeoutError";
26
26
  }
27
27
  /** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
28
- - 如果传入了 on_timeout 参数: 调用 on_timeout,返回 null
29
- - 如果没传入 on_timeout 参数: 抛出 TimeoutError
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>, on_timeout?: () => void | Promise<void>, print?: boolean): 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;
package/utils.browser.js CHANGED
@@ -77,8 +77,10 @@ export class TimeoutError extends Error {
77
77
  name = 'TimeoutError';
78
78
  }
79
79
  /** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
80
- - 如果传入了 on_timeout 参数: 调用 on_timeout,返回 null
81
- - 如果没传入 on_timeout 参数: 抛出 TimeoutError
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
- /** `230` term 字符宽度 (实际上有 240) */
7
- export declare const output_width = 230;
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
  /** 做参数校验,逻辑检查 */
@@ -91,10 +91,12 @@ export declare class TimeoutError extends Error {
91
91
  name: "TimeoutError";
92
92
  }
93
93
  /** 在指定的时间 (milliseconds) 内运行某个任务,超时之后
94
- - 如果传入了 on_timeout 参数: 调用 on_timeout,返回 null
95
- - 如果没传入 on_timeout 参数: 抛出 TimeoutError
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>, on_timeout?: () => void | Promise<void>, print?: boolean): 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
- /** `230` term 字符宽度 (实际上有 240) */
7
- export const output_width = 230;
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
- - 如果传入了 on_timeout 参数: 调用 on_timeout,返回 null
285
- - 如果没传入 on_timeout 参数: 抛出 TimeoutError
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) {