dolphindb 0.0.6 → 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/README.md +16 -0
- package/README.zh.md +15 -0
- package/browser.d.ts +51 -13
- package/browser.js +124 -70
- package/browser.js.map +1 -1
- package/index.d.ts +51 -14
- package/index.js +120 -65
- package/index.js.map +1 -1
- package/package.json +4 -4
package/index.js
CHANGED
|
@@ -431,8 +431,8 @@ class DdbObj {
|
|
|
431
431
|
throw new Error(`array vector 存在非法 unit = ${unit}`);
|
|
432
432
|
}
|
|
433
433
|
let total_length = 0;
|
|
434
|
-
for (
|
|
435
|
-
total_length +=
|
|
434
|
+
for (const x of lengths)
|
|
435
|
+
total_length += x;
|
|
436
436
|
const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
|
|
437
437
|
blocks.push({
|
|
438
438
|
unit,
|
|
@@ -1017,19 +1017,28 @@ function timestamp2str(timestamp) {
|
|
|
1017
1017
|
}
|
|
1018
1018
|
exports.timestamp2str = timestamp2str;
|
|
1019
1019
|
class DDB {
|
|
1020
|
-
|
|
1021
|
-
|
|
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) {
|
|
1022
1028
|
/** 当前的 session id (http 或 tcp) */
|
|
1023
1029
|
this.sid = '0';
|
|
1024
1030
|
/** utf-8 text decoder */
|
|
1025
1031
|
this.dec = new TextDecoder('utf-8');
|
|
1026
1032
|
this.enc = new TextEncoder();
|
|
1027
1033
|
this.print_buffer = false;
|
|
1028
|
-
this.
|
|
1034
|
+
this.websocket = null;
|
|
1029
1035
|
/** little endian (server) */
|
|
1030
1036
|
this.le = true;
|
|
1037
|
+
/** python session flag (2048) */
|
|
1038
|
+
this.python = false;
|
|
1039
|
+
this.message_hook = null;
|
|
1031
1040
|
this.presult = Promise.resolve(null);
|
|
1032
|
-
this.
|
|
1041
|
+
this.url = url;
|
|
1033
1042
|
}
|
|
1034
1043
|
/** print message handler */
|
|
1035
1044
|
printer(message) {
|
|
@@ -1038,66 +1047,102 @@ class DDB {
|
|
|
1038
1047
|
/** resolver, rejector, promise of last rpc */
|
|
1039
1048
|
presolver(buf) { }
|
|
1040
1049
|
prejector(error) { }
|
|
1041
|
-
/**
|
|
1042
|
-
async connect({
|
|
1043
|
-
this.
|
|
1044
|
-
|
|
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)
|
|
1045
1055
|
this.disconnect();
|
|
1046
|
-
let
|
|
1056
|
+
let websocket = new ws_1.WebSocket(url, python ? ['python'] : [], {
|
|
1047
1057
|
maxPayload: 2 ** 33 // 8 GB
|
|
1048
1058
|
});
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
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);
|
|
1072
1087
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
}
|
|
1088
|
+
catch (error) {
|
|
1089
|
+
this.prejector(error);
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1078
1092
|
});
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
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 });
|
|
1096
1110
|
if (login)
|
|
1097
1111
|
await this.call('login', [username, password], { urgent: true });
|
|
1098
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
|
+
}
|
|
1099
1144
|
disconnect() {
|
|
1100
|
-
this.
|
|
1145
|
+
this.websocket?.close(1000);
|
|
1101
1146
|
}
|
|
1102
1147
|
/** rpc through websocket (function/script/variable command)
|
|
1103
1148
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
@@ -1106,10 +1151,10 @@ class DDB {
|
|
|
1106
1151
|
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
1107
1152
|
*/
|
|
1108
1153
|
async rpc(type, { script, func, args = [], vars = [], urgent, }) {
|
|
1109
|
-
if (!this.
|
|
1154
|
+
if (!this.websocket)
|
|
1110
1155
|
await this.connect();
|
|
1111
|
-
if (this.
|
|
1112
|
-
throw new Error(
|
|
1156
|
+
if (this.websocket.readyState !== ws_1.WebSocket.OPEN)
|
|
1157
|
+
throw new Error(`${this.url} is already disconnected`);
|
|
1113
1158
|
// 临界区:保证多个 rpc 并发时形成 promise 链
|
|
1114
1159
|
// ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
|
|
1115
1160
|
// 违反世界观可能造成:
|
|
@@ -1147,14 +1192,16 @@ class DDB {
|
|
|
1147
1192
|
`${vars.join(',')}\n` +
|
|
1148
1193
|
`${vars.length}\n` +
|
|
1149
1194
|
`${Number(DDB.le_client)}\n`;
|
|
1195
|
+
case 'connect':
|
|
1196
|
+
return 'connect\n';
|
|
1150
1197
|
}
|
|
1151
1198
|
})());
|
|
1152
1199
|
const message = (0, utils_js_1.concat)([
|
|
1153
|
-
this.enc.encode(`API2 ${this.sid} ${command.length}${urgent
|
|
1200
|
+
this.enc.encode(`API2 ${this.sid} ${command.length}${this.get_rpc_options({ urgent })}\n`),
|
|
1154
1201
|
command,
|
|
1155
1202
|
...args.map((arg) => arg.pack())
|
|
1156
1203
|
]);
|
|
1157
|
-
this.
|
|
1204
|
+
this.websocket.send(message);
|
|
1158
1205
|
const buf_data = await presult;
|
|
1159
1206
|
if (this.print_buffer)
|
|
1160
1207
|
console.log((0, utils_js_1.typed_array_to_buffer)(buf_data));
|
|
@@ -1181,6 +1228,8 @@ class DDB {
|
|
|
1181
1228
|
- add_node_alias?: 设置 nodes 参数时选传,其它情况不传
|
|
1182
1229
|
*/
|
|
1183
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');
|
|
1184
1233
|
if (node) {
|
|
1185
1234
|
if (typeof func_type === 'undefined')
|
|
1186
1235
|
throw new Error('指定 node 时必须设置 func_type');
|
|
@@ -1196,7 +1245,13 @@ class DDB {
|
|
|
1196
1245
|
new DdbVectorString(nodes),
|
|
1197
1246
|
func,
|
|
1198
1247
|
new DdbVectorAny(this.to_ddbobjs(args)),
|
|
1199
|
-
...
|
|
1248
|
+
...(() => {
|
|
1249
|
+
if (typeof add_node_alias !== 'undefined')
|
|
1250
|
+
return [add_node_alias];
|
|
1251
|
+
if (this.python)
|
|
1252
|
+
return [true];
|
|
1253
|
+
return [];
|
|
1254
|
+
})()
|
|
1200
1255
|
];
|
|
1201
1256
|
func = 'pnode_run';
|
|
1202
1257
|
}
|
|
@@ -1208,9 +1263,9 @@ class DDB {
|
|
|
1208
1263
|
}
|
|
1209
1264
|
/** upload variable through websocket (variable command) */
|
|
1210
1265
|
async upload(
|
|
1211
|
-
/**
|
|
1266
|
+
/** Uploaded variables' name */
|
|
1212
1267
|
vars,
|
|
1213
|
-
/**
|
|
1268
|
+
/** Uploaded variables' value */
|
|
1214
1269
|
args) {
|
|
1215
1270
|
if (!args.length || args.length !== vars.length)
|
|
1216
1271
|
throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
|