dolphindb 2.0.502 → 2.0.505

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.js CHANGED
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DDB = exports.str2nanotimestamp = exports.nanotimestamp2str = exports.str2timestamp = exports.timestamp2str = exports.datetime2str = exports.date2str = exports.DdbTable = exports.DdbVectorSymbol = exports.DdbVectorAny = exports.DdbVectorDouble = exports.DdbVectorString = exports.DdbVectorInt = exports.DdbFunction = exports.DdbPair = exports.DdbNanoTimeStamp = exports.DdbTimeStamp = exports.DdbDateTime = exports.DdbDouble = exports.DdbLong = exports.DdbString = exports.DdbInt = exports.DdbChar = exports.DdbBool = exports.DdbVoid = exports.DdbObj = exports.timezone_offset = exports.nulls = exports.DdbFunctionType = exports.ddb_sizes = exports.DdbType = exports.DdbForm = void 0;
3
+ exports.DDB = exports.str2nanotimestamp = exports.nanotimestamp2str = exports.str2timestamp = exports.timestamp2str = exports.datetime2str = exports.date2str = exports.DdbTable = exports.DdbSetString = exports.DdbSetDouble = exports.DdbSetInt = exports.DdbVectorSymbol = exports.DdbVectorAny = exports.DdbVectorString = exports.DdbVectorDouble = exports.DdbVectorInt = exports.DdbFunction = exports.DdbPair = exports.DdbNanoTimeStamp = exports.DdbTimeStamp = exports.DdbDateTime = exports.DdbDouble = exports.DdbLong = exports.DdbString = exports.DdbInt = exports.DdbChar = exports.DdbBool = exports.DdbVoid = exports.DdbObj = exports.timezone_offset = exports.nulls = exports.DdbFunctionType = exports.ddb_sizes = exports.DdbType = exports.DdbForm = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const ws_1 = require("ws");
6
6
  const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
7
7
  const customParseFormat_js_1 = tslib_1.__importDefault(require("dayjs/plugin/customParseFormat.js"));
8
8
  dayjs_1.default.extend(customParseFormat_js_1.default);
9
+ const net_js_1 = require("xshell/net.js");
9
10
  const utils_js_1 = require("xshell/utils.js");
10
11
  var DdbForm;
11
12
  (function (DdbForm) {
@@ -109,8 +110,7 @@ var DdbFunctionType;
109
110
  DdbFunctionType[DdbFunctionType["JitPartialFunc"] = 8] = "JitPartialFunc";
110
111
  })(DdbFunctionType = exports.DdbFunctionType || (exports.DdbFunctionType = {}));
