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 CHANGED
@@ -75,7 +75,12 @@ export interface DdbArrayVectorBlock {
75
75
  lengths: Uint8Array | Uint16Array | Uint32Array;
76
76
  data: DdbVectorValue;
77
77
  }
78
- export declare type DdbValue = null | boolean | number | [number, number] | bigint | string | string[] | Uint8Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbFunctionDefValue | DdbSymbolExtendedValue | DdbArrayVectorBlock[];
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
- /** message handler */
276
- on_message({ type, data }: DdbMessage, _this: DDB): void;
277
- /** resolver, rejector, promise of last rpc */
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
- // 使用 HTTPS 加密
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
- - on_message?: 在该次 rpc 期间设置 message handler, 结束后恢复原有
354
- - parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
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, on_message, parse_object, }: {
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
- on_message?: DDB['on_message'];
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
- - on_message?: Set the message handler during this rpc, and restore the original after the end
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, on_message, parse_object, }?: {
378
+ eval<T extends DdbObj>(script: string, { urgent, listener, parse_object, }?: {
376
379
  urgent?: boolean;
377
- on_message?: DDB['on_message'];
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
- - on_message?: Set the message handler during this rpc, and restore the original after the end
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, on_message, parse_object, }?: {
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
- on_message?: DDB['on_message'];
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)[], { on_message, parse_object, }?: {
409
- on_message?: DDB['on_message'];
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 declare type DdbMessage = DdbPrintMessage | DdbObjectMessage;
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
- // matrix([
205
+ // rename!(
206
+ // 1..9$3:3,
206
207
  // [1, 2, 3],
207
- // [3, 2, 1]
208
- // ])
209
- // <Buffer 00 has_row_label = , has_col_label =
210
- // 04 03 type = int, form = matrix
211
- // 03 00 00 00 02 00 00 00 rows = 3, cols = 2
212
- // 01 00 00 00 02 00 00 00 03 00 00 00 03 00 00 00 02 00 00 00 01 00 00 00>
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
- if (has_row_labels || has_col_labels)
218
- throw new Error('matrix 暂不支持 row labels 和 col labels');
219
- const datatype = buf_data[1];
220
- const rows = dv.getUint32(3, le);
221
- const cols = dv.getUint32(7, le);
222
- const [len_items, value] = this.parse_vector_items(buf_data.subarray(11), le, datatype, rows * cols // 假设小于 2**32
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 + 11 + len_items,
251
+ length: i_data + offset,
229
252
  rows,
230
253
  cols,
231
- datatype,
232
- value,
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(new ArrayBuffer(2));
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(0, this.datatype, this.form),
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(value, this.datatype, this.rows * this.cols)
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.datatype]}>[${this.rows} rows][${this.cols} cols]`;
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
- row[name] = Boolean(value[i]);
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] = value.subarray(16 * i, 16 * (i + 1));
935
+ row[name] = values.subarray(16 * i, 16 * (i + 1));
900
936
  break;
901
937
  case DdbType.symbol_extended: {
902
- const { base, data } = value;
938
+ const { base, data } = values;
903
939
  row[name] = base[data[i]];
904
940
  break;
905
941
  }
906
942
  default:
907
- row[name] = value[i];
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
- // 使用 HTTPS 加密
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
- this.presult = Promise.resolve(null);
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
- const buf = new Uint8Array(event.data);
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
- if (!this.python)
1443
- await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
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 (!nargs)\n' +
1468
+ ' if not nargs:\n' +
1448
1469
  ' return pnodeRun(func, nodes, add_node_alias)\n' +
1449
1470
  ' \n' +
1450
- ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
1451
- ' args_partial[0] = func\n' +
1452
- ' args_partial[1:] = args\n' +
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
- '}\n', { urgent: true });
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.presolver = buf => { };
1500
- this.prejector = error => { };
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
- - on_message?: 在该次 rpc 期间设置 message handler, 结束后恢复原有
1509
- - parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
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, on_message, parse_object, }) {
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.presult;
1523
- let presolver;
1524
- let prejector;
1525
- const presult = this.presult = new Promise((resolve, reject) => {
1526
- presolver = resolve;
1527
- prejector = reject;
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.presolver = presolver;
1534
- this.prejector = prejector;
1535
- // 临界区结束,只有一个 rpc 请求可以写 WebSocket
1536
- if (urgent && type !== 'script' && type !== 'function')
1537
- throw new Error('urgent 只适用于 script 和 funciton');
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
- const message = (0, utils_browser_1.concat)([
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
- const _on_message = this.on_message;
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
- - on_message?: Set the message handler during this rpc, and restore the original after the end
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, on_message, parse_object, } = {}) {
1589
- return this.rpc('script', { script, urgent, on_message, parse_object });
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
- - on_message?: Set the message handler during this rpc, and restore the original after the end
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, on_message, parse_object, } = {}) {
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
- on_message,
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, { on_message, parse_object, } = {}) {
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, on_message, parse_object });
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
- throw new Error(message);
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
- Object.assign(DdbObj.parse(buf_obj, this.le), { buffer: buf_obj })
1734
+ DdbObj.parse(buf_obj, this.le)
1688
1735
  :
1689
1736
  new DdbObj({
1690
1737
  form: DdbForm.scalar,