dolphindb 0.0.5 → 0.0.8

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
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
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
4
  const tslib_1 = require("tslib");
5
- const dayjs_1 = (0, tslib_1.__importDefault)(require("dayjs"));
6
5
  const ws_1 = require("ws");
6
+ const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
7
7
  const utils_js_1 = require("xshell/utils.js");
8
8
  var DdbForm;
9
9
  (function (DdbForm) {
@@ -54,6 +54,7 @@ var DdbType;
54
54
  DdbType[DdbType["complex"] = 34] = "complex";
55
55
  DdbType[DdbType["point"] = 35] = "point";
56
56
  DdbType[DdbType["duration"] = 36] = "duration";
57
+ DdbType[DdbType["object"] = 37] = "object";
57
58
  DdbType[DdbType["symbol_extended"] = 145] = "symbol_extended";
58
59
  })(DdbType = exports.DdbType || (exports.DdbType = {}));
59
60
  exports.ddb_sizes = [
@@ -431,8 +432,8 @@ class DdbObj {
431
432
  throw new Error(`array vector 存在非法 unit = ${unit}`);
432
433
  }
433
434
  let total_length = 0;
434
- for (let i = 0; i < lengths.length; i++)
435
- total_length += lengths[i];
435
+ for (const x of lengths)
436
+ total_length += x;
436
437
  const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
437
438
  blocks.push({
438
439
  unit,
@@ -1017,80 +1018,132 @@ function timestamp2str(timestamp) {
1017
1018
  }
1018
1019
  exports.timestamp2str = timestamp2str;
1019
1020
  class DDB {
1020
- constructor(ws_url) {
1021
- this.port = 8848;
1021
+ /**
1022
+ Initialize an instance of DolphinDB Client using the WebSocket URL
1023
+ (without establishing an actual network connection)
1024
+ @example
1025
+ let ddb = new DDB('ws://127.0.0.1:8848')
1026
+ let ddb_secure = new DDB('wss://dolphindb.com')
1027
+ */
1028
+ constructor(url) {
1022
1029
  /** 当前的 session id (http 或 tcp) */
1023
1030
  this.sid = '0';
1024
1031
  /** utf-8 text decoder */
1025
1032
  this.dec = new TextDecoder('utf-8');
1026
1033
  this.enc = new TextEncoder();
1027
1034
  this.print_buffer = false;
1028
- this.ws = null;
1035
+ this.websocket = null;
1029
1036
  /** little endian (server) */
1030
1037
  this.le = true;
1038
+ /** python session flag (2048) */
1039
+ this.python = false;
1040
+ this.message_hook = null;
1031
1041
  this.presult = Promise.resolve(null);
1032
- this.ws_url = ws_url;
1042
+ this.url = url;
1043
+ }
1044
+ /** print message handler */
1045
+ printer(message) {
1046
+ console.log(message);
1033
1047
  }
1034
1048
  /** resolver, rejector, promise of last rpc */
1035
1049
  presolver(buf) { }
1036
1050
  prejector(error) { }
1037
- /** 连接到 DolphinDB Server */
1038
- async connect({ ws_url = this.ws_url, login = true, username = 'admin', password = '123456', } = {}) {
1039
- this.ws_url = ws_url;
1040
- if (this.ws?.readyState === ws_1.WebSocket.OPEN)
1051
+ /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
1052
+ async connect({ url = this.url, login = true, username = 'admin', password = '123456', python = false, } = {}) {
1053
+ this.url = url;
1054
+ this.python = python;
1055
+ if (this.websocket?.readyState === ws_1.WebSocket.OPEN)
1041
1056
  this.disconnect();
1042
- let ws = new ws_1.WebSocket(ws_url, [], {
1057
+ let websocket = new ws_1.WebSocket(url, python ? ['python'] : [], {
1043
1058
  maxPayload: 2 ** 33 // 8 GB
1044
1059
  });
1045
- this.ws = ws;
1046
- ws.addEventListener('open', ev => {
1047
- console.log(`${this.ws_url} opened`);
1048
- ws.send(`API ${this.sid} 8\n` +
1049
- 'connect\n');
1050
- });
1051
- ws.addEventListener('close', ev => {
1052
- console.log(`${this.ws_url} closed with code = ${ev.code}, reason = '${ev.reason}'`);
1053
- });
1054
- ws.addEventListener('error', ev => {
1055
- console.log(`${this.ws_url} errored`, ev);
1056
- });
1057
- // 为首个 connect 响应报文初始化 presult 链表头结点
1058
- this.presult = new Promise((resolve, reject) => {
1059
- this.presolver = resolve;
1060
- this.prejector = reject;
1061
- });
1062
- ws.addEventListener('message', ({ data: buf }) => {
1063
- try {
1064
- this.presolver(this.parse_message(
1065
- // node buffer 转 Uint8Array
1066
- new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)));
1067
- }
1068
- catch (error) {
1069
- this.prejector(error);
1070
- }
1060
+ // https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
1061
+ websocket.binaryType = 'arraybuffer';
1062
+ this.websocket = websocket;
1063
+ await new Promise((resolve, reject) => {
1064
+ websocket.addEventListener('open', async (event) => {
1065
+ console.log(`${websocket.url} opened`);
1066
+ await this.rpc('connect', {});
1067
+ resolve();
1068
+ });
1069
+ websocket.addEventListener('close', event => {
1070
+ console.log(`${websocket.url} closed with code = ${event.code}, reason = '${event.reason}'`);
1071
+ });
1072
+ websocket.addEventListener('error', event => {
1073
+ const message = `${websocket.url} errored`;
1074
+ console.error(message, event);
1075
+ reject(Object.assign(new Error(message), { event }));
1076
+ });
1077
+ websocket.addEventListener('message', event => {
1078
+ const buf = new Uint8Array(event.data);
1079
+ if (this.message_hook)
1080
+ this.message_hook(buf);
1081
+ try {
1082
+ const { type, data } = this.parse_message(buf);
1083
+ if (type === 'message') {
1084
+ this.printer(data);
1085
+ return;
1086
+ }
1087
+ this.presolver(data);
1088
+ }
1089
+ catch (error) {
1090
+ this.prejector(error);
1091
+ }
1092
+ });
1071
1093
  });
1072
- await this.presult;
1073
- await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
1074
- ' nargs = size(args)\n' +
1075
- ' func = funcByName(func_name)\n' +
1076
- ' \n' +
1077
- ' if (!nargs)\n' +
1078
- ' return pnodeRun(func, nodes, add_node_alias)\n' +
1079
- ' \n' +
1080
- ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
1081
- ' args_partial[0] = func\n' +
1082
- ' args_partial[1:] = args\n' +
1083
- ' return pnodeRun(\n' +
1084
- ' unifiedCall(partial, args_partial),\n' +
1085
- ' nodes,\n' +
1086
- ' add_node_alias\n' +
1087
- ' )\n' +
1088
- '}\n', { urgent: true });
1094
+ if (!this.python)
1095
+ await this.eval('def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
1096
+ ' nargs = size(args)\n' +
1097
+ ' func = funcByName(func_name)\n' +
1098
+ ' \n' +
1099
+ ' if (!nargs)\n' +
1100
+ ' return pnodeRun(func, nodes, add_node_alias)\n' +
1101
+ ' \n' +
1102
+ ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
1103
+ ' args_partial[0] = func\n' +
1104
+ ' args_partial[1:] = args\n' +
1105
+ ' return pnodeRun(\n' +
1106
+ ' unifiedCall(partial, args_partial),\n' +
1107
+ ' nodes,\n' +
1108
+ ' add_node_alias\n' +
1109
+ ' )\n' +
1110
+ '}\n', { urgent: true });
1089
1111
  if (login)
1090
1112
  await this.call('login', [username, password], { urgent: true });
1091
1113
  }
1114
+ 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, } = {}) {
1115
+ let flag = 0;
1116
+ if (urgent)
1117
+ flag += 1;
1118
+ if (secondary)
1119
+ flag += 2;
1120
+ if (_async)
1121
+ flag += 4;
1122
+ if (pickle)
1123
+ flag += 8;
1124
+ if (clear)
1125
+ flag += 16;
1126
+ if (api)
1127
+ flag += 32;
1128
+ if (compress)
1129
+ flag += 64;
1130
+ // python session
1131
+ if (this.python)
1132
+ flag += 2048;
1133
+ const options = [
1134
+ flag,
1135
+ cancellable ? 1 : 0,
1136
+ priority,
1137
+ parallelism,
1138
+ ...limit ? [
1139
+ root_id,
1140
+ limit,
1141
+ ] : [],
1142
+ ];
1143
+ return `/ ${options.join('_')}`;
1144
+ }
1092
1145
  disconnect() {
1093
- this.ws?.close(1000);
1146
+ this.websocket?.close(1000);
1094
1147
  }
1095
1148
  /** rpc through websocket (function/script/variable command)
1096
1149
  - type: API 类型: 'script' | 'function' | 'variable'
@@ -1099,10 +1152,10 @@ class DDB {
1099
1152
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
1100
1153
  */
1101
1154
  async rpc(type, { script, func, args = [], vars = [], urgent, }) {
1102
- if (!this.ws)
1155
+ if (!this.websocket)
1103
1156
  await this.connect();
1104
- if (this.ws.readyState !== ws_1.WebSocket.OPEN)
1105
- throw new Error('ws 连接已断开');
1157
+ if (this.websocket.readyState !== ws_1.WebSocket.OPEN)
1158
+ throw new Error(`${this.url} is already disconnected`);
1106
1159
  // 临界区:保证多个 rpc 并发时形成 promise 链
1107
1160
  // ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
1108
1161
  // 违反世界观可能造成:
@@ -1140,14 +1193,16 @@ class DDB {
1140
1193
  `${vars.join(',')}\n` +
1141
1194
  `${vars.length}\n` +
1142
1195
  `${Number(DDB.le_client)}\n`;
1196
+ case 'connect':
1197
+ return 'connect\n';
1143
1198
  }
1144
1199
  })());
1145
1200
  const message = (0, utils_js_1.concat)([
1146
- this.enc.encode(`API ${this.sid} ${command.length}${urgent ? ` / 1_1_8_8` : ''}\n`),
1201
+ this.enc.encode(`API2 ${this.sid} ${command.length}${this.get_rpc_options({ urgent })}\n`),
1147
1202
  command,
1148
1203
  ...args.map((arg) => arg.pack())
1149
1204
  ]);
1150
- this.ws.send(message);
1205
+ this.websocket.send(message);
1151
1206
  const buf_data = await presult;
1152
1207
  if (this.print_buffer)
1153
1208
  console.log((0, utils_js_1.typed_array_to_buffer)(buf_data));
@@ -1174,6 +1229,8 @@ class DDB {
1174
1229
  - add_node_alias?: 设置 nodes 参数时选传,其它情况不传
1175
1230
  */
1176
1231
  async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias } = {}) {
1232
+ if (this.python)
1233
+ throw new Error('call doesn\'t support python session yet');
1177
1234
  if (node) {
1178
1235
  if (typeof func_type === 'undefined')
1179
1236
  throw new Error('指定 node 时必须设置 func_type');
@@ -1189,7 +1246,13 @@ class DDB {
1189
1246
  new DdbVectorString(nodes),
1190
1247
  func,
1191
1248
  new DdbVectorAny(this.to_ddbobjs(args)),
1192
- ...typeof add_node_alias === 'undefined' ? [] : [add_node_alias]
1249
+ ...(() => {
1250
+ if (typeof add_node_alias !== 'undefined')
1251
+ return [add_node_alias];
1252
+ if (this.python)
1253
+ return [true];
1254
+ return [];
1255
+ })()
1193
1256
  ];
1194
1257
  func = 'pnode_run';
1195
1258
  }
@@ -1201,9 +1264,9 @@ class DDB {
1201
1264
  }
1202
1265
  /** upload variable through websocket (variable command) */
1203
1266
  async upload(
1204
- /** 上传的变量名 */
1267
+ /** Uploaded variables' name */
1205
1268
  vars,
1206
- /** 上传的变量值 */
1269
+ /** Uploaded variables' value */
1207
1270
  args) {
1208
1271
  if (!args.length || args.length !== vars.length)
1209
1272
  throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
@@ -1211,6 +1274,14 @@ class DDB {
1211
1274
  }
1212
1275
  /** 解析服务端响应报文,返回去掉 header 的 data buf */
1213
1276
  parse_message(buf) {
1277
+ // MSG\n
1278
+ // <message>\0
1279
+ // 'M'.codePointAt(0).to_hex_str()
1280
+ if (buf[0] === 0x4d && buf[1] === 0x53 && buf[2] === 0x47 && buf[3] === 0x0a)
1281
+ return {
1282
+ type: 'message',
1283
+ data: this.dec.decode(buf.subarray(4))
1284
+ };
1214
1285
  // '1166953221 1 1\n'
1215
1286
  // 'OK\n'
1216
1287
  // '\x04\x00\x02\x00\x00\x00'
@@ -1233,7 +1304,10 @@ class DDB {
1233
1304
  const message = this.dec.decode(buf.subarray(i_ls_1, i_lf_1));
1234
1305
  if (message !== 'OK')
1235
1306
  throw new Error(message);
1236
- return buf.subarray(i_lf_1 + 1);
1307
+ return {
1308
+ type: 'object',
1309
+ data: buf.subarray(i_lf_1 + 1)
1310
+ };
1237
1311
  }
1238
1312
  /** 自动转换 js string, boolean 为 DdbObj */
1239
1313
  to_ddbobj(value) {