dolphindb 0.0.4 → 0.0.7

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/index.d.ts CHANGED
@@ -67,16 +67,24 @@ export interface DdbFunctionDefValue {
67
67
  export interface DdbSymbolExtendedValue {
68
68
  base_id: number;
69
69
  base: string[];
70
- value: Uint32Array;
70
+ data: Uint32Array;
71
71
  }
72
- export declare type DdbValue = null | boolean | number | [number, number] | bigint | string | string[] | Uint8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbFunctionDefValue | DdbSymbolExtendedValue;
73
- export declare type DdbVectorValue = string | string[] | Uint8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbSymbolExtendedValue;
72
+ export interface DdbArrayVectorBlock {
73
+ unit: 1 | 2 | 4;
74
+ rows: number;
75
+ lengths: Uint8Array | Uint16Array | Uint32Array;
76
+ data: DdbVectorValue;
77
+ }
78
+ export declare type DdbValue = null | boolean | number | [number, number] | bigint | string | string[] | Uint8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbFunctionDefValue | DdbSymbolExtendedValue | DdbArrayVectorBlock[];
79
+ export declare type DdbVectorValue = string | string[] | Uint8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | Uint8Array[] | DdbObj[] | DdbSymbolExtendedValue | DdbArrayVectorBlock[];
74
80
  export declare const nulls: {
75
81
  readonly char: "€";
76
82
  readonly int16: -32768;
77
83
  readonly int32: -2147483648;
78
84
  readonly int64: -9223372036854775808n;
79
85
  };
86
+ export declare const timezone_offset: number;
87
+ /** 可以表示所有 DolphinDB 数据库中的数据类型 */
80
88
  export declare class DdbObj<T extends DdbValue = DdbValue> {
81
89
  static dec: TextDecoder;
82
90
  static enc: TextEncoder;
@@ -129,6 +137,7 @@ export declare class DdbObj<T extends DdbValue = DdbValue> {
129
137
  pack(): Uint8Array;
130
138
  static pack_vector_body(value: DdbVectorValue, type: DdbType, length: number): ArrayBufferView[];
131
139
  [inspect.custom](): string;
140
+ to_dict<T = Record<string, any>>(): T;
132
141
  }
133
142
  export declare class DdbVoid extends DdbObj<undefined> {
134
143
  constructor();
@@ -166,44 +175,85 @@ export declare class DdbPair extends DdbObj<Int32Array> {
166
175
  export declare class DdbFunction extends DdbObj<DdbFunctionDefValue> {
167
176
  constructor(name: string, type: DdbFunctionType);
168
177
  }
178
+ export declare function date2str(date: number): string;
179
+ export declare function timestamp2str(timestamp: bigint): string;
169
180
  export declare class DDB {
170
- port: number;
171
181
  /** 当前的 session id (http 或 tcp) */
172
182
  sid: string;
173
183
  /** utf-8 text decoder */
174
184
  dec: TextDecoder;
175
185
  enc: TextEncoder;
176
186
  print_buffer: boolean;
177
- ws_url: string;
178
- ws: WebSocket;
187
+ /** DolphinDB WebSocket URL
188
+ e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
189
+ */
190
+ url: string;
191
+ websocket: WebSocket;
179
192
  /** little endian (server) */
180
193
  le: boolean;
181
194
  /** little endian (client) */
182
195
  static le_client: boolean;
196
+ /** python session flag (2048) */
197
+ python: boolean;
198
+ message_hook: (message: Uint8Array) => any;
199
+ /** print message handler */
200
+ printer(message: string): void;
183
201
  /** resolver, rejector, promise of last rpc */
184
202
  presolver(buf: Uint8Array): void;
185
203
  prejector(error: Error): void;
186
204
  presult: Promise<Uint8Array>;
187
- constructor(ws_url: string);
188
- /** 连接到 DolphinDB Server */
189
- connect({ ws_url, login, username, password, }?: {
190
- /** 默认使用实例初始化时传入的 WebSocket 链接地址 */
191
- ws_url?: string;
192
- /** 是否在建立连接后自动登录,默认 true */
205
+ /**
206
+ Initialize an instance of DolphinDB Client using the WebSocket URL
207
+ (without establishing an actual network connection)
208
+ @example
209
+ let ddb = new DDB('ws://127.0.0.1:8848')
210
+ let ddb_secure = new DDB('wss://dolphindb.com')
211
+ */
212
+ constructor(url?: string);
213
+ /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
214
+ connect({ url, login, username, password, python, }?: {
215
+ /** By default, the WebSocket URL passed in when the instance is initialized is used */
216
+ url?: string;
217
+ /** Whether to automatically log in after the connection is established, the default is true */
193
218
  login?: boolean;
194
- /** DolphinDB 登录用户名 */
219
+ /** DolphinDB username */
195
220
  username?: string;
196
- /** DolphinDB 登录密码 */
221
+ /** DolphinDB password */
197
222
  password?: string;
223
+ /** set python session flag */
224
+ python?: boolean;
198
225
  }): Promise<void>;
226
+ get_rpc_options({ urgent, secondary, async: _async, pickle, clear, api, compress, cancellable, priority, parallelism, root_id, limit, }?: {
227
+ urgent?: boolean;
228
+ /** API 提交的任务, secondary 必须为 false */
229
+ secondary?: boolean;
230
+ /** 是否异步任务(不返回结果) */
231
+ async?: boolean;
232
+ /** 让服务端以 pickle 协议返回数据 */
233
+ pickle?: boolean;
234
+ /** 本次任务完成后 clear session memory */
235
+ clear?: boolean;
236
+ /** 是否为 api client */
237
+ api?: boolean;
238
+ compress?: boolean;
239
+ /** 任务是否可以取消 */
240
+ cancellable?: boolean;
241
+ priority?: number;
242
+ /** `8` 0 ~ 64, 指定本任务并行度 */
243
+ parallelism?: number;
244
+ /** 根任务编号,内部使用,API中固定为空 */
245
+ root_id?: string;
246
+ /** 指定分块返回的块大小 */
247
+ limit?: boolean;
248
+ }): string;
199
249
  disconnect(): void;
200
- /** rpc through websocket (function command)
250
+ /** rpc through websocket (function/script/variable command)
201
251
  - type: API 类型: 'script' | 'function' | 'variable'
202
252
  - options:
203
253
  - urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
204
254
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
205
255
  */
206
- rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable', { script, func, args, vars, urgent, }: {
256
+ rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable' | 'connect', { script, func, args, vars, urgent, }: {
207
257
  script?: string;
208
258
  func?: string;
209
259
  args?: (DdbObj | string | boolean)[];
@@ -216,14 +266,14 @@ export declare class DDB {
216
266
  script: string,
217
267
  /** 执行选项 */
218
268
  { urgent }?: {
219
- /** 紧急 flag,使用 urgent worker 处理,防止被其它作业阻塞 */
269
+ /** 紧急 flag,确保提交的脚本使用 urgent worker 处理,防止被其它作业阻塞 */
220
270
  urgent?: boolean;
221
271
  }): Promise<T>;
222
272
  /** call function through websocket (function command)
223
273
  - func: 函数名
224
274
  - args?: `[ ]` 调用参数 (传入的原生 string 和 boolean 会被自动转换为 DdbObj<string> 和 DdbObj<boolean>)
225
275
  - options?: 调用选项
226
- - urgent?: 紧急 flag,使用 urgent worker 处理,防止被其它作业阻塞
276
+ - urgent?: 紧急 flag。使用 urgent worker 执行,防止被其它作业阻塞
227
277
  - node?: 设置结点 alias 时发送到集群中对应的结点执行 (使用 DolphinDB 中的 rpc 方法)
228
278
  - nodes?: 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法)
229
279
  - func_type?: 设置 node 参数时必传,需指定函数类型,其它情况下不传
@@ -238,12 +288,18 @@ export declare class DDB {
238
288
  }): Promise<T>;
239
289
  /** upload variable through websocket (variable command) */
240
290
  upload(
241
- /** 上传的变量名 */
291
+ /** Uploaded variables' name */
242
292
  vars: string[],
243
- /** 上传的变量值 */
293
+ /** Uploaded variables' value */
244
294
  args: (DdbObj | string | boolean)[]): Promise<DdbObj<DdbValue>>;
245
295
  /** 解析服务端响应报文,返回去掉 header 的 data buf */
246
- parse_message(buf: Uint8Array): Uint8Array;
296
+ parse_message(buf: Uint8Array): {
297
+ type: "message";
298
+ data: string;
299
+ } | {
300
+ type: "object";
301
+ data: Uint8Array;
302
+ };
247
303
  /** 自动转换 js string, boolean 为 DdbObj */
248
304
  to_ddbobj(value: DdbObj | string | boolean): DdbObj;
249
305
  /** 转换 js 数组为 DdbObj[] (in place, 会修改原数组) */
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DDB = exports.DdbFunction = exports.DdbPair = exports.DdbVectorAny = exports.DdbVectorDouble = exports.DdbVectorString = exports.DdbVectorInt = exports.DdbDouble = exports.DdbLong = exports.DdbString = exports.DdbInt = exports.DdbBool = exports.DdbVoid = exports.DdbObj = exports.nulls = exports.DdbFunctionType = exports.ddb_sizes = exports.DdbType = exports.DdbForm = void 0;
3
+ exports.DDB = exports.timestamp2str = exports.date2str = exports.DdbFunction = exports.DdbPair = exports.DdbVectorAny = exports.DdbVectorDouble = exports.DdbVectorString = exports.DdbVectorInt = exports.DdbDouble = exports.DdbLong = exports.DdbString = exports.DdbInt = exports.DdbBool = exports.DdbVoid = exports.DdbObj = exports.timezone_offset = exports.nulls = exports.DdbFunctionType = exports.ddb_sizes = exports.DdbType = exports.DdbForm = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const dayjs_1 = (0, tslib_1.__importDefault)(require("dayjs"));
4
6
  const ws_1 = require("ws");
5
7
  const utils_js_1 = require("xshell/utils.js");
6
8
  var DdbForm;
@@ -109,6 +111,8 @@ exports.nulls = {
109
111
  int32: -2147483648,
110
112
  int64: -0x8000000000000000n, // -922_3372_0368_5477_5808
111
113
  };
114
+ exports.timezone_offset = 1000 * 60 * new Date().getTimezoneOffset();
115
+ /** 可以表示所有 DolphinDB 数据库中的数据类型 */
112
116
  class DdbObj {
113
117
  constructor(data) {
114
118
  /** 是否为小端 (little endian) */
@@ -367,16 +371,86 @@ class DdbObj {
367
371
  static parse_vector(buf, le, type) {
368
372
  const dv = new DataView(buf.buffer, buf.byteOffset);
369
373
  const rows = dv.getUint32(0, le);
370
- const i_items_start = 8;
371
- const [len_items, value] = this.parse_vector_items(buf.subarray(i_items_start), le, type, rows);
374
+ let i_items_start = 8;
375
+ if (type < 64 || type >= 128) {
376
+ const [len_items, value] = this.parse_vector_items(buf.subarray(i_items_start), le, type, rows);
377
+ return new this({
378
+ le,
379
+ form: DdbForm.vector,
380
+ type,
381
+ length: i_items_start + len_items,
382
+ cols: 1,
383
+ rows,
384
+ value,
385
+ });
386
+ }
387
+ // array vector
388
+ // av = array(INT[], 0, 3)
389
+ // append!(av, [1..4])
390
+ // append!(av, [1..70000])
391
+ // av
392
+ // <Buffer 44 01 type = array vector, form = vector
393
+ // 02 00 00 00 74 11 01 00 rows = 2, cols = 70004 (0x011174)
394
+ // block 0
395
+ // 01 00 block.rows = 1
396
+ // 04 block.unit = 4
397
+ // 00 reserved
398
+ // 04 00 00 00 block.lengths = [4]
399
+ // 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 block.data
400
+ // block 1
401
+ // 01 00 block.rows = 1
402
+ // 04 block.unit = 4
403
+ // 00 reserved
404
+ // 70 11 01 00 block.lengths = [70000 (0x00011170)]
405
+ // 01 00 00 00 02 00 00 00 ... 279992 more bytes> block.data
406
+ const cols = dv.getUint32(4, le);
407
+ let blocks = [];
408
+ let i_block_start = i_items_start;
409
+ // 解析一个 block
410
+ for (let i_row = 0; i_row < rows;) {
411
+ /** 对应 array vector 中元素个数 */
412
+ const rows = dv.getUint16(i_block_start, le);
413
+ /** 每个 length 占用的字节数 */
414
+ const unit = dv.getUint8(i_block_start + 2);
415
+ /** array vector 每个元素的子元素长度 */
416
+ let lengths;
417
+ const i_lengths_start = i_block_start + 4;
418
+ const i_data_start = i_lengths_start + rows * unit;
419
+ const lengths_buf = buf.slice(i_lengths_start, i_data_start);
420
+ switch (unit) {
421
+ case 1:
422
+ lengths = lengths_buf;
423
+ break;
424
+ case 2:
425
+ lengths = new Uint16Array(lengths_buf.buffer);
426
+ break;
427
+ case 4:
428
+ lengths = new Uint32Array(lengths_buf.buffer);
429
+ break;
430
+ default:
431
+ throw new Error(`array vector 存在非法 unit = ${unit}`);
432
+ }
433
+ let total_length = 0;
434
+ for (const x of lengths)
435
+ total_length += x;
436
+ const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
437
+ blocks.push({
438
+ unit,
439
+ rows,
440
+ lengths,
441
+ data
442
+ });
443
+ i_block_start = i_data_start + len_items;
444
+ i_row += rows;
445
+ }
372
446
  return new this({
373
447
  le,
374
448
  form: DdbForm.vector,
375
449
  type,
376
- length: i_items_start + len_items,
377
- cols: 1,
450
+ length: i_block_start,
451
+ cols,
378
452
  rows,
379
- value,
453
+ value: blocks
380
454
  });
381
455
  }
382
456
  /** 有可能没有字节对齐,不能直接使用原有 message 的 arraybuffer, 统一复制出来,让原有 arraybuffer 被回收掉比较好 */
@@ -457,13 +531,13 @@ class DdbObj {
457
531
  }
458
532
  const value_start = 8 + base_length;
459
533
  const value_end = value_start + length * 4;
460
- const value = new Uint32Array(buf.buffer.slice(buf.byteOffset + value_start, buf.byteOffset + value_end));
534
+ const data = new Uint32Array(buf.buffer.slice(buf.byteOffset + value_start, buf.byteOffset + value_end));
461
535
  return [
462
536
  value_end,
463
537
  {
464
538
  base_id,
465
539
  base,
466
- value
540
+ data
467
541
  }
468
542
  ];
469
543
  }
@@ -588,11 +662,24 @@ class DdbObj {
588
662
  return [Float64Array.from(this.value)];
589
663
  case DdbType.duration:
590
664
  return [value];
665
+ case DdbType.handle:
666
+ throw new Error('DolphinDB Server 不支持 handle 的反序列化');
591
667
  default:
592
668
  throw new Error(`${DdbType[type]} 暂时不支持序列化`);
593
669
  }
594
670
  case DdbForm.vector:
595
671
  case DdbForm.pair:
672
+ // pack array vector
673
+ if (form === DdbForm.vector && 64 <= type && type < 128)
674
+ return [
675
+ Uint32Array.of(this.rows, this.cols),
676
+ ...this.value.map(block => ([
677
+ Uint16Array.of(block.rows),
678
+ Uint8Array.of(block.unit, 0),
679
+ block.lengths,
680
+ block.data
681
+ ])).flat()
682
+ ];
596
683
  return [
597
684
  Uint32Array.of(this.rows, 1),
598
685
  ...DdbObj.pack_vector_body(value, type, this.rows)
@@ -708,6 +795,14 @@ class DdbObj {
708
795
  bufs[i] = value[i].pack();
709
796
  return bufs;
710
797
  }
798
+ case DdbType.symbol_extended: {
799
+ const { base_id, base, data } = value;
800
+ return [
801
+ Uint32Array.of(base_id, base.length),
802
+ ...this.pack_vector_body(base, DdbType.string, base.length),
803
+ data
804
+ ];
805
+ }
711
806
  default:
712
807
  throw new Error(`vector ${DdbType[type]} 暂不支持序列化`);
713
808
  }
@@ -721,6 +816,8 @@ class DdbObj {
721
816
  return `functiondef<${DdbFunctionType[this.value.type]}>`;
722
817
  return tname;
723
818
  case DdbForm.vector:
819
+ if (64 <= this.type && this.type < 128)
820
+ return `${DdbType[this.type - 64]}[][${this.rows}]`;
724
821
  return `${tname}[${this.rows}]`;
725
822
  case DdbForm.pair:
726
823
  return `pair<${tname}>`;
@@ -747,6 +844,15 @@ class DdbObj {
747
844
  })();
748
845
  return `${type.blue}(${this.name ? `${(0, utils_js_1.inspect)(this.name)}, ` : ''}${data})`;
749
846
  }
847
+ to_dict() {
848
+ if (this.form !== DdbForm.dict)
849
+ throw new Error('this.form 不是 dict, 不能转换为 Object');
850
+ const [{ value: keys }, { value: values }] = this.value;
851
+ let obj = {};
852
+ for (let i = 0; i < this.rows; i++)
853
+ obj[keys[i]] = values[i].value;
854
+ return obj;
855
+ }
750
856
  }
751
857
  exports.DdbObj = DdbObj;
752
858
  DdbObj.dec = new TextDecoder('utf-8');
@@ -896,93 +1002,159 @@ class DdbFunction extends DdbObj {
896
1002
  }
897
1003
  }
898
1004
  exports.DdbFunction = DdbFunction;
1005
+ function date2str(date) {
1006
+ return date === exports.nulls.int32 ?
1007
+ ''
1008
+ :
1009
+ (0, dayjs_1.default)(exports.timezone_offset + 1000 * 3600 * 24 * date).format('YYYY.MM.DD');
1010
+ }
1011
+ exports.date2str = date2str;
1012
+ function timestamp2str(timestamp) {
1013
+ return timestamp === exports.nulls.int64 ?
1014
+ ''
1015
+ :
1016
+ (0, dayjs_1.default)(exports.timezone_offset + Number(timestamp)).format('YYYY.MM.DD HH:mm:ss.SSS');
1017
+ }
1018
+ exports.timestamp2str = timestamp2str;
899
1019
  class DDB {
900
- constructor(ws_url) {
901
- this.port = 8848;
1020
+ /**
1021
+ Initialize an instance of DolphinDB Client using the WebSocket URL
1022
+ (without establishing an actual network connection)
1023
+ @example
1024
+ let ddb = new DDB('ws://127.0.0.1:8848')
1025
+ let ddb_secure = new DDB('wss://dolphindb.com')
1026
+ */
1027
+ constructor(url) {
902
1028
  /** 当前的 session id (http 或 tcp) */
903
1029
  this.sid = '0';
904
1030
  /** utf-8 text decoder */
905
1031
  this.dec = new TextDecoder('utf-8');
906
1032
  this.enc = new TextEncoder();
907
1033
  this.print_buffer = false;
908
- this.ws = null;
1034
+ this.websocket = null;
909
1035
  /** little endian (server) */
910
1036
  this.le = true;
1037
+ /** python session flag (2048) */
1038
+ this.python = false;
1039
+ this.message_hook = null;
911
1040
  this.presult = Promise.resolve(null);
912
- this.ws_url = ws_url;
1041
+ this.url = url;
1042
+ }
1043
+ /** print message handler */
1044
+ printer(message) {
1045
+ console.log(message);
913
1046
  }
914
1047
  /** resolver, rejector, promise of last rpc */
915
1048
  presolver(buf) { }
916
1049
  prejector(error) { }
917
- /** 连接到 DolphinDB Server */
918
- async connect({ ws_url = this.ws_url, login = true, username = 'admin', password = '123456', } = {}) {
919
- this.ws_url = ws_url;
920
- if (this.ws?.readyState === ws_1.WebSocket.OPEN)
1050
+ /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
1051
+ async connect({ url = this.url, login = true, username = 'admin', password = '123456', python = false, } = {}) {
1052
+ this.url = url;
1053
+ this.python = python;
1054
+ if (this.websocket?.readyState === ws_1.WebSocket.OPEN)
921
1055
  this.disconnect();
922
- let ws = new ws_1.WebSocket(ws_url, [], {
1056
+ let websocket = new ws_1.WebSocket(url, python ? ['python'] : [], {
923
1057
  maxPayload: 2 ** 33 // 8 GB
924
1058
  });
925
- this.ws = ws;
926
- ws.addEventListener('open', ev => {
927
- console.log(`${this.ws_url} opened`);
928
- ws.send(`API ${this.sid} 8\n` +
929
- 'connect\n');
930
- });
931
- ws.addEventListener('close', ev => {
932
- console.log(`${this.ws_url} closed with code = ${ev.code}, reason = '${ev.reason}'`);
933
- });
934
- ws.addEventListener('error', ev => {
935
- console.log(`${this.ws_url} errored`, ev);
936
- });
937
- // 为首个 connect 响应报文初始化 presult 链表头结点
938
- this.presult = new Promise((resolve, reject) => {
939
- this.presolver = resolve;
940
- this.prejector = reject;
941
- });
942
- ws.addEventListener('message', ({ data: buf }) => {
943
- try {
944
- this.presolver(this.parse_message(
945
- // node buffer 转 Uint8Array
946
- new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)));
947
- }
948
- catch (error) {
949
- this.prejector(error);
950
- }
1059
+ // https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
1060
+ websocket.binaryType = 'arraybuffer';
1061
+ this.websocket = websocket;
1062
+ await new Promise((resolve, reject) => {
1063
+ websocket.addEventListener('open', async (event) => {
1064
+ console.log(`${websocket.url} opened`);
1065
+ await this.rpc('connect', {});
1066
+ resolve();
1067
+ });
1068
+ websocket.addEventListener('close', event => {
1069
+ console.log(`${websocket.url} closed with code = ${event.code}, reason = '${event.reason}'`);
1070
+ });
1071
+ websocket.addEventListener('error', event => {
1072
+ const message = `${websocket.url} errored`;
1073
+ console.error(message, event);
1074
+ reject(Object.assign(new Error(message), { event }));
1075
+ });
1076
+ websocket.addEventListener('message', event => {
1077
+ const buf = new Uint8Array(event.data);
1078
+ if (this.message_hook)
1079
+ this.message_hook(buf);
1080
+ try {
1081
+ const { type, data } = this.parse_message(buf);
1082
+ if (type === 'message') {
1083
+ this.printer(data);
1084
+ return;
1085
+ }
1086
+ this.presolver(data);
1087
+ }
1088
+ catch (error) {
1089
+ this.prejector(error);
1090
+ }
1091
+ });
951
1092
  });
952
- await this.presult;
953
- await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
954
- ' nargs = size(args)\n' +
955
- ' func = funcByName(func_name)\n' +
956
- ' \n' +
957
- ' if (!nargs)\n' +
958
- ' return pnodeRun(func, nodes, add_node_alias)\n' +
959
- ' \n' +
960
- ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
961
- ' args_partial[0] = func\n' +
962
- ' args_partial[1:] = args\n' +
963
- ' return pnodeRun(\n' +
964
- ' unifiedCall(partial, args_partial),\n' +
965
- ' nodes,\n' +
966
- ' add_node_alias\n' +
967
- ' )\n' +
968
- '}\n', { urgent: true });
1093
+ if (!this.python)
1094
+ await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
1095
+ ' nargs = size(args)\n' +
1096
+ ' func = funcByName(func_name)\n' +
1097
+ ' \n' +
1098
+ ' if (!nargs)\n' +
1099
+ ' return pnodeRun(func, nodes, add_node_alias)\n' +
1100
+ ' \n' +
1101
+ ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
1102
+ ' args_partial[0] = func\n' +
1103
+ ' args_partial[1:] = args\n' +
1104
+ ' return pnodeRun(\n' +
1105
+ ' unifiedCall(partial, args_partial),\n' +
1106
+ ' nodes,\n' +
1107
+ ' add_node_alias\n' +
1108
+ ' )\n' +
1109
+ '}\n', { urgent: true });
969
1110
  if (login)
970
1111
  await this.call('login', [username, password], { urgent: true });
971
1112
  }
1113
+ get_rpc_options({ urgent = false, secondary = false, async: _async = false, pickle = false, clear = false, api = false, compress = false, cancellable = true, priority = urgent ? 8 : 4, parallelism = 8, root_id = '', limit, } = {}) {
1114
+ let flag = 0;
1115
+ if (urgent)
1116
+ flag += 1;
1117
+ if (secondary)
1118
+ flag += 2;
1119
+ if (_async)
1120
+ flag += 4;
1121
+ if (pickle)
1122
+ flag += 8;
1123
+ if (clear)
1124
+ flag += 16;
1125
+ if (api)
1126
+ flag += 32;
1127
+ if (compress)
1128
+ flag += 64;
1129
+ // python session
1130
+ if (this.python)
1131
+ flag += 2048;
1132
+ const options = [
1133
+ flag,
1134
+ cancellable ? 1 : 0,
1135
+ priority,
1136
+ parallelism,
1137
+ ...limit ? [
1138
+ root_id,
1139
+ limit,
1140
+ ] : [],
1141
+ ];
1142
+ return `/ ${options.join('_')}`;
1143
+ }
972
1144
  disconnect() {
973
- this.ws?.close(1000);
1145
+ this.websocket?.close(1000);
974
1146
  }
975
- /** rpc through websocket (function command)
1147
+ /** rpc through websocket (function/script/variable command)
976
1148
  - type: API 类型: 'script' | 'function' | 'variable'
977
1149
  - options:
978
1150
  - urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
979
1151
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
980
1152
  */
981
1153
  async rpc(type, { script, func, args = [], vars = [], urgent, }) {
982
- if (!this.ws)
1154
+ if (!this.websocket)
983
1155
  await this.connect();
984
- if (this.ws.readyState !== ws_1.WebSocket.OPEN)
985
- throw new Error('ws 连接已断开');
1156
+ if (this.websocket.readyState !== ws_1.WebSocket.OPEN)
1157
+ throw new Error(`${this.url} is already disconnected`);
986
1158
  // 临界区:保证多个 rpc 并发时形成 promise 链
987
1159
  // ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
988
1160
  // 违反世界观可能造成:
@@ -1020,14 +1192,16 @@ class DDB {
1020
1192
  `${vars.join(',')}\n` +
1021
1193
  `${vars.length}\n` +
1022
1194
  `${Number(DDB.le_client)}\n`;
1195
+ case 'connect':
1196
+ return 'connect\n';
1023
1197
  }
1024
1198
  })());
1025
1199
  const message = (0, utils_js_1.concat)([
1026
- this.enc.encode(`API ${this.sid} ${command.length}${urgent ? ` / 1_1_8_8` : ''}\n`),
1200
+ this.enc.encode(`API2 ${this.sid} ${command.length}${this.get_rpc_options({ urgent })}\n`),
1027
1201
  command,
1028
1202
  ...args.map((arg) => arg.pack())
1029
1203
  ]);
1030
- this.ws.send(message);
1204
+ this.websocket.send(message);
1031
1205
  const buf_data = await presult;
1032
1206
  if (this.print_buffer)
1033
1207
  console.log((0, utils_js_1.typed_array_to_buffer)(buf_data));
@@ -1047,13 +1221,15 @@ class DDB {
1047
1221
  - func: 函数名
1048
1222
  - args?: `[ ]` 调用参数 (传入的原生 string 和 boolean 会被自动转换为 DdbObj<string> 和 DdbObj<boolean>)
1049
1223
  - options?: 调用选项
1050
- - urgent?: 紧急 flag,使用 urgent worker 处理,防止被其它作业阻塞
1224
+ - urgent?: 紧急 flag。使用 urgent worker 执行,防止被其它作业阻塞
1051
1225
  - node?: 设置结点 alias 时发送到集群中对应的结点执行 (使用 DolphinDB 中的 rpc 方法)
1052
1226
  - nodes?: 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法)
1053
1227
  - func_type?: 设置 node 参数时必传,需指定函数类型,其它情况下不传
1054
1228
  - add_node_alias?: 设置 nodes 参数时选传,其它情况不传
1055
1229
  */
1056
1230
  async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias } = {}) {
1231
+ if (this.python)
1232
+ throw new Error('call doesn\'t support python session yet');
1057
1233
  if (node) {
1058
1234
  if (typeof func_type === 'undefined')
1059
1235
  throw new Error('指定 node 时必须设置 func_type');
@@ -1069,7 +1245,13 @@ class DDB {
1069
1245
  new DdbVectorString(nodes),
1070
1246
  func,
1071
1247
  new DdbVectorAny(this.to_ddbobjs(args)),
1072
- ...typeof add_node_alias === 'undefined' ? [] : [add_node_alias]
1248
+ ...(() => {
1249
+ if (typeof add_node_alias !== 'undefined')
1250
+ return [add_node_alias];
1251
+ if (this.python)
1252
+ return [true];
1253
+ return [];
1254
+ })()
1073
1255
  ];
1074
1256
  func = 'pnode_run';
1075
1257
  }
@@ -1081,9 +1263,9 @@ class DDB {
1081
1263
  }
1082
1264
  /** upload variable through websocket (variable command) */
1083
1265
  async upload(
1084
- /** 上传的变量名 */
1266
+ /** Uploaded variables' name */
1085
1267
  vars,
1086
- /** 上传的变量值 */
1268
+ /** Uploaded variables' value */
1087
1269
  args) {
1088
1270
  if (!args.length || args.length !== vars.length)
1089
1271
  throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
@@ -1091,6 +1273,14 @@ class DDB {
1091
1273
  }
1092
1274
  /** 解析服务端响应报文,返回去掉 header 的 data buf */
1093
1275
  parse_message(buf) {
1276
+ // MSG\n
1277
+ // <message>\0
1278
+ // 'M'.codePointAt(0).to_hex_str()
1279
+ if (buf[0] === 0x4d && buf[1] === 0x53 && buf[2] === 0x47 && buf[3] === 0x0a)
1280
+ return {
1281
+ type: 'message',
1282
+ data: this.dec.decode(buf.subarray(4))
1283
+ };
1094
1284
  // '1166953221 1 1\n'
1095
1285
  // 'OK\n'
1096
1286
  // '\x04\x00\x02\x00\x00\x00'
@@ -1113,7 +1303,10 @@ class DDB {
1113
1303
  const message = this.dec.decode(buf.subarray(i_ls_1, i_lf_1));
1114
1304
  if (message !== 'OK')
1115
1305
  throw new Error(message);
1116
- return buf.subarray(i_lf_1 + 1);
1306
+ return {
1307
+ type: 'object',
1308
+ data: buf.subarray(i_lf_1 + 1)
1309
+ };
1117
1310
  }
1118
1311
  /** 自动转换 js string, boolean 为 DdbObj */
1119
1312
  to_ddbobj(value) {