dolphindb 2.0.505 → 2.0.508
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/browser.d.ts +37 -27
- package/browser.js +153 -106
- package/browser.js.map +1 -1
- package/index.d.ts +51 -40
- package/index.js +178 -128
- package/index.js.map +1 -1
- package/package.json +4 -4
package/browser.d.ts
CHANGED
|
@@ -75,7 +75,12 @@ export interface DdbArrayVectorBlock {
|
|
|
75
75
|
lengths: Uint8Array | Uint16Array | Uint32Array;
|
|
76
76
|
data: DdbVectorValue;
|
|
77
77
|
}
|
|
78
|
-
export
|
|
78
|
+
export interface DdbMatrixValue {
|
|
79
|
+
rows: DdbObj;
|
|
80
|
+
cols: DdbObj;
|
|
81
|
+
data: DdbVectorValue;
|
|
82
|
+
}
|
|
83
|
+
export declare type DdbValue = null | boolean | number | [number, number] | bigint | string | string[] | Uint8Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbFunctionDefValue | DdbSymbolExtendedValue | DdbArrayVectorBlock[] | DdbMatrixValue;
|
|
79
84
|
export declare type DdbVectorValue = string | string[] | Uint8Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbSymbolExtendedValue | DdbArrayVectorBlock[];
|
|
80
85
|
export declare const nulls: {
|
|
81
86
|
readonly int8: -128;
|
|
@@ -120,23 +125,20 @@ export declare class DdbObj<T extends DdbValue = DdbValue> {
|
|
|
120
125
|
rows?: number;
|
|
121
126
|
/** 第 2 维 */
|
|
122
127
|
cols?: number;
|
|
123
|
-
/** matrix 中值的类型,仅 matrix 才有 */
|
|
124
|
-
datatype?: DdbType;
|
|
125
128
|
/** 实际数据。不同的 DdbForm, DdbType 使用 DdbValue 中不同的类型来表示实际数据 */
|
|
126
129
|
value: T;
|
|
127
|
-
/**
|
|
130
|
+
/** 原始二进制数据,仅在 parse_object 为 false 时通过 parse_message 生成的顶层对象有这个属性 */
|
|
128
131
|
buffer?: Uint8Array;
|
|
129
132
|
constructor(data: Partial<DdbObj> & {
|
|
130
133
|
form: DdbForm;
|
|
131
134
|
type: DdbType;
|
|
132
|
-
length: number;
|
|
133
135
|
});
|
|
134
136
|
static parse(buf: Uint8Array, le: boolean): DdbObj<DdbValue>;
|
|
135
137
|
static parse_scalar(buf: Uint8Array, le: boolean, type: DdbType): [number, DdbValue];
|
|
136
138
|
/** parse: rows, cols, items
|
|
137
139
|
返回的 ddbobj.length 不包括 vector 的 type 和 form
|
|
138
140
|
*/
|
|
139
|
-
static parse_vector(buf: Uint8Array, le: boolean, type: DdbType): DdbObj
|
|
141
|
+
static parse_vector(buf: Uint8Array, le: boolean, type: DdbType): DdbObj<DdbVectorValue>;
|
|
140
142
|
/** 有可能没有字节对齐,不能直接使用原有 message 的 arraybuffer, 统一复制出来,让原有 arraybuffer 被回收掉比较好 */
|
|
141
143
|
static parse_vector_items(buf: Uint8Array, le: boolean, type: DdbType, length: number): [
|
|
142
144
|
number,
|
|
@@ -271,13 +273,13 @@ export declare class DDB {
|
|
|
271
273
|
password: string;
|
|
272
274
|
/** python session flag (2048) */
|
|
273
275
|
python: boolean;
|
|
276
|
+
print_message_buffer: boolean;
|
|
277
|
+
print_object_buffer: boolean;
|
|
278
|
+
print_message: boolean;
|
|
274
279
|
parse_object: boolean;
|
|
275
|
-
/**
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
presolver(message: DdbMessage): void;
|
|
279
|
-
prejector(error: Error): void;
|
|
280
|
-
presult: Promise<DdbMessage>;
|
|
280
|
+
/** DdbMessage listeners */
|
|
281
|
+
listeners: DdbMessageListener[];
|
|
282
|
+
promise: Promise<any>;
|
|
281
283
|
get connected(): boolean;
|
|
282
284
|
/**
|
|
283
285
|
Initialize an instance of DolphinDB Client using the WebSocket URL
|
|
@@ -292,7 +294,7 @@ export declare class DDB {
|
|
|
292
294
|
@example
|
|
293
295
|
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
294
296
|
|
|
295
|
-
//
|
|
297
|
+
// Encrypt with HTTPS
|
|
296
298
|
let ddbsecure = new DDB('wss://dolphindb.com', {
|
|
297
299
|
autologin: true,
|
|
298
300
|
username: 'admin',
|
|
@@ -306,6 +308,7 @@ export declare class DDB {
|
|
|
306
308
|
password?: string;
|
|
307
309
|
python?: boolean;
|
|
308
310
|
});
|
|
311
|
+
private on_message;
|
|
309
312
|
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
|
|
310
313
|
- options?:
|
|
311
314
|
- url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
|
|
@@ -350,31 +353,31 @@ export declare class DDB {
|
|
|
350
353
|
- options:
|
|
351
354
|
- urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
|
|
352
355
|
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
353
|
-
-
|
|
354
|
-
- parse_object?:
|
|
355
|
-
|
|
356
|
+
- listener?: 处理本次 rpc 期间的消息 (DdbMessage)
|
|
357
|
+
- parse_object?: 在本次 rpc 期间设置 parse_object, 结束后恢复原有
|
|
358
|
+
为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
|
|
356
359
|
*/
|
|
357
|
-
rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable' | 'connect', { script, func, args, vars, urgent,
|
|
360
|
+
rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable' | 'connect', { script, func, args, vars, urgent, listener, parse_object, }: {
|
|
358
361
|
script?: string;
|
|
359
362
|
func?: string;
|
|
360
363
|
args?: (DdbObj | string | boolean)[];
|
|
361
364
|
vars?: string[];
|
|
362
365
|
urgent?: boolean;
|
|
363
|
-
|
|
366
|
+
listener?: DdbMessageListener;
|
|
364
367
|
parse_object?: boolean;
|
|
365
368
|
}): Promise<T>;
|
|
366
369
|
/** eval script through websocket (script command)
|
|
367
370
|
- script?: Script to execute
|
|
368
371
|
- options?: execution options
|
|
369
372
|
- urgent?: Urgent flag to ensure that submitted scripts are processed by urgent workers to prevent being blocked by other jobs
|
|
370
|
-
-
|
|
373
|
+
- listener?: Process messages during this rpc (DdbMessage)
|
|
371
374
|
- parse_object?: Set parse_object during this rpc, and restore the original after the end.
|
|
372
375
|
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
373
376
|
so as to facilitate subsequent forwarding and serialization
|
|
374
377
|
*/
|
|
375
|
-
eval<T extends DdbObj>(script: string, { urgent,
|
|
378
|
+
eval<T extends DdbObj>(script: string, { urgent, listener, parse_object, }?: {
|
|
376
379
|
urgent?: boolean;
|
|
377
|
-
|
|
380
|
+
listener?: DdbMessageListener;
|
|
378
381
|
parse_object?: boolean;
|
|
379
382
|
}): Promise<T>;
|
|
380
383
|
/** call function through websocket (function command)
|
|
@@ -386,18 +389,18 @@ export declare class DDB {
|
|
|
386
389
|
- nodes?: When setting multiple node aliases, send them to the corresponding multiple nodes in the cluster for execution (using the pnodeRun method in DolphinDB)
|
|
387
390
|
- func_type?: It must be passed when setting the node parameter, the function type needs to be specified, and it is not passed in other cases
|
|
388
391
|
- add_node_alias?: Select to pass when setting the nodes parameter, otherwise not pass
|
|
389
|
-
-
|
|
392
|
+
- listener?: Process messages during this rpc (DdbMessage)
|
|
390
393
|
- parse_object?: Set parse_object during this rpc, and restore the original after the end.
|
|
391
394
|
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
392
395
|
so as to facilitate subsequent forwarding and serialization
|
|
393
396
|
*/
|
|
394
|
-
call<T extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias,
|
|
397
|
+
call<T extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, }?: {
|
|
395
398
|
urgent?: boolean;
|
|
396
399
|
node?: string;
|
|
397
400
|
nodes?: string[];
|
|
398
401
|
func_type?: DdbFunctionType;
|
|
399
402
|
add_node_alias?: boolean;
|
|
400
|
-
|
|
403
|
+
listener?: DdbMessageListener;
|
|
401
404
|
parse_object?: boolean;
|
|
402
405
|
}): Promise<T>;
|
|
403
406
|
/** upload variable through websocket (variable command) */
|
|
@@ -405,8 +408,8 @@ export declare class DDB {
|
|
|
405
408
|
/** Uploaded variables' name */
|
|
406
409
|
vars: string[],
|
|
407
410
|
/** Uploaded variables' value */
|
|
408
|
-
args: (DdbObj | string | boolean)[], {
|
|
409
|
-
|
|
411
|
+
args: (DdbObj | string | boolean)[], { listener, parse_object, }?: {
|
|
412
|
+
listener?: DdbMessageListener;
|
|
410
413
|
parse_object?: boolean;
|
|
411
414
|
}): Promise<DdbObj<DdbValue>>;
|
|
412
415
|
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
@@ -416,6 +419,9 @@ export declare class DDB {
|
|
|
416
419
|
/** 转换 js 数组为 DdbObj[] */
|
|
417
420
|
to_ddbobjs(values: any[]): DdbObj<DdbValue>[];
|
|
418
421
|
}
|
|
422
|
+
export interface DdbMessageListener {
|
|
423
|
+
(message: DdbMessage, _this: DDB): any;
|
|
424
|
+
}
|
|
419
425
|
export interface DdbPrintMessage {
|
|
420
426
|
type: 'print';
|
|
421
427
|
data: string;
|
|
@@ -424,6 +430,10 @@ export interface DdbObjectMessage {
|
|
|
424
430
|
type: 'object';
|
|
425
431
|
data: DdbObj;
|
|
426
432
|
}
|
|
427
|
-
export
|
|
433
|
+
export interface DdbErrorMessage {
|
|
434
|
+
type: 'error';
|
|
435
|
+
data: Error;
|
|
436
|
+
}
|
|
437
|
+
export declare type DdbMessage = DdbPrintMessage | DdbObjectMessage | DdbErrorMessage;
|
|
428
438
|
export declare let ddb: DDB;
|
|
429
439
|
export default ddb;
|
package/browser.js
CHANGED
|
@@ -202,34 +202,60 @@ class DdbObj {
|
|
|
202
202
|
});
|
|
203
203
|
}
|
|
204
204
|
case DdbForm.matrix: {
|
|
205
|
-
//
|
|
205
|
+
// rename!(
|
|
206
|
+
// 1..9$3:3,
|
|
206
207
|
// [1, 2, 3],
|
|
207
|
-
// [
|
|
208
|
-
//
|
|
209
|
-
// <Buffer
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
// 01
|
|
208
|
+
// ['c1', 'c2', 'c3']
|
|
209
|
+
// )
|
|
210
|
+
// <Buffer 04 03 type = int, form = matrix
|
|
211
|
+
// 03 has_row_label (& 0x01) = 1, has_col_label (& 0x02) = 1
|
|
212
|
+
// row labels
|
|
213
|
+
// 04 01 type = int, form = vector
|
|
214
|
+
// 03 00 00 00 01 00 00 00 rows = 3, cols = 1
|
|
215
|
+
// 01 00 00 00 02 00 00 00 03 00 00 00 vector values
|
|
216
|
+
// col labels
|
|
217
|
+
// 12 01 type = string, form = vector
|
|
218
|
+
// 03 00 00 00 01 00 00 00 rows = 3, cols = 1
|
|
219
|
+
// 63 31 00 63 32 00 63 33 00
|
|
220
|
+
// matrix data
|
|
221
|
+
// 04 03 type = matrix.type, form = matrix
|
|
222
|
+
// 03 00 00 00 03 00 00 00 rows = 3, cols = 3
|
|
213
223
|
const dv = new DataView(buf.buffer, buf.byteOffset + i_data);
|
|
214
224
|
const label_flags = buf_data[0];
|
|
215
225
|
const has_row_labels = Boolean(label_flags & 0x01);
|
|
216
226
|
const has_col_labels = Boolean(label_flags & 0x02);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
let row_labels = null;
|
|
228
|
+
let col_labels = null;
|
|
229
|
+
let offset = 1;
|
|
230
|
+
if (has_row_labels) {
|
|
231
|
+
row_labels = this.parse_vector(buf_data.subarray(offset + 2), le, buf_data[offset]);
|
|
232
|
+
row_labels.length += 2;
|
|
233
|
+
offset += row_labels.length;
|
|
234
|
+
}
|
|
235
|
+
if (has_col_labels) {
|
|
236
|
+
col_labels = this.parse_vector(buf_data.subarray(offset + 2), le, buf_data[offset]);
|
|
237
|
+
col_labels.length += 2;
|
|
238
|
+
offset += col_labels.length;
|
|
239
|
+
}
|
|
240
|
+
if (buf_data[offset] !== type)
|
|
241
|
+
throw new Error('matrix.datatype !== matrix.type');
|
|
242
|
+
const rows = dv.getUint32(offset + 2, le);
|
|
243
|
+
const cols = dv.getUint32(offset + 6, le);
|
|
244
|
+
const [len_items, data] = this.parse_vector_items(buf_data.subarray(offset + 10), le, type, rows * cols // 假设小于 2**32
|
|
223
245
|
);
|
|
246
|
+
offset += 10 + len_items;
|
|
224
247
|
return new this({
|
|
225
248
|
le,
|
|
226
249
|
form,
|
|
227
250
|
type,
|
|
228
|
-
length: i_data +
|
|
251
|
+
length: i_data + offset,
|
|
229
252
|
rows,
|
|
230
253
|
cols,
|
|
231
|
-
|
|
232
|
-
|
|
254
|
+
value: {
|
|
255
|
+
rows: row_labels,
|
|
256
|
+
cols: col_labels,
|
|
257
|
+
data,
|
|
258
|
+
},
|
|
233
259
|
});
|
|
234
260
|
}
|
|
235
261
|
default:
|
|
@@ -581,7 +607,7 @@ class DdbObj {
|
|
|
581
607
|
}
|
|
582
608
|
pack() {
|
|
583
609
|
const { form, type, value } = this;
|
|
584
|
-
let header = new Uint8Array(
|
|
610
|
+
let header = new Uint8Array(2);
|
|
585
611
|
header[0] = type;
|
|
586
612
|
header[1] = form;
|
|
587
613
|
const body = (() => {
|
|
@@ -722,12 +748,17 @@ class DdbObj {
|
|
|
722
748
|
value[0].pack(),
|
|
723
749
|
value[1].pack(),
|
|
724
750
|
];
|
|
725
|
-
case DdbForm.matrix:
|
|
751
|
+
case DdbForm.matrix: {
|
|
752
|
+
const { rows, cols, data } = value;
|
|
726
753
|
return [
|
|
727
|
-
Uint8Array.of(
|
|
754
|
+
Uint8Array.of((rows && 0x01) | (cols && 0x02)),
|
|
755
|
+
...rows ? [rows.pack()] : [],
|
|
756
|
+
...cols ? [cols.pack()] : [],
|
|
757
|
+
Uint8Array.of(this.type, this.form),
|
|
728
758
|
Uint32Array.of(this.rows, this.cols),
|
|
729
|
-
...DdbObj.pack_vector_body(
|
|
759
|
+
...DdbObj.pack_vector_body(data, this.type, this.rows * this.cols)
|
|
730
760
|
];
|
|
761
|
+
}
|
|
731
762
|
default:
|
|
732
763
|
throw new Error(`${DdbForm[form]} 暂不支持序列化`);
|
|
733
764
|
}
|
|
@@ -841,7 +872,7 @@ class DdbObj {
|
|
|
841
872
|
case DdbForm.dict:
|
|
842
873
|
return `dict<${DdbType[this.value[0].type]}, ${DdbType[this.value[1].type]}>`;
|
|
843
874
|
case DdbForm.matrix:
|
|
844
|
-
return `matrix<${DdbType[this.
|
|
875
|
+
return `matrix<${DdbType[this.type]}>[${this.rows} rows][${this.cols} cols]`;
|
|
845
876
|
default:
|
|
846
877
|
return `${DdbForm[this.form]} ${tname}`;
|
|
847
878
|
}
|
|
@@ -890,21 +921,26 @@ class DdbObj {
|
|
|
890
921
|
for (let i = 0; i < this.rows; i++) {
|
|
891
922
|
let row = {};
|
|
892
923
|
for (let j = 0; j < this.cols; j++) {
|
|
893
|
-
const { type, name, value } = this.value[j]; // column
|
|
924
|
+
const { type, name, value: values } = this.value[j]; // column
|
|
894
925
|
switch (type) {
|
|
895
|
-
case DdbType.bool:
|
|
896
|
-
|
|
926
|
+
case DdbType.bool: {
|
|
927
|
+
const value = values[i];
|
|
928
|
+
row[name] = value === exports.nulls.int8 ?
|
|
929
|
+
null
|
|
930
|
+
:
|
|
931
|
+
Boolean(value);
|
|
897
932
|
break;
|
|
933
|
+
}
|
|
898
934
|
case DdbType.ipaddr:
|
|
899
|
-
row[name] =
|
|
935
|
+
row[name] = values.subarray(16 * i, 16 * (i + 1));
|
|
900
936
|
break;
|
|
901
937
|
case DdbType.symbol_extended: {
|
|
902
|
-
const { base, data } =
|
|
938
|
+
const { base, data } = values;
|
|
903
939
|
row[name] = base[data[i]];
|
|
904
940
|
break;
|
|
905
941
|
}
|
|
906
942
|
default:
|
|
907
|
-
row[name] =
|
|
943
|
+
row[name] = values[i];
|
|
908
944
|
}
|
|
909
945
|
}
|
|
910
946
|
rows[i] = row;
|
|
@@ -1342,7 +1378,7 @@ class DDB {
|
|
|
1342
1378
|
@example
|
|
1343
1379
|
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
1344
1380
|
|
|
1345
|
-
//
|
|
1381
|
+
// Encrypt with HTTPS
|
|
1346
1382
|
let ddbsecure = new DDB('wss://dolphindb.com', {
|
|
1347
1383
|
autologin: true,
|
|
1348
1384
|
username: 'admin',
|
|
@@ -1367,8 +1403,13 @@ class DDB {
|
|
|
1367
1403
|
this.password = '123456';
|
|
1368
1404
|
/** python session flag (2048) */
|
|
1369
1405
|
this.python = false;
|
|
1406
|
+
this.print_message_buffer = false;
|
|
1407
|
+
this.print_object_buffer = false;
|
|
1408
|
+
this.print_message = true;
|
|
1370
1409
|
this.parse_object = true;
|
|
1371
|
-
|
|
1410
|
+
/** DdbMessage listeners */
|
|
1411
|
+
this.listeners = [];
|
|
1412
|
+
this.promise = Promise.resolve(null);
|
|
1372
1413
|
if (!url) {
|
|
1373
1414
|
const _url = new URL(location.href);
|
|
1374
1415
|
const hostname = _url.searchParams.get('hostname') || location.hostname;
|
|
@@ -1385,20 +1426,10 @@ class DDB {
|
|
|
1385
1426
|
if (options.python !== undefined)
|
|
1386
1427
|
this.python = options.python;
|
|
1387
1428
|
}
|
|
1388
|
-
/** message handler */
|
|
1389
|
-
on_message({ type, data }, _this) {
|
|
1390
|
-
switch (type) {
|
|
1391
|
-
case 'print':
|
|
1392
|
-
console.log(data);
|
|
1393
|
-
return;
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
/** resolver, rejector, promise of last rpc */
|
|
1397
|
-
presolver(message) { }
|
|
1398
|
-
prejector(error) { }
|
|
1399
1429
|
get connected() {
|
|
1400
1430
|
return this.websocket?.readyState === WebSocket.OPEN;
|
|
1401
1431
|
}
|
|
1432
|
+
on_message(event) { }
|
|
1402
1433
|
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
|
|
1403
1434
|
- options?:
|
|
1404
1435
|
- url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
|
|
@@ -1426,36 +1457,44 @@ class DDB {
|
|
|
1426
1457
|
await this.rpc('connect', {});
|
|
1427
1458
|
},
|
|
1428
1459
|
on_message: event => {
|
|
1429
|
-
|
|
1430
|
-
try {
|
|
1431
|
-
const message = this.parse_message(buf);
|
|
1432
|
-
this.on_message(message, this);
|
|
1433
|
-
if (message.type === 'print')
|
|
1434
|
-
return;
|
|
1435
|
-
this.presolver(message);
|
|
1436
|
-
}
|
|
1437
|
-
catch (error) {
|
|
1438
|
-
this.prejector(error);
|
|
1439
|
-
}
|
|
1460
|
+
this.on_message(event);
|
|
1440
1461
|
}
|
|
1441
1462
|
});
|
|
1442
|
-
|
|
1443
|
-
|
|
1463
|
+
await this.eval(this.python ?
|
|
1464
|
+
'def pnode_run (nodes, func_name, args, add_node_alias):\n' +
|
|
1444
1465
|
' nargs = size(args)\n' +
|
|
1445
1466
|
' func = funcByName(func_name)\n' +
|
|
1446
1467
|
' \n' +
|
|
1447
|
-
' if
|
|
1468
|
+
' if not nargs:\n' +
|
|
1448
1469
|
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
1449
1470
|
' \n' +
|
|
1450
|
-
' args_partial =
|
|
1451
|
-
' args_partial
|
|
1452
|
-
'
|
|
1471
|
+
' args_partial = [ ]\n' +
|
|
1472
|
+
' args_partial.append(func)\n' +
|
|
1473
|
+
' for a in args:\n' +
|
|
1474
|
+
' args_partial.append(a)\n' +
|
|
1475
|
+
' \n' +
|
|
1453
1476
|
' return pnodeRun(\n' +
|
|
1454
1477
|
' unifiedCall(partial, args_partial),\n' +
|
|
1455
1478
|
' nodes,\n' +
|
|
1456
1479
|
' add_node_alias\n' +
|
|
1457
|
-
' )\n'
|
|
1458
|
-
|
|
1480
|
+
' )\n'
|
|
1481
|
+
:
|
|
1482
|
+
'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
|
|
1483
|
+
' nargs = size(args)\n' +
|
|
1484
|
+
' func = funcByName(func_name)\n' +
|
|
1485
|
+
' \n' +
|
|
1486
|
+
' if (!nargs)\n' +
|
|
1487
|
+
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
1488
|
+
' \n' +
|
|
1489
|
+
' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
|
|
1490
|
+
' args_partial[0] = func\n' +
|
|
1491
|
+
' args_partial[1:] = args\n' +
|
|
1492
|
+
' return pnodeRun(\n' +
|
|
1493
|
+
' unifiedCall(partial, args_partial),\n' +
|
|
1494
|
+
' nodes,\n' +
|
|
1495
|
+
' add_node_alias\n' +
|
|
1496
|
+
' )\n' +
|
|
1497
|
+
'}\n', { urgent: true });
|
|
1459
1498
|
if (this.autologin)
|
|
1460
1499
|
if (this.python)
|
|
1461
1500
|
await this.eval(`login(${this.username.quote('double')}, ${this.password.quote('double')})`, { urgent: true });
|
|
@@ -1496,45 +1535,64 @@ class DDB {
|
|
|
1496
1535
|
disconnect() {
|
|
1497
1536
|
if (this.connected)
|
|
1498
1537
|
this.websocket.close(1000);
|
|
1499
|
-
this.
|
|
1500
|
-
this.
|
|
1501
|
-
this.presult = Promise.resolve(null);
|
|
1538
|
+
this.on_message = () => { };
|
|
1539
|
+
this.promise = Promise.resolve(null);
|
|
1502
1540
|
}
|
|
1503
1541
|
/** rpc through websocket (function/script/variable command)
|
|
1504
1542
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
1505
1543
|
- options:
|
|
1506
1544
|
- urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
|
|
1507
1545
|
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
1508
|
-
-
|
|
1509
|
-
- parse_object?:
|
|
1510
|
-
|
|
1546
|
+
- listener?: 处理本次 rpc 期间的消息 (DdbMessage)
|
|
1547
|
+
- parse_object?: 在本次 rpc 期间设置 parse_object, 结束后恢复原有
|
|
1548
|
+
为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
|
|
1511
1549
|
*/
|
|
1512
|
-
async rpc(type, { script, func, args = [], vars = [], urgent,
|
|
1550
|
+
async rpc(type, { script, func, args = [], vars = [], urgent, listener, parse_object, }) {
|
|
1513
1551
|
if (!this.websocket)
|
|
1514
1552
|
await this.connect();
|
|
1515
1553
|
if (!this.connected)
|
|
1516
1554
|
throw new Error(`${this.url} is already disconnected`);
|
|
1555
|
+
// this 上的当前配置需要在 message 到达后使用,先保存起来
|
|
1556
|
+
const _handlers = [...this.listeners].reverse();
|
|
1517
1557
|
// 临界区:保证多个 rpc 并发时形成 promise 链
|
|
1518
1558
|
// ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
|
|
1519
1559
|
// 违反世界观可能造成:
|
|
1520
1560
|
// 1. 并发多个请求只返回第一个结果(阻塞,需后续请求疏通)
|
|
1521
1561
|
// 2. windows 下 ddb server 返回多个相同的结果
|
|
1522
|
-
const ptail = this.
|
|
1523
|
-
let
|
|
1524
|
-
let
|
|
1525
|
-
const
|
|
1526
|
-
|
|
1527
|
-
|
|
1562
|
+
const ptail = this.promise;
|
|
1563
|
+
let resolve;
|
|
1564
|
+
let reject;
|
|
1565
|
+
const promise = this.promise = new Promise((_resolve, _reject) => {
|
|
1566
|
+
resolve = _resolve;
|
|
1567
|
+
reject = _reject;
|
|
1528
1568
|
});
|
|
1529
1569
|
try {
|
|
1530
1570
|
await ptail;
|
|
1531
1571
|
}
|
|
1532
1572
|
catch { }
|
|
1533
|
-
this.
|
|
1534
|
-
this.
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1573
|
+
// 临界区结束,只有一个 rpc 函数调用运行到这里,可以独占 this.on_message 然后写 WebSocket
|
|
1574
|
+
this.on_message = ({ data: buffer }) => {
|
|
1575
|
+
const buf = new Uint8Array(buffer);
|
|
1576
|
+
if (this.print_message_buffer)
|
|
1577
|
+
console.log(buf);
|
|
1578
|
+
const message = this.parse_message(buf, parse_object);
|
|
1579
|
+
listener?.(message, this);
|
|
1580
|
+
for (const listener of _handlers)
|
|
1581
|
+
listener(message, this);
|
|
1582
|
+
const { type, data } = message;
|
|
1583
|
+
switch (type) {
|
|
1584
|
+
case 'print':
|
|
1585
|
+
if (this.print_message)
|
|
1586
|
+
console.log(data);
|
|
1587
|
+
return;
|
|
1588
|
+
case 'object':
|
|
1589
|
+
resolve(data);
|
|
1590
|
+
return;
|
|
1591
|
+
case 'error':
|
|
1592
|
+
reject(data);
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1538
1596
|
args = this.to_ddbobjs(args);
|
|
1539
1597
|
const command = this.enc.encode((() => {
|
|
1540
1598
|
switch (type) {
|
|
@@ -1555,38 +1613,24 @@ class DDB {
|
|
|
1555
1613
|
return 'connect\n';
|
|
1556
1614
|
}
|
|
1557
1615
|
})());
|
|
1558
|
-
|
|
1616
|
+
this.websocket.send((0, utils_browser_1.concat)([
|
|
1559
1617
|
this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
|
|
1560
1618
|
command,
|
|
1561
1619
|
...args.map((arg) => arg.pack())
|
|
1562
|
-
]);
|
|
1563
|
-
|
|
1564
|
-
const _parse_object = this.parse_object;
|
|
1565
|
-
if (on_message)
|
|
1566
|
-
this.on_message = on_message;
|
|
1567
|
-
if (parse_object !== undefined)
|
|
1568
|
-
this.parse_object = parse_object;
|
|
1569
|
-
try {
|
|
1570
|
-
this.websocket.send(message);
|
|
1571
|
-
const { data } = (await presult);
|
|
1572
|
-
return data;
|
|
1573
|
-
}
|
|
1574
|
-
finally {
|
|
1575
|
-
this.on_message = _on_message;
|
|
1576
|
-
this.parse_object = _parse_object;
|
|
1577
|
-
}
|
|
1620
|
+
]));
|
|
1621
|
+
return promise;
|
|
1578
1622
|
}
|
|
1579
1623
|
/** eval script through websocket (script command)
|
|
1580
1624
|
- script?: Script to execute
|
|
1581
1625
|
- options?: execution options
|
|
1582
1626
|
- urgent?: Urgent flag to ensure that submitted scripts are processed by urgent workers to prevent being blocked by other jobs
|
|
1583
|
-
-
|
|
1627
|
+
- listener?: Process messages during this rpc (DdbMessage)
|
|
1584
1628
|
- parse_object?: Set parse_object during this rpc, and restore the original after the end.
|
|
1585
1629
|
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
1586
1630
|
so as to facilitate subsequent forwarding and serialization
|
|
1587
1631
|
*/
|
|
1588
|
-
async eval(script, { urgent,
|
|
1589
|
-
return this.rpc('script', { script, urgent,
|
|
1632
|
+
async eval(script, { urgent, listener, parse_object, } = {}) {
|
|
1633
|
+
return this.rpc('script', { script, urgent, listener, parse_object });
|
|
1590
1634
|
}
|
|
1591
1635
|
/** call function through websocket (function command)
|
|
1592
1636
|
- func: function name
|
|
@@ -1597,14 +1641,12 @@ class DDB {
|
|
|
1597
1641
|
- nodes?: When setting multiple node aliases, send them to the corresponding multiple nodes in the cluster for execution (using the pnodeRun method in DolphinDB)
|
|
1598
1642
|
- func_type?: It must be passed when setting the node parameter, the function type needs to be specified, and it is not passed in other cases
|
|
1599
1643
|
- add_node_alias?: Select to pass when setting the nodes parameter, otherwise not pass
|
|
1600
|
-
-
|
|
1644
|
+
- listener?: Process messages during this rpc (DdbMessage)
|
|
1601
1645
|
- parse_object?: Set parse_object during this rpc, and restore the original after the end.
|
|
1602
1646
|
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
1603
1647
|
so as to facilitate subsequent forwarding and serialization
|
|
1604
1648
|
*/
|
|
1605
|
-
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias,
|
|
1606
|
-
if (this.python)
|
|
1607
|
-
throw new Error('call doesn\'t support python session yet');
|
|
1649
|
+
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, } = {}) {
|
|
1608
1650
|
if (node) {
|
|
1609
1651
|
if (typeof func_type === 'undefined')
|
|
1610
1652
|
throw new Error('指定 node 时必须设置 func_type');
|
|
@@ -1634,7 +1676,7 @@ class DDB {
|
|
|
1634
1676
|
func,
|
|
1635
1677
|
args,
|
|
1636
1678
|
urgent,
|
|
1637
|
-
|
|
1679
|
+
listener,
|
|
1638
1680
|
parse_object
|
|
1639
1681
|
});
|
|
1640
1682
|
}
|
|
@@ -1643,10 +1685,10 @@ class DDB {
|
|
|
1643
1685
|
/** Uploaded variables' name */
|
|
1644
1686
|
vars,
|
|
1645
1687
|
/** Uploaded variables' value */
|
|
1646
|
-
args, {
|
|
1688
|
+
args, { listener, parse_object, } = {}) {
|
|
1647
1689
|
if (!args.length || args.length !== vars.length)
|
|
1648
1690
|
throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
|
|
1649
|
-
return this.rpc('variable', { vars, args,
|
|
1691
|
+
return this.rpc('variable', { vars, args, listener, parse_object });
|
|
1650
1692
|
}
|
|
1651
1693
|
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
1652
1694
|
parse_message(buf, parse_object = this.parse_object) {
|
|
@@ -1679,12 +1721,17 @@ class DDB {
|
|
|
1679
1721
|
/** 'OK' 表示成功,其它文本表示失败 */
|
|
1680
1722
|
const message = this.dec.decode(buf.subarray(i_ls_1, i_lf_1));
|
|
1681
1723
|
if (message !== 'OK')
|
|
1682
|
-
|
|
1724
|
+
return {
|
|
1725
|
+
type: 'error',
|
|
1726
|
+
data: new Error(message)
|
|
1727
|
+
};
|
|
1683
1728
|
const buf_obj = buf.subarray(i_lf_1 + 1);
|
|
1729
|
+
if (this.print_object_buffer)
|
|
1730
|
+
console.log(buf_obj);
|
|
1684
1731
|
return {
|
|
1685
1732
|
type: 'object',
|
|
1686
1733
|
data: parse_object ?
|
|
1687
|
-
|
|
1734
|
+
DdbObj.parse(buf_obj, this.le)
|
|
1688
1735
|
:
|
|
1689
1736
|
new DdbObj({
|
|
1690
1737
|
form: DdbForm.scalar,
|