xshell 1.1.25 → 1.2.0
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/builder.d.ts +2 -2
- package/builder.js +1 -1
- package/file.d.ts +1 -2
- package/file.js +15 -16
- package/io.browser.d.ts +22 -0
- package/io.browser.js +537 -0
- package/io.d.ts +22 -0
- package/io.js +537 -0
- package/net.browser.d.ts +1 -30
- package/net.browser.js +6 -53
- package/net.d.ts +1 -30
- package/net.js +6 -53
- package/package.json +1 -1
- package/process.js +1 -0
- package/prototype.browser.d.ts +19 -6
- package/prototype.browser.js +20 -6
- package/prototype.d.ts +19 -6
- package/prototype.js +20 -6
- package/server.d.ts +2 -2
- package/server.js +17 -17
- package/utils.browser.d.ts +7 -1
- package/utils.browser.js +19 -2
- package/utils.d.ts +10 -4
- package/utils.js +23 -5
package/io.js
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import "./prototype.js";
|
|
2
|
+
import { decode, encode_into, ceil2, seq } from "./utils.js";
|
|
3
|
+
// 类型 | 编码
|
|
4
|
+
// --------------- | -------------------
|
|
5
|
+
// small int + | 0x00 - 0x1f (0 - 31 自然数)
|
|
6
|
+
// small bin | 0x20 - 0x3f (32 - 63) 0 - 31 个字节的 uint8array
|
|
7
|
+
// small string | 0x40 - 0x7f (64 - 127) 0 - 63 长度的字符串
|
|
8
|
+
// small array | 0x80 - 0x8f (128 - 143) 0 - 15 个元素的数组
|
|
9
|
+
// small set | 0x90 - 0x9f (144 - 159) 0 - 15 个 key 的 set
|
|
10
|
+
// small object | 0xa0 - 0xaf (160 - 175) 0 - 15 个 key 的对象
|
|
11
|
+
// small map | 0xb0 - 0xbf (176 - 191) 0 - 15 个 kv 的 map
|
|
12
|
+
// undefined | 0xc0
|
|
13
|
+
// null | 0xc1
|
|
14
|
+
// false | 0xc2
|
|
15
|
+
// true | 0xc3
|
|
16
|
+
// int 8 | 0xc4
|
|
17
|
+
// int 16 | 0xc5
|
|
18
|
+
// int 32 | 0xc6
|
|
19
|
+
// float 64 | 0xc7
|
|
20
|
+
// bigint 64 | 0xc8 int64
|
|
21
|
+
// bigint string | 0xc9 string
|
|
22
|
+
// error 8 | 0xca 长度 1 b + kv 对
|
|
23
|
+
// regexp | 0xcb source string + flags string
|
|
24
|
+
// rpc message | 0xcc small array, 格式为 [id, func, data, error, done], 最后的 undefined 的项去掉
|
|
25
|
+
// date | 0xcd 8 b float64
|
|
26
|
+
// url | 0xce string
|
|
27
|
+
// bin 8 | 0xd0 长度 1 b + 内容
|
|
28
|
+
// bin 16 | 0xd1 长度 2 b + 内容
|
|
29
|
+
// bin 32 | 0xd2 长度 4 b + 内容
|
|
30
|
+
// string 8 | 0xd3 长度 1 b + 内容
|
|
31
|
+
// string 16 | 0xd4 长度 2 b + 内容
|
|
32
|
+
// string 32 | 0xd5 长度 4 b + 内容
|
|
33
|
+
// array 8 | 0xd6
|
|
34
|
+
// array 32 | 0xd7
|
|
35
|
+
// set 8 | 0xd8
|
|
36
|
+
// set 32 | 0xd9
|
|
37
|
+
// object kv 对数量只有全部遍历才知道,因此只用 small object / object 16
|
|
38
|
+
// object 16 | 0xda kv 对数 2 b + kv 对
|
|
39
|
+
// map 8 | 0xdb
|
|
40
|
+
// map 32 | 0xdc
|
|
41
|
+
// small int - | 0xe0 - 0xff (-32 ~ -1)
|
|
42
|
+
// --- 共享状态,可以看成是模块对象的属性 (隐式 this),有以下好处:
|
|
43
|
+
// 避免函数调用时传一堆参数,返回一堆值
|
|
44
|
+
// 方便设计 buffer pool, 减少对象创建
|
|
45
|
+
// --- 解码
|
|
46
|
+
/** 待解码的 buffer */
|
|
47
|
+
let buf = new Uint8Array(0);
|
|
48
|
+
/** 待解码的 buffer 对应的 dataview */
|
|
49
|
+
let dv = buf.dataview;
|
|
50
|
+
/** 指针,指向下一个要读取 / 写入的位置 */
|
|
51
|
+
let p = 0;
|
|
52
|
+
// --- 编码
|
|
53
|
+
/** 编码缓冲区,持续往里写入,满了就用一个两倍大小的替换,将旧的未写完的部分复制过来 */
|
|
54
|
+
let buffer = new Uint8Array(Buffer.poolSize);
|
|
55
|
+
/** 编码缓冲区对应的 dataview */
|
|
56
|
+
let dataview = buffer.dataview;
|
|
57
|
+
/** 指针,编码缓冲区可以写入的位置,只增不减,除非换新 buffer */
|
|
58
|
+
let q = 0;
|
|
59
|
+
/** 某次编码开始时的位置,用于换缓冲区时从这里开始复制,以及最终返回时的起点 */
|
|
60
|
+
let qstart = 0;
|
|
61
|
+
const int64max = 1n << 63n;
|
|
62
|
+
/** 用这个符号来标识 message 对象 */
|
|
63
|
+
export const message_symbol = Symbol('message');
|
|
64
|
+
const message_keys = ['id', 'func', 'data', 'error', 'done'];
|
|
65
|
+
export function parse(_buf) {
|
|
66
|
+
// 初始化共享状态
|
|
67
|
+
buf = _buf;
|
|
68
|
+
dv = _buf.dataview;
|
|
69
|
+
p = 0;
|
|
70
|
+
return _parse();
|
|
71
|
+
}
|
|
72
|
+
function _parse() {
|
|
73
|
+
const type = buf[p++];
|
|
74
|
+
// 0 - 31 自然数
|
|
75
|
+
if (type <= 0x1f)
|
|
76
|
+
return type;
|
|
77
|
+
// small bin
|
|
78
|
+
if (type <= 0x3f)
|
|
79
|
+
return buf.subarray(p, p += type - 0x20);
|
|
80
|
+
// small string (0 - 63 长度的字符串)
|
|
81
|
+
if (type <= 0x7f)
|
|
82
|
+
return parse_string(type - 0x40);
|
|
83
|
+
// small array
|
|
84
|
+
if (type <= 0x8f)
|
|
85
|
+
return parse_array(type - 0x80);
|
|
86
|
+
// small set
|
|
87
|
+
if (type <= 0x9f)
|
|
88
|
+
return parse_set(type - 0x90);
|
|
89
|
+
// small object
|
|
90
|
+
if (type <= 0xaf)
|
|
91
|
+
return parse_object(type - 0xa0);
|
|
92
|
+
// small map
|
|
93
|
+
if (type <= 0xbf)
|
|
94
|
+
return parse_map(type - 0xb0);
|
|
95
|
+
// -32 ~ -1 小负整数
|
|
96
|
+
if (type >= 0xe0)
|
|
97
|
+
return type - 0x100;
|
|
98
|
+
switch (type) {
|
|
99
|
+
case 0xc0:
|
|
100
|
+
return undefined;
|
|
101
|
+
case 0xc1:
|
|
102
|
+
return null;
|
|
103
|
+
case 0xc2:
|
|
104
|
+
return false;
|
|
105
|
+
case 0xc3:
|
|
106
|
+
return true;
|
|
107
|
+
// int 8
|
|
108
|
+
case 0xc4:
|
|
109
|
+
return dv.getInt8(p++);
|
|
110
|
+
// int 16
|
|
111
|
+
case 0xc5:
|
|
112
|
+
return dv.getInt16(inc(2), true);
|
|
113
|
+
// int 32
|
|
114
|
+
case 0xc6:
|
|
115
|
+
return dv.getInt32(inc(4), true);
|
|
116
|
+
// float 64
|
|
117
|
+
case 0xc7:
|
|
118
|
+
return dv.getFloat64(inc(8), true);
|
|
119
|
+
// bigint 64
|
|
120
|
+
case 0xc8:
|
|
121
|
+
return dv.getBigInt64(inc(8), true);
|
|
122
|
+
// bigint string
|
|
123
|
+
case 0xc9:
|
|
124
|
+
return BigInt(_parse());
|
|
125
|
+
// error 8
|
|
126
|
+
case 0xca:
|
|
127
|
+
return Object.assign(new Error(), parse_object(buf[p++]));
|
|
128
|
+
// regexp
|
|
129
|
+
case 0xcb:
|
|
130
|
+
return new RegExp(_parse(), _parse());
|
|
131
|
+
// rpc message
|
|
132
|
+
case 0xcc: {
|
|
133
|
+
const values = _parse();
|
|
134
|
+
let message = {};
|
|
135
|
+
for (let i = 0; i < values.length; i++)
|
|
136
|
+
message[message_keys[i]] = values[i];
|
|
137
|
+
return message;
|
|
138
|
+
}
|
|
139
|
+
// date
|
|
140
|
+
case 0xcd:
|
|
141
|
+
return new Date(dv.getFloat64(inc(8), true));
|
|
142
|
+
// url
|
|
143
|
+
case 0xce:
|
|
144
|
+
return new URL(_parse());
|
|
145
|
+
// bin 8, 16, 32
|
|
146
|
+
case 0xd0:
|
|
147
|
+
case 0xd1:
|
|
148
|
+
case 0xd2: {
|
|
149
|
+
const len = parse_length(type - 0xd0);
|
|
150
|
+
return buf.subarray(p, p += len);
|
|
151
|
+
}
|
|
152
|
+
// string 8, 16, 32
|
|
153
|
+
case 0xd3:
|
|
154
|
+
case 0xd4:
|
|
155
|
+
case 0xd5:
|
|
156
|
+
return parse_string(parse_length(type - 0xd3));
|
|
157
|
+
// array 8, 32
|
|
158
|
+
case 0xd6:
|
|
159
|
+
case 0xd7:
|
|
160
|
+
return parse_array(parse_length(type === 0xd6 ? 0 : 2));
|
|
161
|
+
// set 8, 32
|
|
162
|
+
case 0xd8:
|
|
163
|
+
case 0xd9:
|
|
164
|
+
return parse_set(parse_length(type === 0xd8 ? 0 : 2));
|
|
165
|
+
// object 16
|
|
166
|
+
case 0xda:
|
|
167
|
+
return parse_object(dv.getUint16(inc(2), true));
|
|
168
|
+
// map 8, 32
|
|
169
|
+
case 0xdb:
|
|
170
|
+
case 0xdc:
|
|
171
|
+
return parse_map(parse_length(type === 0xdb ? 0 : 2));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** 模拟自增 (后置++) 运算符 */
|
|
175
|
+
function inc(len) {
|
|
176
|
+
p += len;
|
|
177
|
+
return p - len;
|
|
178
|
+
}
|
|
179
|
+
function parse_length(length_type) {
|
|
180
|
+
switch (length_type) {
|
|
181
|
+
case 0:
|
|
182
|
+
return buf[p++];
|
|
183
|
+
case 1:
|
|
184
|
+
return dv.getUint16(inc(2), true);
|
|
185
|
+
case 2:
|
|
186
|
+
return dv.getUint32(inc(4), true);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function parse_string(len) {
|
|
190
|
+
return decode(buf.subarray(p, p += len));
|
|
191
|
+
}
|
|
192
|
+
function parse_array(len) {
|
|
193
|
+
let a = new Array(len);
|
|
194
|
+
for (let i = 0; i < len; i++)
|
|
195
|
+
a[i] = _parse();
|
|
196
|
+
return a;
|
|
197
|
+
}
|
|
198
|
+
function parse_set(size) {
|
|
199
|
+
let s = new Set();
|
|
200
|
+
for (let i = 0; i < size; i++)
|
|
201
|
+
s.add(_parse());
|
|
202
|
+
return s;
|
|
203
|
+
}
|
|
204
|
+
function parse_object(nentries) {
|
|
205
|
+
let o = {};
|
|
206
|
+
for (let i = 0; i < nentries; i++) {
|
|
207
|
+
const key = _parse();
|
|
208
|
+
o[key] = _parse();
|
|
209
|
+
}
|
|
210
|
+
return o;
|
|
211
|
+
}
|
|
212
|
+
function parse_map(nentries) {
|
|
213
|
+
let map = new Map();
|
|
214
|
+
for (let i = 0; i < nentries; i++)
|
|
215
|
+
map.set(_parse(), _parse());
|
|
216
|
+
return map;
|
|
217
|
+
}
|
|
218
|
+
export function pack(obj) {
|
|
219
|
+
qstart = q;
|
|
220
|
+
_pack(obj);
|
|
221
|
+
return buffer.subarray(qstart, q);
|
|
222
|
+
}
|
|
223
|
+
/** 申请空间,确保 [q, q + size) 可以写入,不够时扩容,换缓冲区,并复制现有内容
|
|
224
|
+
- size: 准备写入多少字节的内容,取值 >= 1 */
|
|
225
|
+
function alloc(size) {
|
|
226
|
+
if (q + size <= buffer.byteLength)
|
|
227
|
+
return;
|
|
228
|
+
let buffer_ = new Uint8Array(ceil2(q + size));
|
|
229
|
+
// console.log('扩容:', buffer_.byteLength / 2**20)
|
|
230
|
+
buffer_.set(buffer.subarray(qstart, q));
|
|
231
|
+
buffer = buffer_;
|
|
232
|
+
dataview = buffer_.dataview;
|
|
233
|
+
q -= qstart;
|
|
234
|
+
qstart = 0;
|
|
235
|
+
}
|
|
236
|
+
function _pack(value) {
|
|
237
|
+
// 提前判断以减少一次函数调用
|
|
238
|
+
if (q + 1 >= buffer.byteLength)
|
|
239
|
+
alloc(1);
|
|
240
|
+
switch (typeof value) {
|
|
241
|
+
case 'undefined':
|
|
242
|
+
buffer[q++] = 0xc0;
|
|
243
|
+
return;
|
|
244
|
+
case 'boolean':
|
|
245
|
+
buffer[q++] = value ? 0xc3 : 0xc2;
|
|
246
|
+
return;
|
|
247
|
+
case 'string': {
|
|
248
|
+
const { length } = value;
|
|
249
|
+
// 分配空间按照极限情况 strlen * 3 考虑,反正先申请着,后面也可以作他用
|
|
250
|
+
// 提前判断以减少一次函数调用
|
|
251
|
+
if (q + 1 + 4 + length * 3 >= buffer.byteLength)
|
|
252
|
+
alloc(1 + 4 + length * 3);
|
|
253
|
+
// 按最乐观的估计,如果估计错误,且影响到布局,再复制
|
|
254
|
+
// 通常受影响的都是小字符串,且概率不大,因此总体复制开销不大
|
|
255
|
+
let lensize = 0;
|
|
256
|
+
if (length <= 0x3f)
|
|
257
|
+
lensize = 0;
|
|
258
|
+
else if (length <= 0xff)
|
|
259
|
+
lensize = 1;
|
|
260
|
+
else if (length <= 0xffff)
|
|
261
|
+
lensize = 2;
|
|
262
|
+
else
|
|
263
|
+
lensize = 4;
|
|
264
|
+
// q (类型), lensize ..., qstr ...
|
|
265
|
+
const qstr = q + 1 + lensize;
|
|
266
|
+
const blen = pack_string(value, qstr);
|
|
267
|
+
if (blen <= 0x3f)
|
|
268
|
+
buffer[q++] = 0x40 + blen;
|
|
269
|
+
else if (blen <= 0xff) {
|
|
270
|
+
if (lensize < 1)
|
|
271
|
+
buffer.copyWithin(q + 1 + 1, qstr, qstr + blen);
|
|
272
|
+
buffer[q++] = 0xd3;
|
|
273
|
+
buffer[q++] = blen;
|
|
274
|
+
}
|
|
275
|
+
else if (blen <= 0xffff) {
|
|
276
|
+
if (lensize < 2)
|
|
277
|
+
buffer.copyWithin(q + 1 + 2, qstr, qstr + blen);
|
|
278
|
+
buffer[q++] = 0xd4;
|
|
279
|
+
dataview.setUint16(q, blen, true);
|
|
280
|
+
q += 2;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
if (lensize < 4)
|
|
284
|
+
buffer.copyWithin(q + 1 + 4, qstr, qstr + blen);
|
|
285
|
+
buffer[q++] = 0xd5;
|
|
286
|
+
dataview.setUint32(q, blen, true);
|
|
287
|
+
q += 4;
|
|
288
|
+
}
|
|
289
|
+
q += blen;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
case 'number':
|
|
293
|
+
// 是一个有效的 32 位有符号整数
|
|
294
|
+
if (value >> 0 === value)
|
|
295
|
+
if (value >= 0)
|
|
296
|
+
if (value <= 0x1f)
|
|
297
|
+
buffer[q++] = value;
|
|
298
|
+
else if (value <= 0x7f) {
|
|
299
|
+
buffer[q++] = 0xc4;
|
|
300
|
+
alloc(1);
|
|
301
|
+
buffer[q++] = value;
|
|
302
|
+
}
|
|
303
|
+
else if (value <= 0x7fff) {
|
|
304
|
+
buffer[q++] = 0xc5;
|
|
305
|
+
alloc(2);
|
|
306
|
+
dataview.setInt16(q, value, true);
|
|
307
|
+
q += 2;
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
buffer[q++] = 0xc6;
|
|
311
|
+
alloc(4);
|
|
312
|
+
dataview.setInt32(q, value, true);
|
|
313
|
+
q += 4;
|
|
314
|
+
}
|
|
315
|
+
else if (value >= -0x20)
|
|
316
|
+
// 等价于 dataview.setInt8
|
|
317
|
+
buffer[q++] = value + 0x100;
|
|
318
|
+
else if (value >= -0x80) {
|
|
319
|
+
buffer[q++] = 0xc4;
|
|
320
|
+
alloc(1);
|
|
321
|
+
buffer[q++] = value + 0x100;
|
|
322
|
+
}
|
|
323
|
+
else if (value >= -0x8000) {
|
|
324
|
+
buffer[q++] = 0xc5;
|
|
325
|
+
alloc(2);
|
|
326
|
+
dataview.setInt16(q, value, true);
|
|
327
|
+
q += 2;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
buffer[q++] = 0xc6;
|
|
331
|
+
alloc(4);
|
|
332
|
+
dataview.setInt32(q, value, true);
|
|
333
|
+
q += 4;
|
|
334
|
+
}
|
|
335
|
+
else { // 是浮点数或大于 int32 范围的数
|
|
336
|
+
buffer[q++] = 0xc7;
|
|
337
|
+
alloc(8);
|
|
338
|
+
dataview.setFloat64(q, value, true);
|
|
339
|
+
q += 8;
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
case 'object':
|
|
343
|
+
if (value === null)
|
|
344
|
+
buffer[q++] = 0xc1;
|
|
345
|
+
else if (Array.isArray(value)) {
|
|
346
|
+
const { length } = value;
|
|
347
|
+
if (length <= 0x0f)
|
|
348
|
+
buffer[q++] = 0x80 + length;
|
|
349
|
+
else if (length <= 0xff) {
|
|
350
|
+
buffer[q++] = 0xd6;
|
|
351
|
+
alloc(1);
|
|
352
|
+
buffer[q++] = length;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
buffer[q++] = 0xd7;
|
|
356
|
+
alloc(4);
|
|
357
|
+
dataview.setUint32(q, length, true);
|
|
358
|
+
q += 4;
|
|
359
|
+
}
|
|
360
|
+
for (let i = 0; i < length; i++)
|
|
361
|
+
_pack(value[i]);
|
|
362
|
+
}
|
|
363
|
+
else if (value instanceof Uint8Array) {
|
|
364
|
+
const { length } = value;
|
|
365
|
+
if (length <= 0x1f) {
|
|
366
|
+
buffer[q++] = 0x20 + length;
|
|
367
|
+
alloc(length);
|
|
368
|
+
}
|
|
369
|
+
else if (length <= 0xff) {
|
|
370
|
+
buffer[q++] = 0xd0;
|
|
371
|
+
alloc(1 + length);
|
|
372
|
+
buffer[q++] = length;
|
|
373
|
+
}
|
|
374
|
+
else if (length <= 0xffff) {
|
|
375
|
+
buffer[q++] = 0xd1;
|
|
376
|
+
alloc(2 + length);
|
|
377
|
+
dataview.setUint16(q, length, true);
|
|
378
|
+
q += 2;
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
buffer[q++] = 0xd2;
|
|
382
|
+
alloc(4 + length);
|
|
383
|
+
dataview.setUint32(q, length, true);
|
|
384
|
+
q += 4;
|
|
385
|
+
}
|
|
386
|
+
buffer.set(value, q);
|
|
387
|
+
q += length;
|
|
388
|
+
}
|
|
389
|
+
else if (value instanceof Error) {
|
|
390
|
+
// 乐观认为 error 不超过 255 个 key, 超过的部分直接忽略
|
|
391
|
+
buffer[q++] = 0xca;
|
|
392
|
+
const keys = Object.getOwnPropertyNames(value);
|
|
393
|
+
alloc(1);
|
|
394
|
+
buffer[q++] = keys.length;
|
|
395
|
+
for (const key of keys) {
|
|
396
|
+
_pack(key);
|
|
397
|
+
_pack(value[key]);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
else if (value instanceof Date) {
|
|
401
|
+
buffer[q++] = 0xcd;
|
|
402
|
+
alloc(8);
|
|
403
|
+
dataview.setFloat64(q, value.getTime(), true);
|
|
404
|
+
q += 8;
|
|
405
|
+
}
|
|
406
|
+
else if (value instanceof Set) {
|
|
407
|
+
const { size } = value;
|
|
408
|
+
if (size <= 0x0f)
|
|
409
|
+
buffer[q++] = 0x90 + size;
|
|
410
|
+
else if (size <= 0xff) {
|
|
411
|
+
buffer[q++] = 0xd8;
|
|
412
|
+
alloc(1);
|
|
413
|
+
buffer[q++] = size;
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
buffer[q++] = 0xd9;
|
|
417
|
+
alloc(4);
|
|
418
|
+
dataview.setUint32(q, size, true);
|
|
419
|
+
q += 4;
|
|
420
|
+
}
|
|
421
|
+
for (const v of value)
|
|
422
|
+
_pack(v);
|
|
423
|
+
}
|
|
424
|
+
else if (value instanceof Map) {
|
|
425
|
+
const { size } = value;
|
|
426
|
+
if (size <= 0x0f)
|
|
427
|
+
buffer[q++] = 0xb0 + size;
|
|
428
|
+
else if (size <= 0xff) {
|
|
429
|
+
buffer[q++] = 0xdb;
|
|
430
|
+
alloc(1);
|
|
431
|
+
buffer[q++] = size;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
buffer[q++] = 0xdc;
|
|
435
|
+
alloc(4);
|
|
436
|
+
dataview.setUint32(q, size, true);
|
|
437
|
+
q += 4;
|
|
438
|
+
}
|
|
439
|
+
for (const [k, v] of value) {
|
|
440
|
+
_pack(k);
|
|
441
|
+
_pack(v);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else if (value instanceof RegExp) {
|
|
445
|
+
buffer[q++] = 0xcb;
|
|
446
|
+
_pack(value.source);
|
|
447
|
+
_pack(value.flags);
|
|
448
|
+
}
|
|
449
|
+
else if (value instanceof URL) {
|
|
450
|
+
buffer[q++] = 0xce;
|
|
451
|
+
_pack(value.toString());
|
|
452
|
+
}
|
|
453
|
+
else if (message_symbol in value) {
|
|
454
|
+
buffer[q++] = 0xcc;
|
|
455
|
+
let values = seq(message_keys.length, i => value[message_keys[i]]);
|
|
456
|
+
let iend = message_keys.length;
|
|
457
|
+
for (; iend >= 1 && values[iend - 1] === undefined; --iend)
|
|
458
|
+
_pack(values.slice(0, iend));
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
// 先检查 kv 对的数量是否小于等于 15 (small object)
|
|
462
|
+
// 先不序列化,防止某个 key 对应的 value 很大
|
|
463
|
+
let nkv = 0;
|
|
464
|
+
for (const key in value)
|
|
465
|
+
if (++nkv === 16)
|
|
466
|
+
break;
|
|
467
|
+
// 记录相对位置,避免 buffer 替换后位置错误
|
|
468
|
+
const offset = q + 1 - qstart;
|
|
469
|
+
if (nkv <= 0x0f) // small object
|
|
470
|
+
buffer[q++] = 0xa0 + nkv;
|
|
471
|
+
else {
|
|
472
|
+
buffer[q++] = 0xda;
|
|
473
|
+
// 预留长度,先不填 kv 对数
|
|
474
|
+
alloc(2);
|
|
475
|
+
q += 2;
|
|
476
|
+
}
|
|
477
|
+
nkv = 0;
|
|
478
|
+
for (const key in value) {
|
|
479
|
+
_pack(key);
|
|
480
|
+
_pack(value[key]);
|
|
481
|
+
if (nkv++ > 0xffff)
|
|
482
|
+
throw new Error('对象 key 数量大于 65535,无法序列化');
|
|
483
|
+
}
|
|
484
|
+
if (nkv >= 16)
|
|
485
|
+
// 补填 kv 对数
|
|
486
|
+
dataview.setUint16(qstart + offset, nkv, true);
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
case 'bigint':
|
|
490
|
+
if (value < int64max && value >= -int64max) {
|
|
491
|
+
buffer[q++] = 0xc8;
|
|
492
|
+
alloc(8);
|
|
493
|
+
dataview.setBigInt64(q, value, true);
|
|
494
|
+
q += 8;
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
buffer[q++] = 0xc9;
|
|
498
|
+
_pack(value.toString());
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/** 从 qstr 位置开始写入编码后的 utf8 内容,使用前需要用 alloc 提前预分配空间,
|
|
504
|
+
返回编码后的字节数 */
|
|
505
|
+
function pack_string(value, qstr) {
|
|
506
|
+
const { length } = value;
|
|
507
|
+
if (length <= 0x3f) {
|
|
508
|
+
let j = qstr;
|
|
509
|
+
for (let i = 0; i < length; i++) {
|
|
510
|
+
let c1 = value.charCodeAt(i), c2 = 0;
|
|
511
|
+
if (c1 < 0x80)
|
|
512
|
+
buffer[j++] = c1;
|
|
513
|
+
else if (c1 < 0x800) {
|
|
514
|
+
buffer[j++] = (c1 >> 6) | 0xc0;
|
|
515
|
+
buffer[j++] = (c1 & 0x3f) | 0x80;
|
|
516
|
+
}
|
|
517
|
+
else if ((c1 & 0xfc00) === 0xd800 && ((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00) {
|
|
518
|
+
c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
|
|
519
|
+
i++;
|
|
520
|
+
buffer[j++] = (c1 >> 18) | 0xf0;
|
|
521
|
+
buffer[j++] = ((c1 >> 12) & 0x3f) | 0x80;
|
|
522
|
+
buffer[j++] = ((c1 >> 6) & 0x3f) | 0x80;
|
|
523
|
+
buffer[j++] = (c1 & 0x3f) | 0x80;
|
|
524
|
+
}
|
|
525
|
+
else {
|
|
526
|
+
buffer[j++] = (c1 >> 12) | 0xe0;
|
|
527
|
+
buffer[j++] = ((c1 >> 6) & 0x3f) | 0x80;
|
|
528
|
+
buffer[j++] = (c1 & 0x3f) | 0x80;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return j - qstr;
|
|
532
|
+
}
|
|
533
|
+
else
|
|
534
|
+
return encode_into(value, buffer.subarray(qstr))
|
|
535
|
+
.written;
|
|
536
|
+
}
|
|
537
|
+
//# sourceMappingURL=io.js.map
|
package/net.browser.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import './prototype.browser.ts';
|
|
2
|
+
import { type Message } from './io.browser.ts';
|
|
2
3
|
import { Lock } from './utils.browser.ts';
|
|
3
4
|
export interface FullResponse<TBody extends ArrayBuffer | string> {
|
|
4
5
|
status: number;
|
|
@@ -105,33 +106,6 @@ export declare function connect_websocket(url: string | URL, { protocols, on_mes
|
|
|
105
106
|
- void: 什么都不做
|
|
106
107
|
- 以上的 promise */
|
|
107
108
|
export type MessageHandler<TData extends any[] = any[]> = (message: Message<TData>, websocket?: WebSocket) => void | any[] | Promise<void | any[]>;
|
|
108
|
-
/** 二进制消息格式
|
|
109
|
-
- json.length (小端序): 4 字节
|
|
110
|
-
- json 数据
|
|
111
|
-
- binary 数据 */
|
|
112
|
-
export interface Message<TData extends any[] = any[]> {
|
|
113
|
-
/** rpc id: 在 rpc 系统中认为是唯一的。用来在单个 websocket 连接上复用多个 rpc 请求。多个相同 id 的 message 组成一个请求流 */
|
|
114
|
-
id?: number;
|
|
115
|
-
/** 只在 rpc 发起时指定被调用的 function name,发起时 rpc 时必传 */
|
|
116
|
-
func?: string;
|
|
117
|
-
/** 通过这个 flag 主动表明这是发往对方的最后一个 message, 对方可以销毁 handler 了
|
|
118
|
-
并非强制,可以不说明,由双方的函数自己约定
|
|
119
|
-
*/
|
|
120
|
-
done?: boolean;
|
|
121
|
-
/** 通知对方这里产生的错误,本质上类似 data 也是一种数据,并不代表 rpc 的结束,后续可能继续有 rpc message 交换 */
|
|
122
|
-
error?: Error;
|
|
123
|
-
/** data 是一个数组, 作为:
|
|
124
|
-
- rpc 发起方调用 func 的参数,或者请求流 message 携带的数据
|
|
125
|
-
- 结果或者响应流的数据,传给请求发起方
|
|
126
|
-
|
|
127
|
-
里面是可序列化为 json 的 js 变量,或者是 Uint8Array
|
|
128
|
-
Uint8Array 的参数处理后被替换为 Uint8Array.byteLength, 并将下标记录在 bins 中
|
|
129
|
-
|
|
130
|
-
注意: 数组中如果有 undefined 值,传输到对面会变成 null 值 */
|
|
131
|
-
data?: TData;
|
|
132
|
-
/** bins: data 中哪些下标对应的原始值是 Uint8Array 类型的,如: [0, 3] */
|
|
133
|
-
bins?: number[];
|
|
134
|
-
}
|
|
135
109
|
/** 自动保持 remote 连接,只对 initiator 且传入 url 有效,
|
|
136
110
|
- 在未连接,或 websocket on_error 检测到连接断开后以 reconnect_interval 间隔尝试 remote.call(func) 重连
|
|
137
111
|
- 在连接状态下以 heartbeat_interval 间隔发送心跳包确保连接状态
|
|
@@ -195,9 +169,6 @@ export declare class Remote {
|
|
|
195
169
|
keeping: boolean;
|
|
196
170
|
reconnecting: boolean;
|
|
197
171
|
disconnected: boolean;
|
|
198
|
-
/** 使用 Uint8Array 作为参数更灵活 https://stackoverflow.com/a/74505197/7609214 */
|
|
199
|
-
static parse<TData extends any[] = any[]>(buffer: Uint8Array): Message<TData>;
|
|
200
|
-
static pack({ id, func, data, done, error }: Message): Uint8Array<ArrayBuffer>;
|
|
201
172
|
/** 作为 websocket 连接发起方,传入 url 或 websocket,定义远程 Remote
|
|
202
173
|
作为 websocket 连接接收方,不传 url 和 websocket,定义本地 Remote */
|
|
203
174
|
constructor({ url, funcs, print, verbose, websocket, keeper, on_error, }?: {
|
package/net.browser.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t } from "./i18n/instance.js";
|
|
2
2
|
import "./prototype.browser.js"; // to_time_str()
|
|
3
|
-
import {
|
|
3
|
+
import { message_symbol, pack, parse } from "./io.browser.js";
|
|
4
|
+
import { assert, genid, delay, Lock, timeout, check } from "./utils.browser.js";
|
|
4
5
|
const drop_request_headers = new Set([
|
|
5
6
|
// : 开头的 key
|
|
6
7
|
// sec-*
|
|
@@ -289,54 +290,6 @@ export class Remote {
|
|
|
289
290
|
keeping = false;
|
|
290
291
|
reconnecting = false;
|
|
291
292
|
disconnected = false;
|
|
292
|
-
/** 使用 Uint8Array 作为参数更灵活 https://stackoverflow.com/a/74505197/7609214 */
|
|
293
|
-
static parse(buffer) {
|
|
294
|
-
const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
295
|
-
const len_json = dv.getUint32(0, true);
|
|
296
|
-
let offset = 4 + len_json;
|
|
297
|
-
let message = JSON.parse(decode(buffer.subarray(4, offset)));
|
|
298
|
-
message.data ??= [];
|
|
299
|
-
if (message.bins) {
|
|
300
|
-
const { bins } = message;
|
|
301
|
-
let { data } = message;
|
|
302
|
-
for (const ibin of bins) {
|
|
303
|
-
const len_buf = data[ibin];
|
|
304
|
-
data[ibin] = buffer.subarray(offset, offset + len_buf);
|
|
305
|
-
offset += len_buf;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
if (message.error)
|
|
309
|
-
message.error = Object.assign(new Error(), message.error);
|
|
310
|
-
return message;
|
|
311
|
-
}
|
|
312
|
-
static pack({ id, func, data = [], done, error }) {
|
|
313
|
-
let data_ = new Array(data.length);
|
|
314
|
-
let bins = [];
|
|
315
|
-
let bufs = [];
|
|
316
|
-
for (let i = 0; i < data.length; i++) {
|
|
317
|
-
const item = data[i];
|
|
318
|
-
if (item instanceof Uint8Array) {
|
|
319
|
-
bins.push(i);
|
|
320
|
-
bufs.push(item);
|
|
321
|
-
data_[i] = item.length;
|
|
322
|
-
}
|
|
323
|
-
else
|
|
324
|
-
data_[i] = item;
|
|
325
|
-
}
|
|
326
|
-
const data_json = {
|
|
327
|
-
id,
|
|
328
|
-
...func ? { func } : {},
|
|
329
|
-
...done ? { done } : {},
|
|
330
|
-
...error ? { error } : {},
|
|
331
|
-
...data_.length ? { data: data_ } : {},
|
|
332
|
-
...bins.length ? { bins } : {},
|
|
333
|
-
};
|
|
334
|
-
// 有可能 data_json 含有循环引用导致 JSON.stringify 报错
|
|
335
|
-
const str_json = encode(JSON.stringify(data_json));
|
|
336
|
-
let dv = new DataView(new ArrayBuffer(4));
|
|
337
|
-
dv.setUint32(0, str_json.length, true);
|
|
338
|
-
return concat([dv, str_json, ...bufs]);
|
|
339
|
-
}
|
|
340
293
|
/** 作为 websocket 连接发起方,传入 url 或 websocket,定义远程 Remote
|
|
341
294
|
作为 websocket 连接接收方,不传 url 和 websocket,定义本地 Remote */
|
|
342
295
|
constructor({ url, funcs, print, verbose, websocket, keeper, on_error, } = {}) {
|
|
@@ -483,9 +436,8 @@ export class Remote {
|
|
|
483
436
|
console.log('remote.send:', message);
|
|
484
437
|
try {
|
|
485
438
|
await this.connect(websocket);
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
(websocket || this.lwebsocket.resource).send(Remote.pack(message));
|
|
439
|
+
message[message_symbol] = true;
|
|
440
|
+
(websocket || this.lwebsocket.resource).send(pack(message));
|
|
489
441
|
}
|
|
490
442
|
catch (error) {
|
|
491
443
|
if (message.id)
|
|
@@ -499,9 +451,10 @@ export class Remote {
|
|
|
499
451
|
使用 Uint8Array 作为参数更灵活 https://stackoverflow.com/a/74505197/7609214
|
|
500
452
|
这个方法一般不会抛出错误,也不需要 await,一般在 websocket on_message 时使用 */
|
|
501
453
|
async handle(data, websocket) {
|
|
454
|
+
check(data[0] === 0xcc, 'message 格式错误');
|
|
502
455
|
let message;
|
|
503
456
|
try {
|
|
504
|
-
message =
|
|
457
|
+
message = parse(data);
|
|
505
458
|
}
|
|
506
459
|
catch (error) {
|
|
507
460
|
this.on_error(error);
|