111
112
  exports.nulls = {
112
- bool: 0x80,
113
- char: '\x80',
113
+ int8: -0x80,
114
114
  int16: -32768,
115
115
  int32: -2147483648,
116
116
  int64: -0x8000000000000000n,
@@ -284,12 +284,14 @@ class DdbObj {
284
284
  case DdbType.void:
285
285
  return [1, null];
286
286
  case DdbType.bool: {
287
- const value = buf[0];
288
- return [1, value === exports.nulls.bool ? null : Boolean(value)];
287
+ const dv = new DataView(buf.buffer, buf.byteOffset);
288
+ const value = dv.getInt8(0);
289
+ return [1, value === exports.nulls.int8 ? null : Boolean(value)];
289
290
  }
290
291
  case DdbType.char: {
291
- const value = String.fromCharCode(buf[0]);
292
- return [1, value === exports.nulls.char ? null : value];
292
+ const dv = new DataView(buf.buffer, buf.byteOffset);
293
+ const value = dv.getInt8(0);
294
+ return [1, value === exports.nulls.int8 ? null : value];
293
295
  }
294
296
  case DdbType.short: {
295
297
  const dv = new DataView(buf.buffer, buf.byteOffset);
@@ -474,11 +476,10 @@ class DdbObj {
474
476
  static parse_vector_items(buf, le, type, length) {
475
477
  switch (type) {
476
478
  case DdbType.bool:
477
- return [length, buf.slice(0, length)];
478
479
  case DdbType.char:
479
480
  return [
480
481
  length,
481
- this.dec.decode(buf.subarray(0, length))
482
+ new Int8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + length))
482
483
  ];
483
484
  case DdbType.short:
484
485
  return [
@@ -628,17 +629,17 @@ class DdbObj {
628
629
  return [Uint8Array.of(1)];
629
630
  case DdbType.bool:
630
631
  return [
631
- Uint8Array.of(value === null ?
632
- exports.nulls.bool
632
+ Int8Array.of(value === null ?
633
+ exports.nulls.int8
633
634
  :
634
635
  Number(value))
635
636
  ];
636
637
  case DdbType.char:
637
638
  return [
638
- Uint8Array.of((value === null ?
639
- exports.nulls.char
639
+ Int8Array.of((value === null ?
640
+ exports.nulls.int8
640
641
  :
641
- value).charCodeAt(0))
642
+ value))
642
643
  ];
643
644
  case DdbType.short:
644
645
  return [
@@ -780,7 +781,7 @@ class DdbObj {
780
781
  case DdbType.bool:
781
782
  return [value];
782
783
  case DdbType.char:
783
- return [this.enc.encode(value)];
784
+ return [value];
784
785
  case DdbType.short:
785
786
  return [value];
786
787
  case DdbType.int:
@@ -968,7 +969,10 @@ class DdbChar extends DdbObj {
968
969
  form: DdbForm.scalar,
969
970
  type: DdbType.char,
970
971
  length: 1,
971
- value,
972
+ value: typeof value === 'string' ?
973
+ value.charCodeAt(0)
974
+ :
975
+ value
972
976
  });
973
977
  }
974
978
  }
@@ -1094,20 +1098,6 @@ class DdbVectorInt extends DdbObj {
1094
1098
  }
1095
1099
  }
1096
1100
  exports.DdbVectorInt = DdbVectorInt;
1097
- class DdbVectorString extends DdbObj {
1098
- constructor(strings, name) {
1099
- super({
1100
- form: DdbForm.vector,
1101
- type: DdbType.string,
1102
- length: 0,
1103
- rows: strings.length,
1104
- cols: 1,
1105
- value: strings,
1106
- name,
1107
- });
1108
- }
1109
- }
1110
- exports.DdbVectorString = DdbVectorString;
1111
1101
  class DdbVectorDouble extends DdbObj {
1112
1102
  constructor(doubles, name) {
1113
1103
  super({
@@ -1128,6 +1118,20 @@ class DdbVectorDouble extends DdbObj {
1128
1118
  }
1129
1119
  }
1130
1120
  exports.DdbVectorDouble = DdbVectorDouble;
1121
+ class DdbVectorString extends DdbObj {
1122
+ constructor(strings, name) {
1123
+ super({
1124
+ form: DdbForm.vector,
1125
+ type: DdbType.string,
1126
+ length: 0,
1127
+ rows: strings.length,
1128
+ cols: 1,
1129
+ value: strings,
1130
+ name,
1131
+ });
1132
+ }
1133
+ }
1134
+ exports.DdbVectorString = DdbVectorString;
1131
1135
  class DdbVectorAny extends DdbObj {
1132
1136
  constructor(objs, name) {
1133
1137
  super({
@@ -1173,6 +1177,65 @@ class DdbVectorSymbol extends DdbObj {
1173
1177
  }
1174
1178
  }
1175
1179
  exports.DdbVectorSymbol = DdbVectorSymbol;
1180
+ class DdbSetInt extends DdbObj {
1181
+ constructor(ints) {
1182
+ super({
1183
+ form: DdbForm.set,
1184
+ type: DdbType.int,
1185
+ length: 0,
1186
+ rows: ints instanceof Set ?
1187
+ ints.size
1188
+ :
1189
+ ints.length,
1190
+ cols: 1,
1191
+ value: ints instanceof Int32Array ?
1192
+ ints
1193
+ :
1194
+ Int32Array.from(ints, v => v === null ?
1195
+ exports.nulls.int32
1196
+ :
1197
+ v),
1198
+ });
1199
+ }
1200
+ }
1201
+ exports.DdbSetInt = DdbSetInt;
1202
+ class DdbSetDouble extends DdbObj {
1203
+ constructor(doubles) {
1204
+ super({
1205
+ form: DdbForm.set,
1206
+ type: DdbType.double,
1207
+ length: 0,
1208
+ rows: doubles instanceof Set ?
1209
+ doubles.size
1210
+ :
1211
+ doubles.length,
1212
+ cols: 1,
1213
+ value: doubles instanceof Int32Array ?
1214
+ doubles
1215
+ :
1216
+ Int32Array.from(doubles, v => v === null ?
1217
+ exports.nulls.int32
1218
+ :
1219
+ v),
1220
+ });
1221
+ }
1222
+ }
1223
+ exports.DdbSetDouble = DdbSetDouble;
1224
+ class DdbSetString extends DdbObj {
1225
+ constructor(strings) {
1226
+ if (strings instanceof Set)
1227
+ strings = [...strings];
1228
+ super({
1229
+ form: DdbForm.set,
1230
+ type: DdbType.string,
1231
+ length: 0,
1232
+ rows: strings.length,
1233
+ cols: 1,
1234
+ value: strings
1235
+ });
1236
+ }
1237
+ }
1238
+ exports.DdbSetString = DdbSetString;
1176
1239
  class DdbTable extends DdbObj {
1177
1240
  constructor(columns, name = '') {
1178
1241
  super({
@@ -1280,11 +1343,25 @@ class DDB {
1280
1343
  /**
1281
1344
  Initialize an instance of DolphinDB Client using the WebSocket URL
1282
1345
  (without establishing an actual network connection)
1346
+ - url: DolphinDB WebSocket URL. e.g.:`ws://127.0.0.1:8848`
1347
+ - options?:
1348
+ - autologin?: Whether to log in automatically after establishing a connection, default `true`
1349
+ - username?: DolphinDB username, default `'admin'`
1350
+ - password?: DolphinDB password, default `'123456'`
1351
+ - python?: set python session flag, default `false`
1352
+
1283
1353
  @example
1284
1354
  let ddb = new DDB('ws://127.0.0.1:8848')
1285
- let ddb_secure = new DDB('wss://dolphindb.com')
1355
+
1356
+ // 使用 HTTPS 加密
1357
+ let ddbsecure = new DDB('wss://dolphindb.com', {
1358
+ autologin: true,
1359
+ username: 'admin',
1360
+ password: '123456',
1361
+ python: false
1362
+ })
1286
1363
  */
1287
- constructor(url) {
1364
+ constructor(url, options = {}) {
1288
1365
  /** 当前的 session id (http 或 tcp) */
1289
1366
  this.sid = '0';
1290
1367
  /** utf-8 text decoder */
@@ -1294,63 +1371,83 @@ class DDB {
1294
1371
  this.websocket = null;
1295
1372
  /** little endian (server) */
1296
1373
  this.le = true;
1374
+ /** 是否在建立连接后自动登录,默认 true */
1375
+ this.autologin = true;
1376
+ /** DolphinDB 登录用户名 */
1377
+ this.username = 'admin';
1378
+ /** DolphinDB 登录密码 */
1379
+ this.password = '123456';
1297
1380
  /** python session flag (2048) */
1298
1381
  this.python = false;
1299
- this.message_hook = null;
1382
+ this.parse_object = true;
1300
1383
  this.presult = Promise.resolve(null);
1301
1384
  this.url = url;
1385
+ if (options.autologin !== undefined)
1386
+ this.autologin = options.autologin;
1387
+ if (options.username !== undefined)
1388
+ this.username = options.username;
1389
+ if (options.password !== undefined)
1390
+ this.password = options.password;
1391
+ if (options.python !== undefined)
1392
+ this.python = options.python;
1302
1393
  }
1303
- /** print message handler */
1304
- printer(message) {
1305
- console.log(message);
1394
+ /** message handler */
1395
+ on_message({ type, data }, _this) {
1396
+ switch (type) {
1397
+ case 'print':
1398
+ console.log(data);
1399
+ return;
1400
+ case 'object':
1401
+ if (this.print_buffer)
1402
+ console.log((0, utils_js_1.typed_array_to_buffer)(data.buffer));
1403
+ return;
1404
+ }
1306
1405
  }
1307
1406
  /** resolver, rejector, promise of last rpc */
1308
- presolver(buf) { }
1407
+ presolver(message) { }
1309
1408
  prejector(error) { }
1310
1409
  get connected() {
1311
1410
  return this.websocket?.readyState === ws_1.WebSocket.OPEN;
1312
1411
  }
1313
- /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
1314
- async connect({ url = this.url, login = true, username = 'admin', password = '123456', python = false, } = {}) {
1315
- this.url = url;
1316
- this.python = python;
1412
+ /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
1413
+ - options?:
1414
+ - url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
1415
+ - autologin?: Whether to log in automatically after establishing a connection, default `true`
1416
+ - username?: DolphinDB username, default `'admin'`
1417
+ - password?: DolphinDB password, default `'123456'`
1418
+ - python?: set python session flag, default `false`
1419
+ */
1420
+ async connect(options = {}) {
1421
+ if (options.url !== undefined)
1422
+ this.url = options.url;
1423
+ if (options.autologin !== undefined)
1424
+ this.autologin = options.autologin;
1425
+ if (options.username !== undefined)
1426
+ this.username = options.username;
1427
+ if (options.password !== undefined)
1428
+ this.password = options.password;
1429
+ if (options.python !== undefined)
1430
+ this.python = options.python;
1317
1431
  this.disconnect();
1318
- let websocket = new ws_1.WebSocket(url, python ? ['python'] : [], {
1319
- maxPayload: 2 ** 33 // 8 GB
1320
- });
1321
- // https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
1322
- websocket.binaryType = 'arraybuffer';
1323
- this.websocket = websocket;
1324
- await new Promise((resolve, reject) => {
1325
- websocket.addEventListener('open', async (event) => {
1326
- console.log(`${websocket.url} opened`);
1432
+ await (0, net_js_1.connect_websocket)(this.url, {
1433
+ protocols: this.python ? ['python'] : [],
1434
+ on_open: async (event, websocket) => {
1435
+ this.websocket = websocket;
1327
1436
  await this.rpc('connect', {});
1328
- resolve();
1329
- });
1330
- websocket.addEventListener('close', event => {
1331
- console.log(`${websocket.url} closed with code = ${event.code}, reason = '${event.reason}'`);
1332
- });
1333
- websocket.addEventListener('error', event => {
1334
- const message = `${websocket.url} errored`;
1335
- console.error(message, event);
1336
- reject(Object.assign(new Error(message), { event }));
1337
- });
1338
- websocket.addEventListener('message', event => {
1437
+ },
1438
+ on_message: event => {
1339
1439
  const buf = new Uint8Array(event.data);
1340
- if (this.message_hook)
1341
- this.message_hook(buf);
1342
1440
  try {
1343
- const { type, data } = this.parse_message(buf);
1344
- if (type === 'message') {
1345
- this.printer(data);
1441
+ const message = this.parse_message(buf);
1442
+ this.on_message(message, this);
1443
+ if (message.type === 'print')
1346
1444
  return;
1347
- }
1348
- this.presolver(data);
1445
+ this.presolver(message);
1349
1446
  }
1350
1447
  catch (error) {
1351
1448
  this.prejector(error);
1352
1449
  }
1353
- });
1450
+ }
1354
1451
  });
1355
1452
  if (!this.python)
1356
1453
  await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
@@ -1369,11 +1466,11 @@ class DDB {
1369
1466
  ' add_node_alias\n' +
1370
1467
  ' )\n' +
1371
1468
  '}\n', { urgent: true });
1372
- if (login)
1469
+ if (this.autologin)
1373
1470
  if (this.python)
1374
- await this.eval(`login(${username.quote('double')}, ${password.quote('double')})`, { urgent: true });
1471
+ await this.eval(`login(${this.username.quote('double')}, ${this.password.quote('double')})`, { urgent: true });
1375
1472
  else
1376
- await this.call('login', [username, password], { urgent: true });
1473
+ await this.call('login', [this.username, this.password], { urgent: true });
1377
1474
  }
1378
1475
  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, } = {}) {
1379
1476
  let flag = 0;
@@ -1404,7 +1501,7 @@ class DDB {
1404
1501
  limit,
1405
1502
  ] : [],
1406
1503
  ];
1407
- return `/ ${options.join('_')}`;
1504
+ return options.join('_');
1408
1505
  }
1409
1506
  disconnect() {
1410
1507
  if (this.connected)
@@ -1418,8 +1515,11 @@ class DDB {
1418
1515
  - options:
1419
1516
  - urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
1420
1517
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
1518
+ - on_message?: 在该次 rpc 期间设置 message handler, 结束后恢复原有
1519
+ - parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
1520
+ 不做解析,以便后续转发、序列化
1421
1521
  */
1422
- async rpc(type, { script, func, args = [], vars = [], urgent, }) {
1522
+ async rpc(type, { script, func, args = [], vars = [], urgent, on_message, parse_object, }) {
1423
1523
  if (!this.websocket)
1424
1524
  await this.connect();
1425
1525
  if (!this.connected)
@@ -1466,25 +1566,36 @@ class DDB {
1466
1566
  }
1467
1567
  })());
1468
1568
  const message = (0, utils_js_1.concat)([
1469
- this.enc.encode(`API2 ${this.sid} ${command.length}${this.get_rpc_options({ urgent })}\n`),
1569
+ this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
1470
1570
  command,
1471
1571
  ...args.map((arg) => arg.pack())
1472
1572
  ]);
1473
- this.websocket.send(message);
1474
- const buf_data = await presult;
1475
- if (this.print_buffer)
1476
- console.log((0, utils_js_1.typed_array_to_buffer)(buf_data));
1477
- // LOCAL: 便于 repl
1478
- // return global.DdbObj.parse(data_buf) as DdbObj
1479
- return DdbObj.parse(buf_data, this.le);
1573
+ const _on_message = this.on_message;
1574
+ const _parse_object = this.parse_object;
1575
+ if (on_message)
1576
+ this.on_message = on_message;
1577
+ if (parse_object !== undefined)
1578
+ this.parse_object = parse_object;
1579
+ try {
1580
+ this.websocket.send(message);
1581
+ const { data } = (await presult);
1582
+ return data;
1583
+ }
1584
+ finally {
1585
+ this.on_message = _on_message;
1586
+ this.parse_object = _parse_object;
1587
+ }
1480
1588
  }
1481
- /** eval script through websocket (script command) */
1482
- async eval(
1483
- /** 执行的脚本 */
1484
- script,
1485
- /** 执行选项 */
1486
- { urgent } = {}) {
1487
- return this.rpc('script', { script, urgent });
1589
+ /** eval script through websocket (script command)
1590
+ - script?: 执行的脚本
1591
+ - options?: 执行选项
1592
+ - urgent?: 紧急 flag,确保提交的脚本使用 urgent worker 处理,防止被其它作业阻塞
1593
+ - on_message?: 在该次 rpc 期间设置 message handler, 结束后恢复原有
1594
+ - parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
1595
+ 不做解析,以便后续转发、序列化
1596
+ */
1597
+ async eval(script, { urgent, on_message, parse_object, } = {}) {
1598
+ return this.rpc('script', { script, urgent, on_message, parse_object });
1488
1599
  }
1489
1600
  /** call function through websocket (function command)
1490
1601
  - func: 函数名
@@ -1495,8 +1606,11 @@ class DDB {
1495
1606
  - nodes?: 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法)
1496
1607
  - func_type?: 设置 node 参数时必传,需指定函数类型,其它情况下不传
1497
1608
  - add_node_alias?: 设置 nodes 参数时选传,其它情况不传
1609
+ - on_message?: 在该次 rpc 期间设置 message handler, 结束后恢复原有
1610
+ - parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
1611
+ 不做解析,以便后续转发、序列化
1498
1612
  */
1499
- async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias } = {}) {
1613
+ async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, on_message, parse_object, } = {}) {
1500
1614
  if (this.python)
1501
1615
  throw new Error('call doesn\'t support python session yet');
1502
1616
  if (node) {
@@ -1528,6 +1642,8 @@ class DDB {
1528
1642
  func,
1529
1643
  args,
1530
1644
  urgent,
1645
+ on_message,
1646
+ parse_object
1531
1647
  });
1532
1648
  }
1533
1649
  /** upload variable through websocket (variable command) */
@@ -1535,19 +1651,19 @@ class DDB {
1535
1651
  /** Uploaded variables' name */
1536
1652
  vars,
1537
1653
  /** Uploaded variables' value */
1538
- args) {
1654
+ args, { on_message, parse_object, } = {}) {
1539
1655
  if (!args.length || args.length !== vars.length)
1540
1656
  throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
1541
- return this.rpc('variable', { vars, args });
1657
+ return this.rpc('variable', { vars, args, on_message, parse_object });
1542
1658
  }
1543
1659
  /** 解析服务端响应报文,返回去掉 header 的 data buf */
1544
- parse_message(buf) {
1660
+ parse_message(buf, parse_object = this.parse_object) {
1545
1661
  // MSG\n
1546
1662
  // <message>\0
1547
1663
  // 'M'.codePointAt(0).to_hex_str()
1548
1664
  if (buf[0] === 0x4d && buf[1] === 0x53 && buf[2] === 0x47 && buf[3] === 0x0a)
1549
1665
  return {
1550
- type: 'message',
1666
+ type: 'print',
1551
1667
  data: this.dec.decode(buf.subarray(4))
1552
1668
  };
1553
1669
  // '1166953221 1 1\n'
@@ -1572,9 +1688,19 @@ class DDB {
1572
1688
  const message = this.dec.decode(buf.subarray(i_ls_1, i_lf_1));
1573
1689
  if (message !== 'OK')
1574
1690
  throw new Error(message);
1691
+ const buf_obj = buf.subarray(i_lf_1 + 1);
1575
1692
  return {
1576
1693
  type: 'object',
1577
- data: buf.subarray(i_lf_1 + 1)
1694
+ data: parse_object ?
1695
+ Object.assign(DdbObj.parse(buf_obj, this.le), { buffer: buf_obj })
1696
+ :
1697
+ new DdbObj({
1698
+ form: DdbForm.scalar,
1699
+ type: DdbType.void,
1700
+ length: 0,
1701
+ le: this.le,
1702
+ buffer: buf_obj,
1703
+ })
1578
1704
  };
1579
1705
  }
1580
1706
  /** 自动转换 js string, boolean 为 DdbObj */