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/README.md +68 -7
- package/README.zh.md +67 -7
- package/browser.d.ts +85 -21
- package/browser.js +280 -87
- package/browser.js.map +1 -1
- package/index.d.ts +77 -21
- package/index.js +265 -72
- package/index.js.map +1 -1
- package/package.json +5 -5
- package/test.js +22 -2
- package/test.js.map +1 -1
package/browser.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ddb = 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.DdbObj = exports.nulls = exports.DdbFunctionType = exports.DdbType = exports.DdbForm = void 0;
|
|
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
5
|
const dayjs_1 = (0, tslib_1.__importDefault)(require("dayjs"));
|
|
6
6
|
require("xshell/prototype.browser");
|
|
7
7
|
const utils_browser_1 = require("xshell/utils.browser");
|
|
8
|
-
const chalk_browser_1 = require("xshell/chalk.browser");
|
|
9
8
|
var DdbForm;
|
|
10
9
|
(function (DdbForm) {
|
|
11
10
|
DdbForm[DdbForm["scalar"] = 0] = "scalar";
|
|
@@ -75,6 +74,8 @@ exports.nulls = {
|
|
|
75
74
|
int32: -2147483648,
|
|
76
75
|
int64: -0x8000000000000000n, // -922_3372_0368_5477_5808
|
|
77
76
|
};
|
|
77
|
+
exports.timezone_offset = 1000 * 60 * new Date().getTimezoneOffset();
|
|
78
|
+
/** 可以表示所有 DolphinDB 数据库中的数据类型 */
|
|
78
79
|
class DdbObj {
|
|
79
80
|
constructor(data) {
|
|
80
81
|
/** 是否为小端 (little endian) */
|
|
@@ -333,16 +334,86 @@ class DdbObj {
|
|
|
333
334
|
static parse_vector(buf, le, type) {
|
|
334
335
|
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
335
336
|
const rows = dv.getUint32(0, le);
|
|
336
|
-
|
|
337
|
-
|
|
337
|
+
let i_items_start = 8;
|
|
338
|
+
if (type < 64 || type >= 128) {
|
|
339
|
+
const [len_items, value] = this.parse_vector_items(buf.subarray(i_items_start), le, type, rows);
|
|
340
|
+
return new this({
|
|
341
|
+
le,
|
|
342
|
+
form: DdbForm.vector,
|
|
343
|
+
type,
|
|
344
|
+
length: i_items_start + len_items,
|
|
345
|
+
cols: 1,
|
|
346
|
+
rows,
|
|
347
|
+
value,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// array vector
|
|
351
|
+
// av = array(INT[], 0, 3)
|
|
352
|
+
// append!(av, [1..4])
|
|
353
|
+
// append!(av, [1..70000])
|
|
354
|
+
// av
|
|
355
|
+
// <Buffer 44 01 type = array vector, form = vector
|
|
356
|
+
// 02 00 00 00 74 11 01 00 rows = 2, cols = 70004 (0x011174)
|
|
357
|
+
// block 0
|
|
358
|
+
// 01 00 block.rows = 1
|
|
359
|
+
// 04 block.unit = 4
|
|
360
|
+
// 00 reserved
|
|
361
|
+
// 04 00 00 00 block.lengths = [4]
|
|
362
|
+
// 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 block.data
|
|
363
|
+
// block 1
|
|
364
|
+
// 01 00 block.rows = 1
|
|
365
|
+
// 04 block.unit = 4
|
|
366
|
+
// 00 reserved
|
|
367
|
+
// 70 11 01 00 block.lengths = [70000 (0x00011170)]
|
|
368
|
+
// 01 00 00 00 02 00 00 00 ... 279992 more bytes> block.data
|
|
369
|
+
const cols = dv.getUint32(4, le);
|
|
370
|
+
let blocks = [];
|
|
371
|
+
let i_block_start = i_items_start;
|
|
372
|
+
// 解析一个 block
|
|
373
|
+
for (let i_row = 0; i_row < rows;) {
|
|
374
|
+
/** 对应 array vector 中元素个数 */
|
|
375
|
+
const rows = dv.getUint16(i_block_start, le);
|
|
376
|
+
/** 每个 length 占用的字节数 */
|
|
377
|
+
const unit = dv.getUint8(i_block_start + 2);
|
|
378
|
+
/** array vector 每个元素的子元素长度 */
|
|
379
|
+
let lengths;
|
|
380
|
+
const i_lengths_start = i_block_start + 4;
|
|
381
|
+
const i_data_start = i_lengths_start + rows * unit;
|
|
382
|
+
const lengths_buf = buf.slice(i_lengths_start, i_data_start);
|
|
383
|
+
switch (unit) {
|
|
384
|
+
case 1:
|
|
385
|
+
lengths = lengths_buf;
|
|
386
|
+
break;
|
|
387
|
+
case 2:
|
|
388
|
+
lengths = new Uint16Array(lengths_buf.buffer);
|
|
389
|
+
break;
|
|
390
|
+
case 4:
|
|
391
|
+
lengths = new Uint32Array(lengths_buf.buffer);
|
|
392
|
+
break;
|
|
393
|
+
default:
|
|
394
|
+
throw new Error(`array vector 存在非法 unit = ${unit}`);
|
|
395
|
+
}
|
|
396
|
+
let total_length = 0;
|
|
397
|
+
for (const x of lengths)
|
|
398
|
+
total_length += x;
|
|
399
|
+
const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
|
|
400
|
+
blocks.push({
|
|
401
|
+
unit,
|
|
402
|
+
rows,
|
|
403
|
+
lengths,
|
|
404
|
+
data
|
|
405
|
+
});
|
|
406
|
+
i_block_start = i_data_start + len_items;
|
|
407
|
+
i_row += rows;
|
|
408
|
+
}
|
|
338
409
|
return new this({
|
|
339
410
|
le,
|
|
340
411
|
form: DdbForm.vector,
|
|
341
412
|
type,
|
|
342
|
-
length:
|
|
343
|
-
cols
|
|
413
|
+
length: i_block_start,
|
|
414
|
+
cols,
|
|
344
415
|
rows,
|
|
345
|
-
value
|
|
416
|
+
value: blocks
|
|
346
417
|
});
|
|
347
418
|
}
|
|
348
419
|
/** 有可能没有字节对齐,不能直接使用原有 message 的 arraybuffer, 统一复制出来,让原有 arraybuffer 被回收掉比较好 */
|
|
@@ -423,13 +494,13 @@ class DdbObj {
|
|
|
423
494
|
}
|
|
424
495
|
const value_start = 8 + base_length;
|
|
425
496
|
const value_end = value_start + length * 4;
|
|
426
|
-
const
|
|
497
|
+
const data = new Uint32Array(buf.buffer.slice(buf.byteOffset + value_start, buf.byteOffset + value_end));
|
|
427
498
|
return [
|
|
428
499
|
value_end,
|
|
429
500
|
{
|
|
430
501
|
base_id,
|
|
431
502
|
base,
|
|
432
|
-
|
|
503
|
+
data
|
|
433
504
|
}
|
|
434
505
|
];
|
|
435
506
|
}
|
|
@@ -554,11 +625,24 @@ class DdbObj {
|
|
|
554
625
|
return [Float64Array.from(this.value)];
|
|
555
626
|
case DdbType.duration:
|
|
556
627
|
return [value];
|
|
628
|
+
case DdbType.handle:
|
|
629
|
+
throw new Error('DolphinDB Server 不支持 handle 的反序列化');
|
|
557
630
|
default:
|
|
558
631
|
throw new Error(`${DdbType[type]} 暂时不支持序列化`);
|
|
559
632
|
}
|
|
560
633
|
case DdbForm.vector:
|
|
561
634
|
case DdbForm.pair:
|
|
635
|
+
// pack array vector
|
|
636
|
+
if (form === DdbForm.vector && 64 <= type && type < 128)
|
|
637
|
+
return [
|
|
638
|
+
Uint32Array.of(this.rows, this.cols),
|
|
639
|
+
...this.value.map(block => ([
|
|
640
|
+
Uint16Array.of(block.rows),
|
|
641
|
+
Uint8Array.of(block.unit, 0),
|
|
642
|
+
block.lengths,
|
|
643
|
+
block.data
|
|
644
|
+
])).flat()
|
|
645
|
+
];
|
|
562
646
|
return [
|
|
563
647
|
Uint32Array.of(this.rows, 1),
|
|
564
648
|
...DdbObj.pack_vector_body(value, type, this.rows)
|
|
@@ -674,6 +758,14 @@ class DdbObj {
|
|
|
674
758
|
bufs[i] = value[i].pack();
|
|
675
759
|
return bufs;
|
|
676
760
|
}
|
|
761
|
+
case DdbType.symbol_extended: {
|
|
762
|
+
const { base_id, base, data } = value;
|
|
763
|
+
return [
|
|
764
|
+
Uint32Array.of(base_id, base.length),
|
|
765
|
+
...this.pack_vector_body(base, DdbType.string, base.length),
|
|
766
|
+
data
|
|
767
|
+
];
|
|
768
|
+
}
|
|
677
769
|
default:
|
|
678
770
|
throw new Error(`vector ${DdbType[type]} 暂不支持序列化`);
|
|
679
771
|
}
|
|
@@ -687,6 +779,8 @@ class DdbObj {
|
|
|
687
779
|
return `functiondef<${DdbFunctionType[this.value.type]}>`;
|
|
688
780
|
return tname;
|
|
689
781
|
case DdbForm.vector:
|
|
782
|
+
if (64 <= this.type && this.type < 128)
|
|
783
|
+
return `${DdbType[this.type - 64]}[][${this.rows}]`;
|
|
690
784
|
return `${tname}[${this.rows}]`;
|
|
691
785
|
case DdbForm.pair:
|
|
692
786
|
return `pair<${tname}>`;
|
|
@@ -709,7 +803,7 @@ class DdbObj {
|
|
|
709
803
|
return `'${this.value.name}'`;
|
|
710
804
|
return this.value;
|
|
711
805
|
})();
|
|
712
|
-
return `${
|
|
806
|
+
return `${type}(${this.name ? `'${this.name}', ` : ''}${data})\n`;
|
|
713
807
|
}
|
|
714
808
|
to_cols() {
|
|
715
809
|
return this.value.map(col => {
|
|
@@ -719,18 +813,10 @@ class DdbObj {
|
|
|
719
813
|
};
|
|
720
814
|
switch (col.type) {
|
|
721
815
|
case DdbType.timestamp:
|
|
722
|
-
col_.render =
|
|
723
|
-
if (value === exports.nulls.int64)
|
|
724
|
-
return '';
|
|
725
|
-
return (0, dayjs_1.default)(Number(value)).format('YYYY.MM.DD HH:mm:ss.SSS');
|
|
726
|
-
};
|
|
816
|
+
col_.render = timestamp2str;
|
|
727
817
|
break;
|
|
728
818
|
case DdbType.date:
|
|
729
|
-
col_.render =
|
|
730
|
-
if (value === exports.nulls.int32)
|
|
731
|
-
return '';
|
|
732
|
-
return (0, dayjs_1.default)(Number(1000 * 3600 * 24 * value)).format('YYYY.MM.DD');
|
|
733
|
-
};
|
|
819
|
+
col_.render = date2str;
|
|
734
820
|
break;
|
|
735
821
|
case DdbType.ipaddr:
|
|
736
822
|
col_.render = value => value.slice().reverse().join('.').replace(/^(0\.)+/, '');
|
|
@@ -755,6 +841,15 @@ class DdbObj {
|
|
|
755
841
|
}
|
|
756
842
|
return rows;
|
|
757
843
|
}
|
|
844
|
+
to_dict() {
|
|
845
|
+
if (this.form !== DdbForm.dict)
|
|
846
|
+
throw new Error('this.form 不是 dict, 不能转换为 Object');
|
|
847
|
+
const [{ value: keys }, { value: values }] = this.value;
|
|
848
|
+
let obj = {};
|
|
849
|
+
for (let i = 0; i < this.rows; i++)
|
|
850
|
+
obj[keys[i]] = values[i].value;
|
|
851
|
+
return obj;
|
|
852
|
+
}
|
|
758
853
|
}
|
|
759
854
|
exports.DdbObj = DdbObj;
|
|
760
855
|
DdbObj.dec = new TextDecoder('utf-8');
|
|
@@ -763,6 +858,16 @@ DdbObj.enc = new TextEncoder();
|
|
|
763
858
|
DdbObj.symbol_bases = {};
|
|
764
859
|
/** little endian (client) */
|
|
765
860
|
DdbObj.le_client = Boolean(new Uint8Array(Uint32Array.of(1).buffer)[0]);
|
|
861
|
+
class DdbVoid extends DdbObj {
|
|
862
|
+
constructor() {
|
|
863
|
+
super({
|
|
864
|
+
form: DdbForm.scalar,
|
|
865
|
+
type: DdbType.void,
|
|
866
|
+
length: 0,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
exports.DdbVoid = DdbVoid;
|
|
766
871
|
class DdbBool extends DdbObj {
|
|
767
872
|
constructor(value) {
|
|
768
873
|
super({
|
|
@@ -894,95 +999,162 @@ class DdbFunction extends DdbObj {
|
|
|
894
999
|
}
|
|
895
1000
|
}
|
|
896
1001
|
exports.DdbFunction = DdbFunction;
|
|
1002
|
+
function date2str(date) {
|
|
1003
|
+
return date === exports.nulls.int32 ?
|
|
1004
|
+
''
|
|
1005
|
+
:
|
|
1006
|
+
(0, dayjs_1.default)(exports.timezone_offset + 1000 * 3600 * 24 * date).format('YYYY.MM.DD');
|
|
1007
|
+
}
|
|
1008
|
+
exports.date2str = date2str;
|
|
1009
|
+
function timestamp2str(timestamp) {
|
|
1010
|
+
return timestamp === exports.nulls.int64 ?
|
|
1011
|
+
''
|
|
1012
|
+
:
|
|
1013
|
+
(0, dayjs_1.default)(exports.timezone_offset + Number(timestamp)).format('YYYY.MM.DD HH:mm:ss.SSS');
|
|
1014
|
+
}
|
|
1015
|
+
exports.timestamp2str = timestamp2str;
|
|
897
1016
|
class DDB {
|
|
898
|
-
|
|
1017
|
+
/**
|
|
1018
|
+
Initialize an instance of DolphinDB Client using the WebSocket URL
|
|
1019
|
+
(without establishing an actual network connection)
|
|
1020
|
+
@example
|
|
1021
|
+
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
1022
|
+
let ddb_secure = new DDB('wss://dolphindb.com')
|
|
1023
|
+
*/
|
|
1024
|
+
constructor(url) {
|
|
899
1025
|
/** 当前的 session id (http 或 tcp) */
|
|
900
1026
|
this.sid = '0';
|
|
901
1027
|
/** utf-8 text decoder */
|
|
902
1028
|
this.dec = new TextDecoder('utf-8');
|
|
903
1029
|
this.enc = new TextEncoder();
|
|
904
|
-
this.
|
|
1030
|
+
this.websocket = null;
|
|
905
1031
|
/** little endian (server) */
|
|
906
1032
|
this.le = true;
|
|
1033
|
+
/** python session flag (2048) */
|
|
1034
|
+
this.python = false;
|
|
1035
|
+
this.message_hook = null;
|
|
907
1036
|
this.presult = Promise.resolve(null);
|
|
908
|
-
if (!
|
|
909
|
-
const
|
|
910
|
-
const hostname =
|
|
911
|
-
const port =
|
|
912
|
-
|
|
1037
|
+
if (!url) {
|
|
1038
|
+
const _url = new URL(location.href);
|
|
1039
|
+
const hostname = _url.searchParams.get('hostname') || location.hostname;
|
|
1040
|
+
const port = _url.searchParams.get('port') || location.port;
|
|
1041
|
+
url = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${hostname}${port ? `:${port}` : ''}/`;
|
|
913
1042
|
}
|
|
914
|
-
this.
|
|
1043
|
+
this.url = url;
|
|
1044
|
+
}
|
|
1045
|
+
/** print message handler */
|
|
1046
|
+
printer(message) {
|
|
1047
|
+
console.log(message);
|
|
915
1048
|
}
|
|
916
1049
|
/** resolver, rejector, promise of last rpc */
|
|
917
1050
|
presolver(buf) { }
|
|
918
1051
|
prejector(error) { }
|
|
919
|
-
/**
|
|
920
|
-
async connect({
|
|
921
|
-
this.
|
|
922
|
-
|
|
1052
|
+
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL */
|
|
1053
|
+
async connect({ url = this.url, login = true, username = 'admin', password = '123456', python = false, } = {}) {
|
|
1054
|
+
this.url = url;
|
|
1055
|
+
this.python = python;
|
|
1056
|
+
if (this.websocket?.readyState === WebSocket.OPEN)
|
|
923
1057
|
this.disconnect();
|
|
924
|
-
let
|
|
1058
|
+
let websocket = new WebSocket(url, python ? ['python'] : []);
|
|
925
1059
|
// https://stackoverflow.com/questions/11821096/what-is-the-difference-between-an-arraybuffer-and-a-blob/39951543
|
|
926
|
-
|
|
927
|
-
this.
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
'connect
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
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
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
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.
|
|
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.
|
|
1154
|
+
if (!this.websocket)
|
|
983
1155
|
await this.connect();
|
|
984
|
-
if (this.
|
|
985
|
-
throw new Error(
|
|
1156
|
+
if (this.websocket.readyState !== 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_browser_1.concat)([
|
|
1026
|
-
this.enc.encode(`
|
|
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.
|
|
1204
|
+
this.websocket.send(message);
|
|
1031
1205
|
return DdbObj.parse(await presult, // data_buf
|
|
1032
1206
|
this.le);
|
|
1033
1207
|
}
|
|
@@ -1043,13 +1217,15 @@ class DDB {
|
|
|
1043
1217
|
- func: 函数名
|
|
1044
1218
|
- args?: `[ ]` 调用参数 (传入的原生 string 和 boolean 会被自动转换为 DdbObj<string> 和 DdbObj<boolean>)
|
|
1045
1219
|
- options?: 调用选项
|
|
1046
|
-
- urgent?: 紧急 flag
|
|
1220
|
+
- urgent?: 紧急 flag。使用 urgent worker 执行,防止被其它作业阻塞
|
|
1047
1221
|
- node?: 设置结点 alias 时发送到集群中对应的结点执行 (使用 DolphinDB 中的 rpc 方法)
|
|
1048
1222
|
- nodes?: 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法)
|
|
1049
1223
|
- func_type?: 设置 node 参数时必传,需指定函数类型,其它情况下不传
|
|
1050
1224
|
- add_node_alias?: 设置 nodes 参数时选传,其它情况不传
|
|
1051
1225
|
*/
|
|
1052
1226
|
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias } = {}) {
|
|
1227
|
+
if (this.python)
|
|
1228
|
+
throw new Error('call doesn\'t support python session yet');
|
|
1053
1229
|
if (node) {
|
|
1054
1230
|
if (typeof func_type === 'undefined')
|
|
1055
1231
|
throw new Error('指定 node 时必须设置 func_type');
|
|
@@ -1065,7 +1241,13 @@ class DDB {
|
|
|
1065
1241
|
new DdbVectorString(nodes),
|
|
1066
1242
|
func,
|
|
1067
1243
|
new DdbVectorAny(this.to_ddbobjs(args)),
|
|
1068
|
-
...
|
|
1244
|
+
...(() => {
|
|
1245
|
+
if (typeof add_node_alias !== 'undefined')
|
|
1246
|
+
return [add_node_alias];
|
|
1247
|
+
if (this.python)
|
|
1248
|
+
return [true];
|
|
1249
|
+
return [];
|
|
1250
|
+
})()
|
|
1069
1251
|
];
|
|
1070
1252
|
func = 'pnode_run';
|
|
1071
1253
|
}
|
|
@@ -1077,9 +1259,9 @@ class DDB {
|
|
|
1077
1259
|
}
|
|
1078
1260
|
/** upload variable through websocket (variable command) */
|
|
1079
1261
|
async upload(
|
|
1080
|
-
/**
|
|
1262
|
+
/** Uploaded variables' name */
|
|
1081
1263
|
vars,
|
|
1082
|
-
/**
|
|
1264
|
+
/** Uploaded variables' value */
|
|
1083
1265
|
args) {
|
|
1084
1266
|
if (!args.length || args.length !== vars.length)
|
|
1085
1267
|
throw new Error('variable 指令参数为空或参数名为空,或数量不匹配');
|
|
@@ -1087,6 +1269,14 @@ class DDB {
|
|
|
1087
1269
|
}
|
|
1088
1270
|
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
1089
1271
|
parse_message(buf) {
|
|
1272
|
+
// MSG\n
|
|
1273
|
+
// <message>\0
|
|
1274
|
+
// 'M'.codePointAt(0).to_hex_str()
|
|
1275
|
+
if (buf[0] === 0x4d && buf[1] === 0x53 && buf[2] === 0x47 && buf[3] === 0x0a)
|
|
1276
|
+
return {
|
|
1277
|
+
type: 'message',
|
|
1278
|
+
data: this.dec.decode(buf.subarray(4))
|
|
1279
|
+
};
|
|
1090
1280
|
// '1166953221 1 1\n'
|
|
1091
1281
|
// 'OK\n'
|
|
1092
1282
|
// '\x04\x00\x02\x00\x00\x00'
|
|
@@ -1109,7 +1299,10 @@ class DDB {
|
|
|
1109
1299
|
const message = this.dec.decode(buf.subarray(i_ls_1, i_lf_1));
|
|
1110
1300
|
if (message !== 'OK')
|
|
1111
1301
|
throw new Error(message);
|
|
1112
|
-
return
|
|
1302
|
+
return {
|
|
1303
|
+
type: 'object',
|
|
1304
|
+
data: buf.subarray(i_lf_1 + 1)
|
|
1305
|
+
};
|
|
1113
1306
|
}
|
|
1114
1307
|
/** 自动转换 js string, boolean 为 DdbObj */
|
|
1115
1308
|
to_ddbobj(value) {
|