xshell 0.0.58 → 0.0.60
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/net.browser.d.ts +45 -40
- package/net.browser.js +124 -123
- package/net.browser.js.map +1 -1
- package/net.d.ts +45 -40
- package/net.js +124 -123
- package/net.js.map +1 -1
- package/package.json +22 -23
- package/process.d.ts +6 -0
- package/process.js.map +1 -1
- package/prototype.browser.d.ts +8 -8
- package/prototype.browser.js.map +1 -1
- package/prototype.d.ts +20 -16
- package/prototype.js +17 -12
- package/prototype.js.map +1 -1
- package/repl.d.ts +1 -1
- package/repl.js +12 -10
- package/repl.js.map +1 -1
- package/server.js.map +1 -1
- package/utils.browser.d.ts +14 -2
- package/utils.browser.js +41 -7
- package/utils.browser.js.map +1 -1
- package/utils.d.ts +15 -3
- package/utils.js +32 -3
- package/utils.js.map +1 -1
package/net.d.ts
CHANGED
|
@@ -101,70 +101,75 @@ on_open, on_close, on_error, on_message }: {
|
|
|
101
101
|
data: ArrayBuffer | string;
|
|
102
102
|
}, websocket: WebSocket): any;
|
|
103
103
|
}): Promise<WebSocket>;
|
|
104
|
+
/** 接收到消息后的处理函数
|
|
105
|
+
返回值可以是:
|
|
106
|
+
- 数组: 会自动被封装为 { id: 相同, data: 返回值, done: true } 这样的消息并调用 websocket.send 将其发送
|
|
107
|
+
- void: 什么都不做
|
|
108
|
+
- 以上的 promise */
|
|
109
|
+
export declare type MessageHandler = (message: Message, websocket?: WebSocket) => void | any[] | Promise<void | any[]>;
|
|
104
110
|
/** 二进制消息格式
|
|
105
111
|
- json.length (小端序): 4 字节
|
|
106
112
|
- json 数据
|
|
107
113
|
- binary 数据
|
|
108
114
|
*/
|
|
109
|
-
export interface Message<
|
|
110
|
-
/**
|
|
115
|
+
export interface Message<TData extends any[] = any[]> {
|
|
116
|
+
/** rpc id: 在 rpc 系统中认为是唯一的。用来在单个 websocket 连接上复用多个 rpc 请求。多个相同 id 的 message 组成一个请求流 */
|
|
111
117
|
id?: number;
|
|
112
|
-
/** rpc
|
|
118
|
+
/** 只在 rpc 发起时指定被调用的 function name,发起时 rpc 时必传 */
|
|
113
119
|
func?: string;
|
|
114
|
-
/**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
|
|
120
|
+
/** 通过这个 flag 主动表明这是发往对方的最后一个 message, 对方可以销毁 handler 了
|
|
121
|
+
并非强制,可以不说明,由双方的函数自己约定
|
|
122
|
+
*/
|
|
123
|
+
done?: boolean;
|
|
124
|
+
/** 通知对方这里产生的错误,本质上类似 data 也是一种数据,并不代表 rpc 的结束,后续可能继续有 rpc message 交换 */
|
|
125
|
+
error?: Error;
|
|
126
|
+
/** data 是一个数组, 作为:
|
|
120
127
|
- rpc 发起方调用 func 的参数,或者请求流 message 携带的数据
|
|
121
|
-
-
|
|
128
|
+
- 结果或者响应流的数据,传给请求发起方
|
|
129
|
+
|
|
130
|
+
里面是可序列化为 json 的 js 变量,或者是 Uint8Array
|
|
131
|
+
Uint8Array 的参数处理后被替换为 Uint8Array.byteLength, 并将下标记录在 bins 中
|
|
132
|
+
|
|
133
|
+
注意: 数组中如果有 undefined 值,传输到对面会变成 null 值
|
|
122
134
|
*/
|
|
123
|
-
|
|
124
|
-
/** bins:
|
|
135
|
+
data?: TData;
|
|
136
|
+
/** bins: data 中哪些下标对应的原始值是 Uint8Array 类型的,如: [0, 3] */
|
|
125
137
|
bins?: number[];
|
|
126
|
-
/** 被调方执行 func 产生的错误 */
|
|
127
|
-
error?: Error;
|
|
128
|
-
/** 如果请求或者响应是一个流,通过这个 flag 表明是最后一个 message, 并且可以销毁 handler 了 */
|
|
129
|
-
done?: boolean;
|
|
130
138
|
}
|
|
131
|
-
/** 通过创建
|
|
139
|
+
/** 通过创建 remote 对象对 websocket rpc 进行抽象
|
|
132
140
|
调用方使用 remote.call 进行调用
|
|
133
|
-
被调方在创建
|
|
134
|
-
*/
|
|
141
|
+
被调方在创建 remote 对象时传入 funcs 注册处理函数,并使用 remote.handle 方法处理 websocket message
|
|
142
|
+
未连接时自动连接,断开后自动重连 */
|
|
135
143
|
export declare class Remote {
|
|
136
144
|
url: string;
|
|
137
|
-
websocket
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
funcs: Record<string,
|
|
141
|
-
/**
|
|
142
|
-
handlers:
|
|
145
|
+
/** 主动发起 websocket 连接的客户端 (构造函数传 url) 有这个属性 */
|
|
146
|
+
websocket?: WebSocket;
|
|
147
|
+
/** 通过 rpc message.func 被调用的 rpc 函数 */
|
|
148
|
+
funcs: Record<string, MessageHandler>;
|
|
149
|
+
/** map<id, message handler>: 通过 rpc message.id 找到对应的 handler, unary rpc 接收方不需要设置 handlers, 发送方需要 */
|
|
150
|
+
handlers: Map<number, MessageHandler>;
|
|
143
151
|
print: boolean;
|
|
144
|
-
/** 在未连接时或连接断开后,调用 call 是否自动连接到 remote */
|
|
145
|
-
autoconnect: boolean;
|
|
146
152
|
pconnect: Promise<any>;
|
|
147
153
|
get connected(): boolean;
|
|
148
|
-
static parse<
|
|
149
|
-
static pack({ id, func,
|
|
150
|
-
constructor({ url, funcs, websocket
|
|
154
|
+
static parse<TData extends any[] = any[]>(array_buffer: ArrayBuffer): Message<TData>;
|
|
155
|
+
static pack({ id, func, data, done, error }: Message): Uint8Array;
|
|
156
|
+
constructor({ url, funcs, websocket }?: {
|
|
151
157
|
url?: string;
|
|
152
158
|
funcs?: Remote['funcs'];
|
|
153
159
|
websocket?: WebSocket;
|
|
154
|
-
autoconnect?: boolean;
|
|
155
160
|
});
|
|
161
|
+
/** 幂等,保证 websocket 已连接,否则抛出异常,不需要手动调用,在其它方法中已默认自动重连 */
|
|
156
162
|
connect(): Promise<void>;
|
|
157
163
|
disconnect(): void;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
1. 被调用方接收 message 并开始处理
|
|
165
|
-
2. 调用方处理 message 响应
|
|
166
|
-
*/
|
|
164
|
+
/** 接收 websocket 连接的 remote 端必传 websocket 参数;发起端选传,如果传了必须等于 this.websocket
|
|
165
|
+
发送或连接出错时自动清理 message.id 对应的 handler */
|
|
166
|
+
send(message: Message, websocket?: WebSocket): Promise<void>;
|
|
167
|
+
/** 处理接收到的 websocket message 并解析, 根据 id dispatch 到对应的 handler 进行处理
|
|
168
|
+
如果 message.done == true 则清理 handler
|
|
169
|
+
如果 handler 返回了值,则包装为 message 发送 */
|
|
167
170
|
handle(event: {
|
|
168
171
|
data: ArrayBuffer;
|
|
169
172
|
}, websocket: WebSocket): Promise<void>;
|
|
173
|
+
/** 调用 remote 中的 func, 只适用于最简单的一元 rpc (请求, 响应) */
|
|
174
|
+
call<TReturn extends any[] = any[]>(func: string, args?: any[]): Promise<TReturn>;
|
|
170
175
|
}
|
package/net.js
CHANGED
|
@@ -6,7 +6,7 @@ import iconv from 'iconv-lite';
|
|
|
6
6
|
import qs from 'qs';
|
|
7
7
|
import { Cookie, MemoryCookieStore } from 'tough-cookie';
|
|
8
8
|
import './prototype.js';
|
|
9
|
-
import { inspect, output_width, concat } from './utils.js';
|
|
9
|
+
import { inspect, output_width, concat, assert, genid } from './utils.js';
|
|
10
10
|
export var MyProxy;
|
|
11
11
|
(function (MyProxy) {
|
|
12
12
|
MyProxy["socks5"] = "http://localhost:10080";
|
|
@@ -263,16 +263,22 @@ on_open, on_close, on_error, on_message }) {
|
|
|
263
263
|
websocket.binaryType = 'arraybuffer';
|
|
264
264
|
return new Promise((resolve, reject) => {
|
|
265
265
|
websocket.addEventListener('open', async (event) => {
|
|
266
|
-
console.log(
|
|
266
|
+
console.log(new Date().toLocaleTimeString() + ': ' +
|
|
267
|
+
'websocket connected: ' +
|
|
268
|
+
(protocols ?
|
|
269
|
+
typeof protocols === 'string' ? `protocol: ${protocols}, url: ` : `protocol: [${protocols.join(', ')}], url: `
|
|
270
|
+
:
|
|
271
|
+
'') +
|
|
272
|
+
websocket.url);
|
|
267
273
|
await on_open?.(event, websocket);
|
|
268
274
|
resolve(websocket);
|
|
269
275
|
});
|
|
270
276
|
websocket.addEventListener('close', event => {
|
|
271
|
-
console.log(`${
|
|
277
|
+
console.log(`${new Date().toLocaleTimeString()}: websocket closed: url: ${websocket.url}, code: ${event.code}, reason: ${event.reason}`);
|
|
272
278
|
on_close?.(event, websocket);
|
|
273
279
|
});
|
|
274
280
|
websocket.addEventListener('error', event => {
|
|
275
|
-
const message = `${websocket.url}
|
|
281
|
+
const message = `${new Date().toLocaleTimeString()} websocket errored: ${websocket.url}`;
|
|
276
282
|
on_error?.(event, websocket);
|
|
277
283
|
reject(Object.assign(new Error(message), { event }));
|
|
278
284
|
});
|
|
@@ -281,21 +287,19 @@ on_open, on_close, on_error, on_message }) {
|
|
|
281
287
|
});
|
|
282
288
|
});
|
|
283
289
|
}
|
|
284
|
-
/** 通过创建
|
|
290
|
+
/** 通过创建 remote 对象对 websocket rpc 进行抽象
|
|
285
291
|
调用方使用 remote.call 进行调用
|
|
286
|
-
被调方在创建
|
|
287
|
-
*/
|
|
292
|
+
被调方在创建 remote 对象时传入 funcs 注册处理函数,并使用 remote.handle 方法处理 websocket message
|
|
293
|
+
未连接时自动连接,断开后自动重连 */
|
|
288
294
|
export class Remote {
|
|
289
295
|
url;
|
|
296
|
+
/** 主动发起 websocket 连接的客户端 (构造函数传 url) 有这个属性 */
|
|
290
297
|
websocket;
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
handlers = [];
|
|
298
|
+
/** 通过 rpc message.func 被调用的 rpc 函数 */
|
|
299
|
+
funcs;
|
|
300
|
+
/** map<id, message handler>: 通过 rpc message.id 找到对应的 handler, unary rpc 接收方不需要设置 handlers, 发送方需要 */
|
|
301
|
+
handlers = new Map();
|
|
296
302
|
print = false;
|
|
297
|
-
/** 在未连接时或连接断开后,调用 call 是否自动连接到 remote */
|
|
298
|
-
autoconnect = true;
|
|
299
303
|
pconnect;
|
|
300
304
|
get connected() {
|
|
301
305
|
return this.websocket?.readyState === WebSocket.OPEN;
|
|
@@ -308,154 +312,151 @@ export class Remote {
|
|
|
308
312
|
let message = JSON.parse(decoder.decode(buf.subarray(4, offset)));
|
|
309
313
|
if (message.bins) {
|
|
310
314
|
const { bins } = message;
|
|
311
|
-
let {
|
|
315
|
+
let { data } = message;
|
|
312
316
|
for (const ibin of bins) {
|
|
313
|
-
const len_buf =
|
|
314
|
-
|
|
317
|
+
const len_buf = data[ibin];
|
|
318
|
+
data[ibin] = buf.subarray(offset, offset + len_buf);
|
|
315
319
|
offset += len_buf;
|
|
316
320
|
}
|
|
317
321
|
}
|
|
322
|
+
if (message.error)
|
|
323
|
+
message.error = Object.assign(new Error(), message.error);
|
|
318
324
|
return message;
|
|
319
325
|
}
|
|
320
|
-
static pack({ id, func,
|
|
321
|
-
let
|
|
326
|
+
static pack({ id, func, data = [], done, error }) {
|
|
327
|
+
let data_ = new Array(data.length);
|
|
322
328
|
let bins = [];
|
|
323
329
|
let bufs = [];
|
|
324
|
-
for (let i = 0; i <
|
|
325
|
-
const
|
|
326
|
-
if (
|
|
330
|
+
for (let i = 0; i < data.length; i++) {
|
|
331
|
+
const item = data[i];
|
|
332
|
+
if (item instanceof Uint8Array) {
|
|
327
333
|
bins.push(i);
|
|
328
|
-
bufs.push(
|
|
329
|
-
|
|
334
|
+
bufs.push(item);
|
|
335
|
+
data_[i] = item.length;
|
|
330
336
|
}
|
|
337
|
+
else
|
|
338
|
+
data_[i] = item;
|
|
331
339
|
}
|
|
332
340
|
const data_json = {
|
|
333
341
|
id,
|
|
334
342
|
...func ? { func } : {},
|
|
335
|
-
...ignore ? { ignore } : {},
|
|
336
|
-
..._async ? { async: _async } : {},
|
|
337
343
|
...done ? { done } : {},
|
|
338
344
|
...error ? { error } : {},
|
|
339
|
-
...
|
|
345
|
+
...data_.length ? { data: data_ } : {},
|
|
340
346
|
...bins.length ? { bins } : {},
|
|
341
347
|
};
|
|
342
348
|
const str_json = encoder.encode(JSON.stringify(data_json));
|
|
343
349
|
let dv = new DataView(new ArrayBuffer(4));
|
|
344
350
|
dv.setUint32(0, str_json.length, true);
|
|
345
|
-
return concat([
|
|
346
|
-
dv,
|
|
347
|
-
str_json,
|
|
348
|
-
...bufs
|
|
349
|
-
]);
|
|
351
|
+
return concat([dv, str_json, ...bufs]);
|
|
350
352
|
}
|
|
351
|
-
constructor({ url, funcs, websocket
|
|
353
|
+
constructor({ url, funcs = {}, websocket } = {}) {
|
|
352
354
|
this.url = url;
|
|
353
|
-
|
|
354
|
-
this.funcs = funcs;
|
|
355
|
+
this.funcs = funcs;
|
|
355
356
|
this.websocket = websocket;
|
|
356
|
-
if (typeof autoconnect !== 'undefined')
|
|
357
|
-
this.autoconnect = autoconnect;
|
|
358
357
|
}
|
|
358
|
+
/** 幂等,保证 websocket 已连接,否则抛出异常,不需要手动调用,在其它方法中已默认自动重连 */
|
|
359
359
|
async connect() {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
360
|
+
if (this.connected)
|
|
361
|
+
return;
|
|
362
|
+
const ptail = this.pconnect;
|
|
363
|
+
let resolve;
|
|
364
|
+
this.pconnect = new Promise((_resolve, _reject) => {
|
|
365
|
+
resolve = _resolve;
|
|
366
366
|
});
|
|
367
|
+
await ptail;
|
|
368
|
+
try {
|
|
369
|
+
if (!this.connected)
|
|
370
|
+
// 保存的 rpc 状态在 this.handlers, 与 websocket 无关,因此即使断开重连也不影响 rpc 的运行,即
|
|
371
|
+
// 底层连接断开后自动重连对上层应该是无感知的,除非再次连接时失败
|
|
372
|
+
this.websocket = await connect_websocket(this.url, { on_message: this.handle.bind(this) });
|
|
373
|
+
}
|
|
374
|
+
finally {
|
|
375
|
+
resolve();
|
|
376
|
+
}
|
|
367
377
|
}
|
|
368
378
|
disconnect() {
|
|
369
379
|
this.websocket?.close();
|
|
370
|
-
this.id = 0;
|
|
371
|
-
this.handlers = [];
|
|
372
|
-
}
|
|
373
|
-
send(message, websocket = this.websocket) {
|
|
374
|
-
if (websocket?.readyState !== WebSocket.OPEN)
|
|
375
|
-
throw new Error(`${websocket?.url || 'websocket'} 已断开,无法调用 remote.send`);
|
|
376
|
-
if (!('id' in message))
|
|
377
|
-
message.id = this.id;
|
|
378
|
-
websocket.send(Remote.pack(message));
|
|
379
380
|
}
|
|
380
|
-
/**
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
let resolve;
|
|
389
|
-
this.pconnect = new Promise((_resolve, _reject) => {
|
|
390
|
-
resolve = _resolve;
|
|
391
|
-
});
|
|
392
|
-
try {
|
|
393
|
-
await ptail;
|
|
394
|
-
}
|
|
395
|
-
catch { }
|
|
396
|
-
// 临界区结束,只有一个 call 调用运行到这里,可以开始连接 WebSocket
|
|
397
|
-
if (!this.connected) {
|
|
398
|
-
if (this.websocket)
|
|
399
|
-
console.log(`${this.url} 已断开,尝试自动重连`);
|
|
400
|
-
else
|
|
401
|
-
console.log(`${this.url} 未连接,尝试自动连接`);
|
|
402
|
-
try {
|
|
403
|
-
await this.connect();
|
|
404
|
-
}
|
|
405
|
-
finally {
|
|
406
|
-
resolve();
|
|
407
|
-
}
|
|
408
|
-
}
|
|
381
|
+
/** 接收 websocket 连接的 remote 端必传 websocket 参数;发起端选传,如果传了必须等于 this.websocket
|
|
382
|
+
发送或连接出错时自动清理 message.id 对应的 handler */
|
|
383
|
+
async send(message, websocket) {
|
|
384
|
+
try {
|
|
385
|
+
if (this.url) {
|
|
386
|
+
assert(!websocket || websocket === this.websocket);
|
|
387
|
+
await this.connect();
|
|
388
|
+
websocket = this.websocket;
|
|
409
389
|
}
|
|
410
|
-
else
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
};
|
|
426
|
-
this.send(message);
|
|
427
|
-
this.id++;
|
|
428
|
-
});
|
|
390
|
+
else {
|
|
391
|
+
assert(websocket);
|
|
392
|
+
assert(!websocket.url, `The websocket received by the server should have no url attribute, websocket.url: ${websocket.url}`);
|
|
393
|
+
if (websocket.readyState !== WebSocket.OPEN)
|
|
394
|
+
throw new Error(`remote.send(): websocket client disconnected`);
|
|
395
|
+
}
|
|
396
|
+
if (!message.id)
|
|
397
|
+
message.id = genid();
|
|
398
|
+
websocket.send(Remote.pack(message));
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
if (message.id)
|
|
402
|
+
this.handlers.delete(message.id);
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
429
405
|
}
|
|
430
|
-
/** 处理接收到的
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
*/
|
|
406
|
+
/** 处理接收到的 websocket message 并解析, 根据 id dispatch 到对应的 handler 进行处理
|
|
407
|
+
如果 message.done == true 则清理 handler
|
|
408
|
+
如果 handler 返回了值,则包装为 message 发送 */
|
|
434
409
|
async handle(event, websocket) {
|
|
435
410
|
const message = Remote.parse(event.data);
|
|
436
|
-
const {
|
|
411
|
+
const { id, func, done } = message;
|
|
437
412
|
if (this.print)
|
|
438
413
|
console.log(message);
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
await handler(message, websocket);
|
|
445
|
-
}
|
|
446
|
-
catch (error) {
|
|
447
|
-
this.send({
|
|
448
|
-
id,
|
|
449
|
-
error,
|
|
450
|
-
done: true
|
|
451
|
-
}, websocket);
|
|
452
|
-
throw error;
|
|
453
|
-
}
|
|
454
|
-
else { // 作为发起方
|
|
455
|
-
this.handlers[id](message);
|
|
414
|
+
let handler;
|
|
415
|
+
if (func)
|
|
416
|
+
handler = this.funcs[func];
|
|
417
|
+
else {
|
|
418
|
+
handler = this.handlers.get(id);
|
|
456
419
|
if (done)
|
|
457
|
-
this.handlers
|
|
420
|
+
this.handlers.delete(id);
|
|
458
421
|
}
|
|
422
|
+
try {
|
|
423
|
+
if (handler) {
|
|
424
|
+
const data = await handler(message, websocket);
|
|
425
|
+
if (data)
|
|
426
|
+
await this.send({ id, data }, websocket);
|
|
427
|
+
}
|
|
428
|
+
else if (message.error)
|
|
429
|
+
throw message.error;
|
|
430
|
+
else
|
|
431
|
+
throw new Error(`rpc handler not found: ${func ? `func: ${func.quote()}` : `id: ${id}`}`);
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
// handle 出错并不意味着 rpc 一定会结束,可能 error 是运行中的正常数据,所以不能清理 handler
|
|
435
|
+
if (websocket.readyState === WebSocket.OPEN &&
|
|
436
|
+
!message.error // 防止无限循环往对方发送 error, 只有在对方无错误时才可以发送
|
|
437
|
+
)
|
|
438
|
+
try {
|
|
439
|
+
await this.send({ id, error, /* 不能设置 done 清理对面 handler, 理由同上 */ }, websocket);
|
|
440
|
+
}
|
|
441
|
+
catch { }
|
|
442
|
+
// 再往上层抛出错误没有意义了,上层调用栈是 websocket.on('message') 之类的
|
|
443
|
+
console.log(error);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/** 调用 remote 中的 func, 只适用于最简单的一元 rpc (请求, 响应) */
|
|
447
|
+
async call(func, args) {
|
|
448
|
+
return new Promise(async (resolve, reject) => {
|
|
449
|
+
const id = genid();
|
|
450
|
+
this.handlers.set(id, (message) => {
|
|
451
|
+
const { error, data } = message;
|
|
452
|
+
if (error)
|
|
453
|
+
reject(error);
|
|
454
|
+
else
|
|
455
|
+
resolve(data);
|
|
456
|
+
this.handlers.delete(id);
|
|
457
|
+
});
|
|
458
|
+
await this.send({ id, func, data: args }); // 不需要 done: true, 因为对面的 remote.handlers 中不会有这个 id 的 handler
|
|
459
|
+
});
|
|
459
460
|
}
|
|
460
461
|
}
|
|
461
462
|
//# sourceMappingURL=net.js.map
|