dolphindb 0.0.6 → 0.0.9
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 +52 -13
- package/browser.js +126 -71
- package/browser.js.map +1 -1
- package/index.d.ts +53 -15
- package/index.js +131 -75
- package/index.js.map +1 -1
- package/package.json +6 -6
- package/test.js +1 -1
- package/test.js.map +1 -1
package/README.md
CHANGED
|
@@ -320,3 +320,19 @@ async upload (
|
|
|
320
320
|
): Promise<void>
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
+
|
|
324
|
+
### Notes
|
|
325
|
+
```ts
|
|
326
|
+
import { nulls, DdbInt, timestamp2str } from 'dolphindb'
|
|
327
|
+
|
|
328
|
+
// create DolphinDB null integer value (the smallest 32-bit integer)
|
|
329
|
+
new DdbInt(nulls.int32)
|
|
330
|
+
|
|
331
|
+
// convert DolphinDB timestamp value to string
|
|
332
|
+
timestamp2str(
|
|
333
|
+
(
|
|
334
|
+
await ddb.call<DdbObj<bigint>>('now', [false])
|
|
335
|
+
).value
|
|
336
|
+
) === '2022.02.23 17:23:13.494'
|
|
337
|
+
```
|
|
338
|
+
|
package/README.zh.md
CHANGED
|
@@ -320,3 +320,18 @@ async upload (
|
|
|
320
320
|
): Promise<void>
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
+
|
|
324
|
+
### Notes
|
|
325
|
+
```ts
|
|
326
|
+
import { nulls, DdbInt, timestamp2str } from 'dolphindb'
|
|
327
|
+
|
|
328
|
+
// 创建 DolphinDB 空值 (最小的 32-bit 整数)
|
|
329
|
+
new DdbInt(nulls.int32)
|
|
330
|
+
|
|
331
|
+
// 将 DolphinDB 中的 timestamp 格式化为 string
|
|
332
|
+
timestamp2str(
|
|
333
|
+
(
|
|
334
|
+
await ddb.call<DdbObj<bigint>>('now', [false])
|
|
335
|
+
).value
|
|
336
|
+
) === '2022.02.23 17:23:13.494'
|
|
337
|
+
```
|
package/browser.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export declare enum DdbType {
|
|
|
46
46
|
complex = 34,
|
|
47
47
|
point = 35,
|
|
48
48
|
duration = 36,
|
|
49
|
+
object = 37,
|
|
49
50
|
symbol_extended = 145
|
|
50
51
|
}
|
|
51
52
|
export declare enum DdbFunctionType {
|
|
@@ -188,30 +189,68 @@ export declare class DDB {
|
|
|
188
189
|
/** utf-8 text decoder */
|
|
189
190
|
dec: TextDecoder;
|
|
190
191
|
enc: TextEncoder;
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
/** DolphinDB WebSocket URL
|
|
193
|
+
e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
|
|
194
|
+
*/
|
|
195
|
+
url: string;
|
|
196
|
+
websocket: WebSocket;
|
|
193
197
|
/** little endian (server) */
|
|
194
198
|
le: boolean;
|
|
195
199
|
/** little endian (client) */
|
|
196
200
|
static le_client: boolean;
|
|
201
|
+
/** python session flag (2048) */
|
|
202
|
+
python: boolean;
|
|
203
|
+
message_hook: (message: Uint8Array) => any;
|
|
197
204
|
/** print message handler */
|
|
198
205
|
printer(message: string): void;
|
|
199
206
|
/** resolver, rejector, promise of last rpc */
|
|
200
207
|
presolver(buf: Uint8Array): void;
|
|
201
208
|
prejector(error: Error): void;
|
|
202
209
|
presult: Promise<Uint8Array>;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
/**
|
|
211
|
+
Initialize an instance of DolphinDB Client using the WebSocket URL
|
|
212
|
+
(without establishing an actual network connection)
|
|
213
|
+
@example
|
|
214
|
+
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
215
|
+
let ddb_secure = new DDB('wss://dolphindb.com')
|
|
216
|
+
*/
|
|
217
|
+
constructor(url?: string);
|
|
218
|
+
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
|
|
219
|
+
connect({ url, login, username, password, python, }?: {
|
|
220
|
+
/** By default, the WebSocket URL passed in when the instance is initialized is used */
|
|
221
|
+
url?: string;
|
|
222
|
+
/** Whether to automatically log in after the connection is established, the default is true */
|
|
209
223
|
login?: boolean;
|
|
210
|
-
/** DolphinDB
|
|
224
|
+
/** DolphinDB username */
|
|
211
225
|
username?: string;
|
|
212
|
-
/** DolphinDB
|
|
226
|
+
/** DolphinDB password */
|
|
213
227
|
password?: string;
|
|
228
|
+
/** set python session flag */
|
|
229
|
+
python?: boolean;
|
|
214
230
|
}): Promise<void>;
|
|
231
|
+
get_rpc_options({ urgent, secondary, async: _async, pickle, clear, api, compress, cancellable, priority, parallelism, root_id, limit, }?: {
|
|
232
|
+
urgent?: boolean;
|
|
233
|
+
/** API 提交的任务, secondary 必须为 false */
|
|
234
|
+
secondary?: boolean;
|
|
235
|
+
/** 是否异步任务(不返回结果) */
|
|
236
|
+
async?: boolean;
|
|
237
|
+
/** 让服务端以 pickle 协议返回数据 */
|
|
238
|
+
pickle?: boolean;
|
|
239
|
+
/** 本次任务完成后 clear session memory */
|
|
240
|
+
clear?: boolean;
|
|
241
|
+
/** 是否为 api client */
|
|
242
|
+
api?: boolean;
|
|
243
|
+
compress?: boolean;
|
|
244
|
+
/** 任务是否可以取消 */
|
|
245
|
+
cancellable?: boolean;
|
|
246
|
+
priority?: number;
|
|
247
|
+
/** `8` 0 ~ 64, 指定本任务并行度 */
|
|
248
|
+
parallelism?: number;
|
|
249
|
+
/** 根任务编号,内部使用,API中固定为空 */
|
|
250
|
+
root_id?: string;
|
|
251
|
+
/** 指定分块返回的块大小 */
|
|
252
|
+
limit?: boolean;
|
|
253
|
+
}): string;
|
|
215
254
|
disconnect(): void;
|
|
216
255
|
/** rpc through websocket (function/script/variable command)
|
|
217
256
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
@@ -219,7 +258,7 @@ export declare class DDB {
|
|
|
219
258
|
- urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
|
|
220
259
|
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
221
260
|
*/
|
|
222
|
-
rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable', { script, func, args, vars, urgent, }: {
|
|
261
|
+
rpc<T extends DdbObj = DdbObj>(type: 'script' | 'function' | 'variable' | 'connect', { script, func, args, vars, urgent, }: {
|
|
223
262
|
script?: string;
|
|
224
263
|
func?: string;
|
|
225
264
|
args?: (DdbObj | string | boolean)[];
|
|
@@ -254,9 +293,9 @@ export declare class DDB {
|
|
|
254
293
|
}): Promise<T>;
|
|
255
294
|
/** upload variable through websocket (variable command) */
|
|
256
295
|
upload(
|
|
257
|
-
/**
|
|
296
|
+
/** Uploaded variables' name */
|
|
258
297
|
vars: string[],
|
|
259
|
-
/**
|
|
298
|
+
/** Uploaded variables' value */
|
|
260
299
|
args: (DdbObj | string | boolean)[]): Promise<DdbObj<DdbValue>>;
|
|
261
300
|
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
262
301
|
parse_message(buf: Uint8Array): {
|
package/browser.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ddb = 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.DdbType = exports.DdbForm = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const dayjs_1 =
|
|
5
|
+
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
|
|
6
6
|
require("xshell/prototype.browser");
|
|
7
7
|
const utils_browser_1 = require("xshell/utils.browser");
|
|
8
8
|
var 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
|
var DdbFunctionType;
|
|
@@ -394,8 +395,8 @@ class DdbObj {
|
|
|
394
395
|
throw new Error(`array vector 存在非法 unit = ${unit}`);
|
|
395
396
|
}
|
|
396
397
|
let total_length = 0;
|
|
397
|
-
for (
|
|
398
|
-
total_length +=
|
|
398
|
+
for (const x of lengths)
|
|
399
|
+
total_length += x;
|
|
399
400
|
const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
|
|
400
401
|
blocks.push({
|
|
401
402
|
unit,
|
|
@@ -1014,23 +1015,33 @@ function timestamp2str(timestamp) {
|
|
|
1014
1015
|
}
|
|
1015
1016
|
exports.timestamp2str = timestamp2str;
|
|
1016
1017
|
class DDB {
|
|
1017
|
-
|
|
1018
|
+
/**
|
|
1019
|
+
Initialize an instance of DolphinDB Client using the WebSocket URL
|
|
1020
|
+
(without establishing an actual network connection)
|
|
1021
|
+
@example
|
|
1022
|
+
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
1023
|
+
let ddb_secure = new DDB('wss://dolphindb.com')
|
|
1024
|
+
*/
|
|
1025
|
+
constructor(url) {
|
|
1018
1026
|
/** 当前的 session id (http 或 tcp) */
|
|
1019
1027
|
this.sid = '0';
|
|
1020
1028
|
/** utf-8 text decoder */
|
|
1021
1029
|
this.dec = new TextDecoder('utf-8');
|
|
1022
1030
|
this.enc = new TextEncoder();
|
|
1023
|
-
this.
|
|
1031
|
+
this.websocket = null;
|
|
1024
1032
|
/** little endian (server) */
|
|
1025
1033
|
this.le = true;
|
|
1034
|
+
/** python session flag (2048) */
|
|
1035
|
+
this.python = false;
|
|
1036
|
+
this.message_hook = null;
|
|
1026
1037
|
this.presult = Promise.resolve(null);
|
|
1027
|
-
if (!
|
|
1028
|
-
const
|
|
1029
|
-
const hostname =
|
|
1030
|
-
const port =
|
|
1031
|
-
|
|
1038
|
+
if (!url) {
|
|
1039
|
+
const _url = new URL(location.href);
|
|
1040
|
+
const hostname = _url.searchParams.get('hostname') || location.hostname;
|
|
1041
|
+
const port = _url.searchParams.get('port') || location.port;
|
|
1042
|
+
url = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${hostname}${port ? `:${port}` : ''}/`;
|
|
1032
1043
|
}
|
|
1033
|
-
this.
|
|
1044
|
+
this.url = url;
|
|
1034
1045
|
}
|
|
1035
1046
|
/** print message handler */
|
|
1036
1047
|
printer(message) {
|
|
@@ -1039,66 +1050,100 @@ class DDB {
|
|
|
1039
1050
|
/** resolver, rejector, promise of last rpc */
|
|
1040
1051
|
presolver(buf) { }
|
|
1041
1052
|
prejector(error) { }
|
|
1042
|
-
/**
|
|
1043
|
-
async connect({
|
|
1044
|
-
this.
|
|
1045
|
-
|
|
1053
|
+
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
|
|
1054
|
+
async connect({ url = this.url, login = true, username = 'admin', password = '123456', python = false, } = {}) {
|
|
1055
|
+
this.url = url;
|
|
1056
|
+
this.python = python;
|
|
1057
|
+
if (this.websocket?.readyState === WebSocket.OPEN)
|
|
1046
1058
|
this.disconnect();
|
|
1047
|
-
let
|
|
1059
|
+
let websocket = new WebSocket(url, python ? ['python'] : []);
|
|
1048
1060
|
// https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
|
|
1049
|
-
|
|
1050
|
-
this.
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
'connect
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
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);
|
|
1073
1088
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1089
|
+
catch (error) {
|
|
1090
|
+
this.prejector(error);
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1079
1093
|
});
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
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 });
|
|
1097
1111
|
if (login)
|
|
1098
1112
|
await this.call('login', [username, password], { urgent: true });
|
|
1099
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
|
+
}
|
|
1100
1145
|
disconnect() {
|
|
1101
|
-
this.
|
|
1146
|
+
this.websocket?.close(1000);
|
|
1102
1147
|
}
|
|
1103
1148
|
/** rpc through websocket (function/script/variable command)
|
|
1104
1149
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
@@ -1107,10 +1152,10 @@ class DDB {
|
|
|
1107
1152
|
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
1108
1153
|
*/
|
|
1109
1154
|
async rpc(type, { script, func, args = [], vars = [], urgent, }) {
|
|
1110
|
-
if (!this.
|
|
1155
|
+
if (!this.websocket)
|
|
1111
1156
|
await this.connect();
|
|
1112
|
-
if (this.
|
|
1113
|
-
throw new Error(
|
|
1157
|
+
if (this.websocket.readyState !== WebSocket.OPEN)
|
|
1158
|
+
throw new Error(`${this.url} is already disconnected`);
|
|
1114
1159
|
// 临界区:保证多个 rpc 并发时形成 promise 链
|
|
1115
1160
|
// ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
|
|
1116
1161
|
// 违反世界观可能造成:
|
|
@@ -1148,14 +1193,16 @@ class DDB {
|
|
|
1148
1193
|
`${vars.join(',')}\n` +
|
|
1149
1194
|
`${vars.length}\n` +
|
|
1150
1195
|
`${Number(DDB.le_client)}\n`;
|
|
1196
|
+
case 'connect':
|
|
1197
|
+
return 'connect\n';
|
|
1151
1198
|
}
|
|
1152
1199
|
})());
|
|
1153
1200
|
const message = (0, utils_browser_1.concat)([
|
|
1154
|
-
this.enc.encode(`API2 ${this.sid} ${command.length}${urgent
|
|
1201
|
+
this.enc.encode(`API2 ${this.sid} ${command.length}${this.get_rpc_options({ urgent })}\n`),
|
|
1155
1202
|
command,
|
|
1156
1203
|
...args.map((arg) => arg.pack())
|
|
1157
1204
|
]);
|
|
1158
|
-
this.
|
|
1205
|
+
this.websocket.send(message);
|
|
1159
1206
|
return DdbObj.parse(await presult, // data_buf
|
|
1160
1207
|
this.le);
|
|
1161
1208
|
}
|
|
@@ -1178,6 +1225,8 @@ class DDB {
|
|
|
1178
1225
|
- add_node_alias?: 设置 nodes 参数时选传,其它情况不传
|
|
1179
1226
|
*/
|
|
1180
1227
|
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias } = {}) {
|
|
1228
|
+
if (this.python)
|
|
1229
|
+
throw new Error('call doesn\'t support python session yet');
|
|
1181
1230
|
if (node) {
|
|
1182
1231
|
if (typeof func_type === 'undefined')
|
|
1183
1232
|
throw new Error('指定 node 时必须设置 func_type');
|
|
@@ -1193,7 +1242,13 @@ class DDB {
|
|
|
1193
1242
|
new DdbVectorString(nodes),
|
|
1194
1243
|
func,
|
|
1195
1244
|
new DdbVectorAny(this.to_ddbobjs(args)),
|
|
1196
|
-
...
|
|
1245
|
+
...(() => {
|
|
1246
|
+
if (typeof add_node_alias !== 'undefined')
|
|
1247
|
+
return [add_node_alias];
|
|
1248
|
+
if (this.python)
|
|
1249
|
+
return [true];
|
|
1250
|
+
return [];
|
|
1251
|
+
})()
|
|
1197
1252
|
];
|
|
1198
1253
|
func = 'pnode_run';
|
|
1199
1254
|
}
|
|
@@ -1205,9 +1260,9 @@ class DDB {
|
|
|
1205
1260
|
}
|
|
1206
1261
|
/** upload variable through websocket (variable command) */
|
|
1207
1262
|
async upload(
|
|
1208
|
-
/**
|
|
1263
|
+
/** Uploaded variables' name */
|
|
1209
1264
|
vars,
|
|
1210
|
-
/**
|
|
1265
|
+
/** Uploaded variables' value */
|
|
1211
1266
|
args) {
|
|
1212
1267
|
if (!args.length || args.length !== vars.length)
|
|
1213
1268
|
throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
|