dolphindb 2.0.602 → 2.0.800
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 +1 -0
- package/browser.d.ts +109 -17
- package/browser.js +389 -183
- package/browser.js.map +1 -1
- package/docs.en.json +2046 -552
- package/docs.zh.json +1311 -737
- package/index.d.ts +114 -18
- package/index.js +406 -196
- package/index.js.map +1 -1
- package/language.d.ts +2 -2
- package/language.js +5 -3
- package/language.js.map +1 -1
- package/package.json +7 -7
package/index.js
CHANGED
|
@@ -4,8 +4,8 @@ import DayjsCustomParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
|
4
4
|
dayjs.extend(DayjsCustomParseFormat);
|
|
5
5
|
import ipaddrjs from 'ipaddr.js';
|
|
6
6
|
const { fromByteArray: buf2ipaddr } = ipaddrjs;
|
|
7
|
+
import { concat, assert, inspect, typed_array_to_buffer } from 'xshell/utils.js';
|
|
7
8
|
import { connect_websocket } from 'xshell/net.js';
|
|
8
|
-
import { concat, inspect, typed_array_to_buffer } from 'xshell/utils.js';
|
|
9
9
|
export var DdbForm;
|
|
10
10
|
(function (DdbForm) {
|
|
11
11
|
DdbForm[DdbForm["scalar"] = 0] = "scalar";
|
|
@@ -62,7 +62,11 @@ export var DdbType;
|
|
|
62
62
|
DdbType[DdbType["complex"] = 34] = "complex";
|
|
63
63
|
DdbType[DdbType["point"] = 35] = "point";
|
|
64
64
|
DdbType[DdbType["duration"] = 36] = "duration";
|
|
65
|
-
DdbType[DdbType["
|
|
65
|
+
DdbType[DdbType["decimal32"] = 37] = "decimal32";
|
|
66
|
+
DdbType[DdbType["decimal64"] = 38] = "decimal64";
|
|
67
|
+
DdbType[DdbType["decimal128"] = 39] = "decimal128";
|
|
68
|
+
DdbType[DdbType["object"] = 40] = "object";
|
|
69
|
+
DdbType[DdbType["pynone"] = 41] = "pynone";
|
|
66
70
|
DdbType[DdbType["symbol_extended"] = 145] = "symbol_extended";
|
|
67
71
|
})(DdbType = DdbType || (DdbType = {}));
|
|
68
72
|
export var DdbFunctionType;
|
|
@@ -114,7 +118,15 @@ export const nulls = {
|
|
|
114
118
|
bytes16: Uint8Array.from(new Array(16).fill(0))
|
|
115
119
|
};
|
|
116
120
|
export const timezone_offset = 1000 * 60 * new Date().getTimezoneOffset();
|
|
117
|
-
|
|
121
|
+
export var StreamingStatusCode;
|
|
122
|
+
(function (StreamingStatusCode) {
|
|
123
|
+
StreamingStatusCode[StreamingStatusCode["ok"] = 0] = "ok";
|
|
124
|
+
StreamingStatusCode[StreamingStatusCode["connection_existed"] = 1] = "connection_existed";
|
|
125
|
+
StreamingStatusCode[StreamingStatusCode["not_leader"] = 2] = "not_leader";
|
|
126
|
+
StreamingStatusCode[StreamingStatusCode["other"] = 3] = "other";
|
|
127
|
+
StreamingStatusCode[StreamingStatusCode["error"] = 4] = "error";
|
|
128
|
+
})(StreamingStatusCode = StreamingStatusCode || (StreamingStatusCode = {}));
|
|
129
|
+
/** Can represent data types in all DolphinDB databases */
|
|
118
130
|
export class DdbObj {
|
|
119
131
|
static dec = new TextDecoder('utf-8');
|
|
120
132
|
static enc = new TextEncoder();
|
|
@@ -146,7 +158,7 @@ export class DdbObj {
|
|
|
146
158
|
rows;
|
|
147
159
|
/** 第 2 维 */
|
|
148
160
|
cols;
|
|
149
|
-
/**
|
|
161
|
+
/** The actual data. Different DdbForm, DdbType use different types in DdbValue to represent actual data */
|
|
150
162
|
value;
|
|
151
163
|
/** 原始二进制数据,仅在 parse_object 为 false 时通过 parse_message 生成的顶层对象有这个属性 */
|
|
152
164
|
buffer;
|
|
@@ -267,7 +279,7 @@ export class DdbObj {
|
|
|
267
279
|
if (form === DdbForm.dict)
|
|
268
280
|
return dict;
|
|
269
281
|
else {
|
|
270
|
-
const { chartType: type, stacking, title: titles, extras, data, ...others } = dict.to_dict();
|
|
282
|
+
const { chartType: type, stacking, binStart: bin_start, binEnd: bin_end, binCount: bin_count, title: titles, extras, data, ...others } = dict.to_dict();
|
|
271
283
|
const [chart, x_axis, y_axis] = titles.value;
|
|
272
284
|
dict.form = DdbForm.chart;
|
|
273
285
|
dict.value = {
|
|
@@ -278,6 +290,8 @@ export class DdbObj {
|
|
|
278
290
|
x_axis,
|
|
279
291
|
y_axis,
|
|
280
292
|
},
|
|
293
|
+
...bin_start ? { bin_start, bin_end, } : {},
|
|
294
|
+
...bin_count ? { bin_count } : {},
|
|
281
295
|
...extras ? (() => {
|
|
282
296
|
const { multiYAxes: multi_y_axes = false, ...extras_others } = extras.to_dict({ strip: true });
|
|
283
297
|
return {
|
|
@@ -329,8 +343,7 @@ export class DdbObj {
|
|
|
329
343
|
col_labels.length += 2;
|
|
330
344
|
offset += col_labels.length;
|
|
331
345
|
}
|
|
332
|
-
|
|
333
|
-
throw new Error('matrix.datatype !== matrix.type');
|
|
346
|
+
assert(buf_data[offset] === type, 'matrix.datatype === matrix.type');
|
|
334
347
|
const rows = dv.getUint32(offset + 2, le);
|
|
335
348
|
const cols = dv.getUint32(offset + 6, le);
|
|
336
349
|
const [len_items, data] = this.parse_vector_items(buf_data.subarray(offset + 10), le, type, rows * cols // 假设小于 2**32
|
|
@@ -441,38 +454,30 @@ export class DdbObj {
|
|
|
441
454
|
case DdbType.uuid:
|
|
442
455
|
case DdbType.ipaddr:
|
|
443
456
|
case DdbType.int128:
|
|
444
|
-
return [
|
|
445
|
-
16,
|
|
446
|
-
buf.slice(0, 16)
|
|
447
|
-
];
|
|
457
|
+
return [16, buf.slice(0, 16)];
|
|
448
458
|
case DdbType.blob: {
|
|
449
459
|
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
450
460
|
const length = dv.getUint32(0, le);
|
|
451
|
-
return [
|
|
452
|
-
4 + length,
|
|
453
|
-
buf.slice(4, 4 + length)
|
|
454
|
-
];
|
|
461
|
+
return [4 + length, buf.slice(4, 4 + length)];
|
|
455
462
|
}
|
|
456
463
|
case DdbType.complex:
|
|
457
464
|
case DdbType.point: {
|
|
458
465
|
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
459
|
-
return [
|
|
460
|
-
16,
|
|
461
|
-
[
|
|
462
|
-
dv.getFloat64(0, le),
|
|
463
|
-
dv.getFloat64(8, le)
|
|
464
|
-
]
|
|
465
|
-
];
|
|
466
|
+
return [16, [dv.getFloat64(0, le), dv.getFloat64(8, le)]];
|
|
466
467
|
}
|
|
467
468
|
case DdbType.duration: {
|
|
468
469
|
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
469
|
-
return [
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
470
|
+
return [8, { unit: dv.getUint32(4, le), data: dv.getInt32(0, le) }];
|
|
471
|
+
}
|
|
472
|
+
case DdbType.decimal32: {
|
|
473
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
474
|
+
const data = dv.getInt32(4, le);
|
|
475
|
+
return [8, { scale: dv.getInt32(0, le), data: data === nulls.int32 ? null : data }];
|
|
476
|
+
}
|
|
477
|
+
case DdbType.decimal64: {
|
|
478
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
479
|
+
const data = dv.getBigInt64(4, le);
|
|
480
|
+
return [12, { scale: dv.getInt32(0, le), data: data === nulls.int64 ? null : data }];
|
|
476
481
|
}
|
|
477
482
|
default:
|
|
478
483
|
throw new Error(`${DdbType[type] || type} 暂时不支持解析`);
|
|
@@ -633,7 +638,7 @@ export class DdbObj {
|
|
|
633
638
|
// 02 00 00 00 symbol base size = 2
|
|
634
639
|
// 00 61 61 00 以 \0 分割的字符串
|
|
635
640
|
// 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00>
|
|
636
|
-
const dv = new DataView(buf.buffer, buf.byteOffset
|
|
641
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
637
642
|
const base_id = dv.getUint32(0, le);
|
|
638
643
|
const base_size = dv.getUint32(4, le);
|
|
639
644
|
let base_length = 0;
|
|
@@ -668,7 +673,7 @@ export class DdbObj {
|
|
|
668
673
|
// 04 00 00 00 61 62 63 64
|
|
669
674
|
// 04 00 00 00 61 62 63 64>
|
|
670
675
|
let value = new Array(length);
|
|
671
|
-
const dv = new DataView(buf.buffer, buf.byteOffset
|
|
676
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
672
677
|
let i_head = 0;
|
|
673
678
|
for (let i = 0; i < length; i++) {
|
|
674
679
|
const sublen = dv.getUint32(i_head, le);
|
|
@@ -708,6 +713,31 @@ export class DdbObj {
|
|
|
708
713
|
values
|
|
709
714
|
];
|
|
710
715
|
}
|
|
716
|
+
// 25 01 type = decimal32, form = vector
|
|
717
|
+
// 02 00 00 00 01 00 00 00
|
|
718
|
+
// 00 00 00 00 scale = 0
|
|
719
|
+
// 01 00 00 00 data[0] = 1
|
|
720
|
+
// 3a 01 00 00 data[1] = 0x013a = 314
|
|
721
|
+
case DdbType.decimal32: {
|
|
722
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
723
|
+
return [
|
|
724
|
+
4 + 4 * length,
|
|
725
|
+
{
|
|
726
|
+
scale: dv.getInt32(0, le),
|
|
727
|
+
data: new Int32Array(buf.buffer.slice(buf.byteOffset + 4, buf.byteOffset + 4 + 4 * length))
|
|
728
|
+
}
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
case DdbType.decimal64: {
|
|
732
|
+
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
733
|
+
return [
|
|
734
|
+
4 + 8 * length,
|
|
735
|
+
{
|
|
736
|
+
scale: dv.getInt32(0, le),
|
|
737
|
+
data: new BigInt64Array(buf.buffer.slice(buf.byteOffset + 4, buf.byteOffset + 4 + 8 * length))
|
|
738
|
+
}
|
|
739
|
+
];
|
|
740
|
+
}
|
|
711
741
|
// case DdbType.duration: -> 实际会返回一个 any vector
|
|
712
742
|
// [2y, 1M, 3d, 7H, 11m, 12s, 15ms, 16us, 17ns]
|
|
713
743
|
// <Buffer 19 01 type = any, form = vector
|
|
@@ -811,10 +841,7 @@ export class DdbObj {
|
|
|
811
841
|
case DdbType.int128:
|
|
812
842
|
return [this.value];
|
|
813
843
|
case DdbType.blob:
|
|
814
|
-
return [
|
|
815
|
-
Uint32Array.of(this.value.byteLength),
|
|
816
|
-
this.value
|
|
817
|
-
];
|
|
844
|
+
return [Uint32Array.of(this.value.byteLength), this.value];
|
|
818
845
|
case DdbType.complex:
|
|
819
846
|
case DdbType.point:
|
|
820
847
|
return [Float64Array.from(this.value)];
|
|
@@ -822,8 +849,16 @@ export class DdbObj {
|
|
|
822
849
|
const { unit, data } = this.value;
|
|
823
850
|
return [Int32Array.of(data, unit)];
|
|
824
851
|
}
|
|
852
|
+
case DdbType.decimal32: {
|
|
853
|
+
const { scale, data } = this.value;
|
|
854
|
+
return [Int32Array.of(scale, data === null ? nulls.int32 : data)];
|
|
855
|
+
}
|
|
856
|
+
case DdbType.decimal64: {
|
|
857
|
+
const { scale, data } = this.value;
|
|
858
|
+
return [Int32Array.of(scale), BigInt64Array.of(data === null ? nulls.int64 : data)];
|
|
859
|
+
}
|
|
825
860
|
default:
|
|
826
|
-
throw new Error(`${DdbType[type] || type}
|
|
861
|
+
throw new Error(`${DdbType[type] || type} serialization is not currently supported`);
|
|
827
862
|
}
|
|
828
863
|
case DdbForm.vector:
|
|
829
864
|
case DdbForm.pair:
|
|
@@ -843,12 +878,7 @@ export class DdbObj {
|
|
|
843
878
|
...DdbObj.pack_vector_body(value, type, this.rows)
|
|
844
879
|
];
|
|
845
880
|
case DdbForm.set:
|
|
846
|
-
return [
|
|
847
|
-
new DdbObj({
|
|
848
|
-
...this,
|
|
849
|
-
form: DdbForm.vector,
|
|
850
|
-
}).pack()
|
|
851
|
-
];
|
|
881
|
+
return [new DdbObj({ ...this, form: DdbForm.vector }).pack()];
|
|
852
882
|
case DdbForm.table:
|
|
853
883
|
return [
|
|
854
884
|
Uint32Array.of(this.rows, this.cols),
|
|
@@ -860,36 +890,27 @@ export class DdbObj {
|
|
|
860
890
|
...this.value.map(col => col.pack())
|
|
861
891
|
];
|
|
862
892
|
case DdbForm.dict:
|
|
863
|
-
return [
|
|
864
|
-
value[0].pack(),
|
|
865
|
-
value[1].pack(),
|
|
866
|
-
];
|
|
893
|
+
return [value[0].pack(), value[1].pack()];
|
|
867
894
|
case DdbForm.chart: {
|
|
868
|
-
const { type, stacking, titles: { chart, x_axis, y_axis
|
|
895
|
+
const { type, stacking, bin_start, bin_end, bin_count, titles: { chart, x_axis, y_axis }, extras, data } = this.value;
|
|
869
896
|
const { value: [keys, values] } = new DdbDict({
|
|
870
897
|
chartType: new DdbInt(type),
|
|
871
898
|
stacking,
|
|
899
|
+
...bin_start ? { binStart: bin_start, binEnd: bin_end } : {},
|
|
900
|
+
...bin_count ? { binCount: bin_count } : {},
|
|
872
901
|
title: new DdbVectorString([chart, x_axis, y_axis]),
|
|
873
902
|
...extras ? (() => {
|
|
874
903
|
const { multi_y_axes, ...extras_other } = extras;
|
|
875
|
-
return {
|
|
876
|
-
extras: new DdbDict({
|
|
877
|
-
multiYAxes: multi_y_axes,
|
|
878
|
-
...extras_other
|
|
879
|
-
})
|
|
880
|
-
};
|
|
904
|
+
return { extras: new DdbDict({ multiYAxes: multi_y_axes, ...extras_other }) };
|
|
881
905
|
})() : {},
|
|
882
906
|
data,
|
|
883
907
|
});
|
|
884
|
-
return [
|
|
885
|
-
keys.pack(),
|
|
886
|
-
values.pack(),
|
|
887
|
-
];
|
|
908
|
+
return [keys.pack(), values.pack()];
|
|
888
909
|
}
|
|
889
910
|
case DdbForm.matrix: {
|
|
890
911
|
const { rows, cols, data } = value;
|
|
891
912
|
return [
|
|
892
|
-
Uint8Array.of((rows
|
|
913
|
+
Uint8Array.of((rows ? 0x01 : 0x00) | (cols ? 0x02 : 0x00)),
|
|
893
914
|
...rows ? [rows.pack()] : [],
|
|
894
915
|
...cols ? [cols.pack()] : [],
|
|
895
916
|
Uint8Array.of(this.type, this.form),
|
|
@@ -898,7 +919,7 @@ export class DdbObj {
|
|
|
898
919
|
];
|
|
899
920
|
}
|
|
900
921
|
default:
|
|
901
|
-
throw new Error(`${DdbForm[form]}
|
|
922
|
+
throw new Error(`${DdbForm[form]} serialization is not currently supported`);
|
|
902
923
|
}
|
|
903
924
|
})();
|
|
904
925
|
if (!body)
|
|
@@ -987,6 +1008,11 @@ export class DdbObj {
|
|
|
987
1008
|
data
|
|
988
1009
|
];
|
|
989
1010
|
}
|
|
1011
|
+
case DdbType.decimal32:
|
|
1012
|
+
case DdbType.decimal64: {
|
|
1013
|
+
const { scale, data } = value;
|
|
1014
|
+
return [Int32Array.of(scale), data];
|
|
1015
|
+
}
|
|
990
1016
|
default:
|
|
991
1017
|
throw new Error(`vector ${DdbType[type]} 暂不支持序列化`);
|
|
992
1018
|
}
|
|
@@ -1066,6 +1092,15 @@ export class DdbObj {
|
|
|
1066
1092
|
items[i] = format(this.type, value.subarray(2 * i, 2 * (i + 1)), this.le, options);
|
|
1067
1093
|
return format_array(items, len_data > limit);
|
|
1068
1094
|
}
|
|
1095
|
+
case DdbType.decimal32:
|
|
1096
|
+
case DdbType.decimal64: {
|
|
1097
|
+
const limit = 50;
|
|
1098
|
+
const { data } = this.value;
|
|
1099
|
+
let items = new Array(Math.min(limit, data.length));
|
|
1100
|
+
for (let i = 0; i < items.length; i++)
|
|
1101
|
+
items[i] = formati(this, i, options);
|
|
1102
|
+
return format_array(items, data.length > limit);
|
|
1103
|
+
}
|
|
1069
1104
|
default: {
|
|
1070
1105
|
const limit = 50;
|
|
1071
1106
|
let items = new Array(Math.min(limit, this.value.length));
|
|
@@ -1100,7 +1135,7 @@ export class DdbObj {
|
|
|
1100
1135
|
case DdbForm.table:
|
|
1101
1136
|
return `table[${this.rows}r][${this.cols}c]`;
|
|
1102
1137
|
case DdbForm.dict:
|
|
1103
|
-
return `dict<${DdbType[this.value[0].type]}, ${DdbType[this.value[1].type]}
|
|
1138
|
+
return `dict<${DdbType[this.value[0].type]}, ${DdbType[this.value[1].type]}>[${this.rows}]`;
|
|
1104
1139
|
case DdbForm.chart:
|
|
1105
1140
|
return `chart<${DdbChartType[this.value.type]}>`;
|
|
1106
1141
|
case DdbForm.matrix:
|
|
@@ -1128,8 +1163,7 @@ export class DdbObj {
|
|
|
1128
1163
|
return values.map(value => this.to_ddbobj(value));
|
|
1129
1164
|
}
|
|
1130
1165
|
to_rows() {
|
|
1131
|
-
|
|
1132
|
-
throw new Error('this.form is not DdbForm.table, cannot to_rows');
|
|
1166
|
+
assert(this.form === DdbForm.table, 'form must be DdbForm.table, otherwise it cannot to_rows');
|
|
1133
1167
|
let rows = new Array(this.rows);
|
|
1134
1168
|
for (let i = 0; i < this.rows; i++) {
|
|
1135
1169
|
let row = {};
|
|
@@ -1161,13 +1195,10 @@ export class DdbObj {
|
|
|
1161
1195
|
return rows;
|
|
1162
1196
|
}
|
|
1163
1197
|
to_dict({ strip, deep, } = {}) {
|
|
1164
|
-
|
|
1165
|
-
throw new Error('this.form is not DdbForm.dict and cannot be converted to js object');
|
|
1198
|
+
assert(this.form === DdbForm.dict, 'this.form must be DdbForm.dict, otherwise to_dict cannot be called to convert to js object');
|
|
1166
1199
|
const [{ value: keys, type: key_type }, { value: values, type: value_type }] = this.value;
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (deep && !strip)
|
|
1170
|
-
throw new Error('strip = true must be set when deep = true');
|
|
1200
|
+
assert(key_type === DdbType.string && value_type === DdbType.any, 'Currently only supports automatic conversion of dict<string, any> to js object');
|
|
1201
|
+
assert(!(deep && !strip), 'strip = true must be set when deep = true');
|
|
1171
1202
|
let obj = {};
|
|
1172
1203
|
for (let i = 0; i < this.rows; i++) {
|
|
1173
1204
|
let value = values[i];
|
|
@@ -1179,8 +1210,23 @@ export class DdbObj {
|
|
|
1179
1210
|
return obj;
|
|
1180
1211
|
}
|
|
1181
1212
|
}
|
|
1213
|
+
/** 整数一定用这个 number formatter, InspectOptions.decimals 不传也用这个 */
|
|
1214
|
+
let default_formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
|
|
1215
|
+
let _decimals = 20;
|
|
1216
|
+
/** 缓存,为了优化性能,通常 options.decimals 都是不变的 */
|
|
1217
|
+
let _formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
|
|
1182
1218
|
/** Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
|
|
1183
|
-
export function format(type, value, le, options) {
|
|
1219
|
+
export function format(type, value, le, options = {}) {
|
|
1220
|
+
const formatter = (() => {
|
|
1221
|
+
const { decimals } = options;
|
|
1222
|
+
if (decimals === undefined || decimals === null)
|
|
1223
|
+
return default_formatter;
|
|
1224
|
+
if (decimals !== _decimals) {
|
|
1225
|
+
_decimals = decimals;
|
|
1226
|
+
_formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals });
|
|
1227
|
+
}
|
|
1228
|
+
return _formatter;
|
|
1229
|
+
})();
|
|
1184
1230
|
switch (type) {
|
|
1185
1231
|
case DdbType.bool:
|
|
1186
1232
|
return inspect((value === null || value === nulls.int8) ?
|
|
@@ -1198,26 +1244,32 @@ export function format(type, value, le, options) {
|
|
|
1198
1244
|
:
|
|
1199
1245
|
value, options);
|
|
1200
1246
|
case DdbType.short:
|
|
1201
|
-
return
|
|
1202
|
-
null
|
|
1247
|
+
return value === null || value === nulls.int16 ?
|
|
1248
|
+
inspect(null, options)
|
|
1203
1249
|
:
|
|
1204
|
-
|
|
1250
|
+
options.colors ?
|
|
1251
|
+
default_formatter.format(value).green
|
|
1252
|
+
:
|
|
1253
|
+
default_formatter.format(value);
|
|
1205
1254
|
case DdbType.int:
|
|
1206
|
-
return
|
|
1207
|
-
null
|
|
1255
|
+
return value === null || value === nulls.int32 ?
|
|
1256
|
+
inspect(null, options)
|
|
1208
1257
|
:
|
|
1209
|
-
|
|
1258
|
+
options.colors ?
|
|
1259
|
+
default_formatter.format(value).green
|
|
1260
|
+
:
|
|
1261
|
+
default_formatter.format(value);
|
|
1210
1262
|
case DdbType.long:
|
|
1211
|
-
return
|
|
1212
|
-
|
|
1263
|
+
return value === null || value === nulls.int64 ?
|
|
1264
|
+
inspect(null, options)
|
|
1213
1265
|
:
|
|
1214
1266
|
options.colors ?
|
|
1215
|
-
|
|
1267
|
+
default_formatter.format(value).green
|
|
1216
1268
|
:
|
|
1217
|
-
|
|
1269
|
+
default_formatter.format(value);
|
|
1218
1270
|
case DdbType.date:
|
|
1219
1271
|
return (value === null || value === nulls.int32) ?
|
|
1220
|
-
|
|
1272
|
+
inspect(null, options)
|
|
1221
1273
|
:
|
|
1222
1274
|
options.colors ?
|
|
1223
1275
|
date2str(value).green
|
|
@@ -1225,7 +1277,7 @@ export function format(type, value, le, options) {
|
|
|
1225
1277
|
date2str(value);
|
|
1226
1278
|
case DdbType.month:
|
|
1227
1279
|
return (value === null || value === nulls.int32) ?
|
|
1228
|
-
|
|
1280
|
+
inspect(null, options)
|
|
1229
1281
|
:
|
|
1230
1282
|
options.colors ?
|
|
1231
1283
|
month2str(value).green
|
|
@@ -1233,7 +1285,7 @@ export function format(type, value, le, options) {
|
|
|
1233
1285
|
month2str(value);
|
|
1234
1286
|
case DdbType.time:
|
|
1235
1287
|
return (value === null || value === nulls.int32) ?
|
|
1236
|
-
|
|
1288
|
+
inspect(null, options)
|
|
1237
1289
|
:
|
|
1238
1290
|
options.colors ?
|
|
1239
1291
|
time2str(value).green
|
|
@@ -1241,7 +1293,7 @@ export function format(type, value, le, options) {
|
|
|
1241
1293
|
time2str(value);
|
|
1242
1294
|
case DdbType.minute:
|
|
1243
1295
|
return (value === null || value === nulls.int32) ?
|
|
1244
|
-
|
|
1296
|
+
inspect(null, options)
|
|
1245
1297
|
:
|
|
1246
1298
|
options.colors ?
|
|
1247
1299
|
minute2str(value).green
|
|
@@ -1249,7 +1301,7 @@ export function format(type, value, le, options) {
|
|
|
1249
1301
|
minute2str(value);
|
|
1250
1302
|
case DdbType.second:
|
|
1251
1303
|
return (value === null || value === nulls.int32) ?
|
|
1252
|
-
|
|
1304
|
+
inspect(null, options)
|
|
1253
1305
|
:
|
|
1254
1306
|
options.colors ?
|
|
1255
1307
|
second2str(value).green
|
|
@@ -1257,7 +1309,7 @@ export function format(type, value, le, options) {
|
|
|
1257
1309
|
second2str(value);
|
|
1258
1310
|
case DdbType.datetime:
|
|
1259
1311
|
return (value === null || value === nulls.int32) ?
|
|
1260
|
-
|
|
1312
|
+
inspect(null, options)
|
|
1261
1313
|
:
|
|
1262
1314
|
options.colors ?
|
|
1263
1315
|
datetime2str(value).green
|
|
@@ -1265,7 +1317,7 @@ export function format(type, value, le, options) {
|
|
|
1265
1317
|
datetime2str(value);
|
|
1266
1318
|
case DdbType.timestamp:
|
|
1267
1319
|
return (value === null || value === nulls.int64) ?
|
|
1268
|
-
|
|
1320
|
+
inspect(null, options)
|
|
1269
1321
|
:
|
|
1270
1322
|
options.colors ?
|
|
1271
1323
|
timestamp2str(value).green
|
|
@@ -1273,7 +1325,7 @@ export function format(type, value, le, options) {
|
|
|
1273
1325
|
timestamp2str(value);
|
|
1274
1326
|
case DdbType.nanotime:
|
|
1275
1327
|
return (value === null || value === nulls.int64) ?
|
|
1276
|
-
|
|
1328
|
+
inspect(null, options)
|
|
1277
1329
|
:
|
|
1278
1330
|
options.colors ?
|
|
1279
1331
|
nanotime2str(value).green
|
|
@@ -1281,7 +1333,7 @@ export function format(type, value, le, options) {
|
|
|
1281
1333
|
nanotime2str(value);
|
|
1282
1334
|
case DdbType.nanotimestamp:
|
|
1283
1335
|
return (value === null || value === nulls.int64) ?
|
|
1284
|
-
|
|
1336
|
+
inspect(null, options)
|
|
1285
1337
|
:
|
|
1286
1338
|
options.colors ?
|
|
1287
1339
|
nanotimestamp2str(value).green
|
|
@@ -1289,14 +1341,20 @@ export function format(type, value, le, options) {
|
|
|
1289
1341
|
nanotimestamp2str(value);
|
|
1290
1342
|
case DdbType.float:
|
|
1291
1343
|
return (value === null || value === nulls.float32) ?
|
|
1292
|
-
|
|
1344
|
+
inspect(null, options)
|
|
1293
1345
|
:
|
|
1294
|
-
|
|
1346
|
+
options.colors ?
|
|
1347
|
+
formatter.format(value).green
|
|
1348
|
+
:
|
|
1349
|
+
formatter.format(value);
|
|
1295
1350
|
case DdbType.double:
|
|
1296
1351
|
return (value === null || value === nulls.double) ?
|
|
1297
|
-
|
|
1352
|
+
inspect(null, options)
|
|
1298
1353
|
:
|
|
1299
|
-
|
|
1354
|
+
options.colors ?
|
|
1355
|
+
formatter.format(value).green
|
|
1356
|
+
:
|
|
1357
|
+
formatter.format(value);
|
|
1300
1358
|
case DdbType.symbol:
|
|
1301
1359
|
case DdbType.string:
|
|
1302
1360
|
return inspect(value, options);
|
|
@@ -1335,38 +1393,35 @@ export function format(type, value, le, options) {
|
|
|
1335
1393
|
:
|
|
1336
1394
|
DdbObj.dec.decode(value), options);
|
|
1337
1395
|
case DdbType.point: {
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
x = null;
|
|
1341
|
-
if (y === nulls.double)
|
|
1342
|
-
y = null;
|
|
1343
|
-
return options.colors ?
|
|
1344
|
-
`(${String(x).green}, ${String(y).green})`
|
|
1345
|
-
:
|
|
1346
|
-
`(${String(x)}, ${String(y)})`;
|
|
1396
|
+
const [x, y] = value;
|
|
1397
|
+
return `(${format(DdbType.double, x, le, options)}, ${format(DdbType.double, y, le, options)})`;
|
|
1347
1398
|
}
|
|
1348
1399
|
case DdbType.complex: {
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
x = null;
|
|
1352
|
-
if (y === nulls.double)
|
|
1353
|
-
y = null;
|
|
1354
|
-
return options.colors ?
|
|
1355
|
-
`${String(x).green}+${`${String(y)}i`.green}`
|
|
1356
|
-
:
|
|
1357
|
-
`${String(x)}+${String(y)}i`;
|
|
1400
|
+
const [x, y] = value;
|
|
1401
|
+
return `${format(DdbType.double, x, le, options)}+${format(DdbType.double, y, le, options)}i`;
|
|
1358
1402
|
}
|
|
1359
1403
|
case DdbType.duration: {
|
|
1360
1404
|
const { data, unit } = value;
|
|
1361
1405
|
const str = `${data}${DdbDurationUnit[unit]}`;
|
|
1362
1406
|
return options.colors ? str.green : str;
|
|
1363
1407
|
}
|
|
1408
|
+
case DdbType.decimal32:
|
|
1409
|
+
case DdbType.decimal64: {
|
|
1410
|
+
const { scale, data } = value;
|
|
1411
|
+
if (data === null ||
|
|
1412
|
+
(data === nulls.int64 && type === DdbType.decimal64) ||
|
|
1413
|
+
(data === nulls.int32 && type === DdbType.decimal32))
|
|
1414
|
+
return 'null';
|
|
1415
|
+
const s = String(data < 0 ? -data : data).padStart(scale, '0');
|
|
1416
|
+
const str = (data < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1417
|
+
return options.colors ? str.green : str;
|
|
1418
|
+
}
|
|
1364
1419
|
default:
|
|
1365
1420
|
return inspect(value, options);
|
|
1366
1421
|
}
|
|
1367
1422
|
}
|
|
1368
1423
|
/** formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
|
|
1369
|
-
export function formati(obj, index, options) {
|
|
1424
|
+
export function formati(obj, index, options = {}) {
|
|
1370
1425
|
if (64 <= obj.type && obj.type < 128) { // array vector
|
|
1371
1426
|
// 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
|
|
1372
1427
|
// 都对应 TypedArray 中的一格,所以 lengths.length 等于 block 中的 row 的个数
|
|
@@ -1421,6 +1476,17 @@ export function formati(obj, index, options) {
|
|
|
1421
1476
|
case DdbType.complex:
|
|
1422
1477
|
case DdbType.point:
|
|
1423
1478
|
return format(obj.type, obj.value.subarray(2 * index, 2 * (index + 1)), obj.le, options);
|
|
1479
|
+
case DdbType.decimal32:
|
|
1480
|
+
case DdbType.decimal64: {
|
|
1481
|
+
const { scale, data } = obj.value;
|
|
1482
|
+
const x = data[index];
|
|
1483
|
+
if (x === nulls.int64 && obj.type === DdbType.decimal64 ||
|
|
1484
|
+
x === nulls.int32 && obj.type === DdbType.decimal32)
|
|
1485
|
+
return '';
|
|
1486
|
+
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1487
|
+
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1488
|
+
return options.colors ? str.green : str;
|
|
1489
|
+
}
|
|
1424
1490
|
default:
|
|
1425
1491
|
return format(obj.type, obj.value[index], obj.le, options);
|
|
1426
1492
|
}
|
|
@@ -1835,8 +1901,7 @@ export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
|
|
|
1835
1901
|
export function str2timestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
|
|
1836
1902
|
if (!str || str === 'null')
|
|
1837
1903
|
return nulls.int64;
|
|
1838
|
-
|
|
1839
|
-
throw new Error('The length of the timestamp string is not equal to the length of the format string');
|
|
1904
|
+
assert('The length of the timestamp string must be equal to the length of the format string');
|
|
1840
1905
|
return BigInt(-timezone_offset +
|
|
1841
1906
|
dayjs(str, format).valueOf());
|
|
1842
1907
|
}
|
|
@@ -1849,12 +1914,10 @@ export function nanotime2str(nanotime, format = 'HH:mm:ss.SSSSSSSSS') {
|
|
|
1849
1914
|
if (nanotime < 0n)
|
|
1850
1915
|
return String(nanotime);
|
|
1851
1916
|
const i_second_start = format.indexOf('ss');
|
|
1852
|
-
|
|
1853
|
-
throw new Error('The format string must contain the format for seconds (ss)');
|
|
1917
|
+
assert(i_second_start !== -1, 'The format string must contain the format for seconds (ss)');
|
|
1854
1918
|
const i_second_end = i_second_start + 2;
|
|
1855
1919
|
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
1856
|
-
|
|
1857
|
-
throw new Error('The format string must contain the format for nanoseconds (SSSSSSSSS)');
|
|
1920
|
+
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1858
1921
|
return (dayjs(timezone_offset + (Number(nanotime) / 1000000)).format(format.slice(0, i_second_end)) +
|
|
1859
1922
|
format.slice(i_second_end, i_nanosecond_start) +
|
|
1860
1923
|
String(nanotime % 1000000000n).padStart(9, '0'));
|
|
@@ -1882,12 +1945,10 @@ export function nanotimestamp2str(nanotimestamp, format = 'YYYY.MM.DD HH:mm:ss.S
|
|
|
1882
1945
|
if (nanotimestamp === null || nanotimestamp === nulls.int64)
|
|
1883
1946
|
return 'null';
|
|
1884
1947
|
const i_second_start = format.indexOf('ss');
|
|
1885
|
-
|
|
1886
|
-
throw new Error('The format string must contain the format for seconds (ss)');
|
|
1948
|
+
assert(i_second_start !== -1, 'The format string must contain the format for seconds (ss)');
|
|
1887
1949
|
const i_second_end = i_second_start + 2;
|
|
1888
1950
|
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
1889
|
-
|
|
1890
|
-
throw new Error('The format string must contain the format for nanoseconds (SSSSSSSSS)');
|
|
1951
|
+
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1891
1952
|
const remainder = nanotimestamp % 1000000000n;
|
|
1892
1953
|
const borrow = remainder < 0n;
|
|
1893
1954
|
return (dayjs(timezone_offset +
|
|
@@ -1909,15 +1970,12 @@ export function nanotimestamp2str(nanotimestamp, format = 'YYYY.MM.DD HH:mm:ss.S
|
|
|
1909
1970
|
export function str2nanotimestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSSSSSSSS') {
|
|
1910
1971
|
if (!str || str === 'null')
|
|
1911
1972
|
return nulls.int64;
|
|
1912
|
-
|
|
1913
|
-
throw new Error('nanotimestamp string length is not equal to format string length');
|
|
1973
|
+
assert(str.length === format.length, 'nanotimestamp string length must be equal to format string length');
|
|
1914
1974
|
const i_second_start = format.indexOf('ss');
|
|
1915
|
-
|
|
1916
|
-
throw new Error('The format string must contain the format for seconds (ss)');
|
|
1975
|
+
assert(i_second_start !== -1, 'The format string must contain the format for seconds (ss)');
|
|
1917
1976
|
const i_second_end = i_second_start + 2;
|
|
1918
1977
|
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
1919
|
-
|
|
1920
|
-
throw new Error('Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1978
|
+
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1921
1979
|
return (BigInt(-timezone_offset +
|
|
1922
1980
|
dayjs(str.slice(0, i_second_end), format.slice(0, i_second_end)).valueOf()) * 1000000n
|
|
1923
1981
|
+
|
|
@@ -1945,6 +2003,7 @@ export function int1282str(buffer, le = true) {
|
|
|
1945
2003
|
return [...buf].map(x => x.toString(16)
|
|
1946
2004
|
.padStart(2, '0')).join('');
|
|
1947
2005
|
}
|
|
2006
|
+
export const winsize = 40;
|
|
1948
2007
|
export class DDB {
|
|
1949
2008
|
/** 当前的 session id (http 或 tcp) */
|
|
1950
2009
|
sid = '0';
|
|
@@ -1968,13 +2027,18 @@ export class DDB {
|
|
|
1968
2027
|
password = '123456';
|
|
1969
2028
|
/** python session flag (2048) */
|
|
1970
2029
|
python = false;
|
|
2030
|
+
/** Whether it is a streaming data connection, this field is always null for non-streaming data */
|
|
2031
|
+
streaming = null;
|
|
2032
|
+
// --- 内部选项, 状态
|
|
1971
2033
|
print_message_buffer = false;
|
|
1972
2034
|
print_object_buffer = false;
|
|
1973
2035
|
print_message = true;
|
|
1974
2036
|
parse_object = true;
|
|
2037
|
+
pnode_run_defined = false;
|
|
1975
2038
|
/** DdbMessage listeners */
|
|
1976
2039
|
listeners = [];
|
|
1977
2040
|
pconnect = Promise.resolve();
|
|
2041
|
+
ppnoderun = Promise.resolve();
|
|
1978
2042
|
presult = Promise.resolve(null);
|
|
1979
2043
|
get connected() {
|
|
1980
2044
|
return this.websocket?.readyState === WebSocket.OPEN;
|
|
@@ -1988,11 +2052,12 @@ export class DDB {
|
|
|
1988
2052
|
- username?: DolphinDB username, default `'admin'`
|
|
1989
2053
|
- password?: DolphinDB password, default `'123456'`
|
|
1990
2054
|
- python?: set python session flag, default `false`
|
|
2055
|
+
- streaming?: When this option is set, the WebSocket connection is only used for streaming data
|
|
1991
2056
|
|
|
1992
2057
|
@example
|
|
1993
2058
|
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
1994
2059
|
|
|
1995
|
-
//
|
|
2060
|
+
// Encrypt with HTTPS
|
|
1996
2061
|
let ddbsecure = new DDB('wss://dolphindb.com', {
|
|
1997
2062
|
autologin: true,
|
|
1998
2063
|
username: 'admin',
|
|
@@ -2010,8 +2075,13 @@ export class DDB {
|
|
|
2010
2075
|
this.password = options.password;
|
|
2011
2076
|
if (options.python !== undefined)
|
|
2012
2077
|
this.python = options.python;
|
|
2078
|
+
if (options.streaming !== undefined)
|
|
2079
|
+
this.streaming = options.streaming;
|
|
2080
|
+
}
|
|
2081
|
+
on_message(event) {
|
|
2082
|
+
console.log('This is the default on_message before calling this.rpc, it should not be called unless the server pushes the message first after the connection is established');
|
|
2083
|
+
console.log(event.data);
|
|
2013
2084
|
}
|
|
2014
|
-
on_message(event) { }
|
|
2015
2085
|
/** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
|
|
2016
2086
|
- options?:
|
|
2017
2087
|
- url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
|
|
@@ -2019,69 +2089,42 @@ export class DDB {
|
|
|
2019
2089
|
- username?: DolphinDB username, default `'admin'`
|
|
2020
2090
|
- password?: DolphinDB password, default `'123456'`
|
|
2021
2091
|
- python?: set python session flag, default `false`
|
|
2092
|
+
- streaming?: When this option is set, the WebSocket connection is only used for streaming data
|
|
2022
2093
|
*/
|
|
2023
|
-
async connect(
|
|
2024
|
-
if (
|
|
2025
|
-
this.url =
|
|
2026
|
-
if (
|
|
2027
|
-
this.autologin =
|
|
2028
|
-
if (
|
|
2029
|
-
this.username =
|
|
2030
|
-
if (
|
|
2031
|
-
this.password =
|
|
2032
|
-
if (
|
|
2033
|
-
this.python =
|
|
2094
|
+
async connect({ url, autologin, username, password, python, streaming } = {}) {
|
|
2095
|
+
if (url !== undefined)
|
|
2096
|
+
this.url = url;
|
|
2097
|
+
if (autologin !== undefined)
|
|
2098
|
+
this.autologin = autologin;
|
|
2099
|
+
if (username !== undefined)
|
|
2100
|
+
this.username = username;
|
|
2101
|
+
if (password !== undefined)
|
|
2102
|
+
this.password = password;
|
|
2103
|
+
if (python !== undefined)
|
|
2104
|
+
this.python = python;
|
|
2105
|
+
if (streaming !== undefined)
|
|
2106
|
+
this.streaming = streaming;
|
|
2034
2107
|
this.disconnect();
|
|
2035
2108
|
await connect_websocket(this.url, {
|
|
2036
|
-
protocols:
|
|
2109
|
+
protocols: (() => {
|
|
2110
|
+
if (this.streaming)
|
|
2111
|
+
return 'streaming';
|
|
2112
|
+
if (this.python)
|
|
2113
|
+
return 'python';
|
|
2114
|
+
})(),
|
|
2037
2115
|
on_open: async (event, websocket) => {
|
|
2038
2116
|
this.websocket = websocket;
|
|
2039
|
-
|
|
2117
|
+
if (this.streaming)
|
|
2118
|
+
await this.subscribe();
|
|
2119
|
+
else
|
|
2120
|
+
await this.rpc('connect', {});
|
|
2040
2121
|
},
|
|
2041
2122
|
on_message: (event) => {
|
|
2042
2123
|
this.on_message(event);
|
|
2043
2124
|
}
|
|
2044
2125
|
});
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
' nargs = size(args)\n' +
|
|
2048
|
-
' func = funcByName(func_name)\n' +
|
|
2049
|
-
' \n' +
|
|
2050
|
-
' if not nargs:\n' +
|
|
2051
|
-
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2052
|
-
' \n' +
|
|
2053
|
-
' args_partial = [ ]\n' +
|
|
2054
|
-
' args_partial.append(func)\n' +
|
|
2055
|
-
' for a in args:\n' +
|
|
2056
|
-
' args_partial.append(a)\n' +
|
|
2057
|
-
' \n' +
|
|
2058
|
-
' return pnodeRun(\n' +
|
|
2059
|
-
' unifiedCall(partial, args_partial),\n' +
|
|
2060
|
-
' nodes,\n' +
|
|
2061
|
-
' add_node_alias\n' +
|
|
2062
|
-
' )\n'
|
|
2063
|
-
:
|
|
2064
|
-
'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
|
|
2065
|
-
' nargs = size(args)\n' +
|
|
2066
|
-
' func = funcByName(func_name)\n' +
|
|
2067
|
-
' \n' +
|
|
2068
|
-
' if (!nargs)\n' +
|
|
2069
|
-
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2070
|
-
' \n' +
|
|
2071
|
-
' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
|
|
2072
|
-
' args_partial[0] = func\n' +
|
|
2073
|
-
' args_partial[1:] = args\n' +
|
|
2074
|
-
' return pnodeRun(\n' +
|
|
2075
|
-
' unifiedCall(partial, args_partial),\n' +
|
|
2076
|
-
' nodes,\n' +
|
|
2077
|
-
' add_node_alias\n' +
|
|
2078
|
-
' )\n' +
|
|
2079
|
-
'}\n', { urgent: true });
|
|
2080
|
-
if (this.autologin)
|
|
2081
|
-
if (this.python)
|
|
2082
|
-
await this.eval(`login(${this.username.quote('double')}, ${this.password.quote('double')})`, { urgent: true });
|
|
2083
|
-
else
|
|
2084
|
-
await this.call('login', [this.username, this.password], { urgent: true });
|
|
2126
|
+
if (!this.streaming && this.autologin)
|
|
2127
|
+
await this.call('login', [this.username, this.password], { urgent: true });
|
|
2085
2128
|
}
|
|
2086
2129
|
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, } = {}) {
|
|
2087
2130
|
let flag = 0;
|
|
@@ -2120,6 +2163,7 @@ export class DDB {
|
|
|
2120
2163
|
this.on_message = () => { };
|
|
2121
2164
|
this.presult = Promise.resolve(null);
|
|
2122
2165
|
this.pconnect = Promise.resolve();
|
|
2166
|
+
this.pnode_run_defined = false;
|
|
2123
2167
|
}
|
|
2124
2168
|
/** rpc through websocket (function/script/variable command)
|
|
2125
2169
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
@@ -2148,6 +2192,55 @@ export class DDB {
|
|
|
2148
2192
|
}
|
|
2149
2193
|
if (!this.connected)
|
|
2150
2194
|
throw new Error(`${this.url} is already disconnected`);
|
|
2195
|
+
if (func === 'pnode_run' && !this.pnode_run_defined) {
|
|
2196
|
+
const ptail = this.ppnoderun;
|
|
2197
|
+
let resolve;
|
|
2198
|
+
this.ppnoderun = new Promise((_resolve, _reject) => {
|
|
2199
|
+
resolve = _resolve;
|
|
2200
|
+
});
|
|
2201
|
+
await ptail;
|
|
2202
|
+
try {
|
|
2203
|
+
if (!this.pnode_run_defined)
|
|
2204
|
+
await this.eval(this.python ?
|
|
2205
|
+
'def pnode_run (nodes, func_name, args, add_node_alias):\n' +
|
|
2206
|
+
' nargs = size(args)\n' +
|
|
2207
|
+
' func = funcByName(func_name)\n' +
|
|
2208
|
+
' \n' +
|
|
2209
|
+
' if not nargs:\n' +
|
|
2210
|
+
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2211
|
+
' \n' +
|
|
2212
|
+
' args_partial = [ ]\n' +
|
|
2213
|
+
' args_partial.append(func)\n' +
|
|
2214
|
+
' for a in args:\n' +
|
|
2215
|
+
' args_partial.append(a)\n' +
|
|
2216
|
+
' \n' +
|
|
2217
|
+
' return pnodeRun(\n' +
|
|
2218
|
+
' unifiedCall(partial, args_partial),\n' +
|
|
2219
|
+
' nodes,\n' +
|
|
2220
|
+
' add_node_alias\n' +
|
|
2221
|
+
' )\n'
|
|
2222
|
+
:
|
|
2223
|
+
'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
|
|
2224
|
+
' nargs = size(args)\n' +
|
|
2225
|
+
' func = funcByName(func_name)\n' +
|
|
2226
|
+
' \n' +
|
|
2227
|
+
' if (!nargs)\n' +
|
|
2228
|
+
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2229
|
+
' \n' +
|
|
2230
|
+
' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
|
|
2231
|
+
' args_partial[0] = func\n' +
|
|
2232
|
+
' args_partial[1:] = args\n' +
|
|
2233
|
+
' return pnodeRun(\n' +
|
|
2234
|
+
' unifiedCall(partial, args_partial),\n' +
|
|
2235
|
+
' nodes,\n' +
|
|
2236
|
+
' add_node_alias\n' +
|
|
2237
|
+
' )\n' +
|
|
2238
|
+
'}\n', { urgent: true });
|
|
2239
|
+
}
|
|
2240
|
+
finally {
|
|
2241
|
+
resolve();
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2151
2244
|
// this 上的当前配置需要在 message 到达后使用,先保存起来
|
|
2152
2245
|
const _handlers = [...this.listeners].reverse();
|
|
2153
2246
|
// 临界区:保证多个 rpc 并发时形成 promise 链
|
|
@@ -2249,8 +2342,7 @@ export class DDB {
|
|
|
2249
2342
|
*/
|
|
2250
2343
|
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, } = {}) {
|
|
2251
2344
|
if (node) {
|
|
2252
|
-
|
|
2253
|
-
throw new Error('指定 node 时必须设置 func_type');
|
|
2345
|
+
assert(func_type in DdbFunctionType, 'func_type must be set when specifying node');
|
|
2254
2346
|
args = [
|
|
2255
2347
|
node,
|
|
2256
2348
|
new DdbFunction(func, func_type),
|
|
@@ -2287,10 +2379,21 @@ export class DDB {
|
|
|
2287
2379
|
vars,
|
|
2288
2380
|
/** Uploaded variables' value */
|
|
2289
2381
|
args, { listener, parse_object, } = {}) {
|
|
2290
|
-
|
|
2291
|
-
throw new Error('variable command parameter is empty or parameter name is empty, or the number does not match');
|
|
2382
|
+
assert(args.length && args.length === vars.length, 'variable command parameter cannot be empty and parameter name cannot be empty, and the number should match');
|
|
2292
2383
|
return this.rpc('variable', { vars, args, listener, parse_object });
|
|
2293
2384
|
}
|
|
2385
|
+
/** Cancel all console jobs corresponding to the current session id */
|
|
2386
|
+
async cancel() {
|
|
2387
|
+
let ddb = new DDB(this.url, this);
|
|
2388
|
+
try {
|
|
2389
|
+
await ddb.eval(`jobs = exec rootJobId from getConsoleJobs() where sessionId = ${this.sid}\n` +
|
|
2390
|
+
'if (size(jobs))\n' +
|
|
2391
|
+
' cancelConsoleJob(jobs)\n', { urgent: true });
|
|
2392
|
+
}
|
|
2393
|
+
finally {
|
|
2394
|
+
ddb.disconnect();
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2294
2397
|
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
2295
2398
|
parse_message(buf, parse_object = this.parse_object) {
|
|
2296
2399
|
// MSG\n
|
|
@@ -2305,8 +2408,8 @@ export class DDB {
|
|
|
2305
2408
|
// 'OK\n'
|
|
2306
2409
|
// '\x04\x00\x02\x00\x00\x00'
|
|
2307
2410
|
/** index of line feed 0 */
|
|
2308
|
-
const
|
|
2309
|
-
const parts = this.dec.decode(buf.subarray(0,
|
|
2411
|
+
const ilf0 = buf.indexOf(0x0a); // '\n'
|
|
2412
|
+
const parts = this.dec.decode(buf.subarray(0, ilf0)).split(' ');
|
|
2310
2413
|
/** session id */
|
|
2311
2414
|
const sid = parts[0];
|
|
2312
2415
|
if (sid !== this.sid) {
|
|
@@ -2314,34 +2417,141 @@ export class DDB {
|
|
|
2314
2417
|
this.sid = sid;
|
|
2315
2418
|
}
|
|
2316
2419
|
/** 返回对象的数量 */
|
|
2317
|
-
const
|
|
2420
|
+
const nobj = Number(parts[1]);
|
|
2318
2421
|
/** 大小端: 协议中大端为 0, 小端为 1 */
|
|
2319
2422
|
this.le = Number(parts[2]) !== 0;
|
|
2320
|
-
const
|
|
2321
|
-
const
|
|
2423
|
+
const ils1 = ilf0 + 1;
|
|
2424
|
+
const ilf1 = buf.indexOf(0x0a, ils1); // '\n'
|
|
2322
2425
|
/** 'OK' 表示成功,其它文本表示失败 */
|
|
2323
|
-
const message = this.dec.decode(buf.subarray(
|
|
2426
|
+
const message = this.dec.decode(buf.subarray(ils1, ilf1));
|
|
2324
2427
|
if (message !== 'OK')
|
|
2325
2428
|
return {
|
|
2326
2429
|
type: 'error',
|
|
2327
2430
|
data: new Error(message)
|
|
2328
2431
|
};
|
|
2329
|
-
const
|
|
2432
|
+
const bufobj = buf.subarray(ilf1 + 1);
|
|
2330
2433
|
if (this.print_object_buffer)
|
|
2331
|
-
console.log(typed_array_to_buffer(
|
|
2434
|
+
console.log(typed_array_to_buffer(bufobj));
|
|
2332
2435
|
return {
|
|
2333
2436
|
type: 'object',
|
|
2334
2437
|
data: parse_object ?
|
|
2335
|
-
DdbObj.parse(
|
|
2438
|
+
DdbObj.parse(bufobj, this.le)
|
|
2336
2439
|
:
|
|
2337
2440
|
new DdbObj({
|
|
2338
2441
|
form: DdbForm.scalar,
|
|
2339
2442
|
type: DdbType.void,
|
|
2340
2443
|
length: 0,
|
|
2341
2444
|
le: this.le,
|
|
2342
|
-
buffer:
|
|
2445
|
+
buffer: bufobj,
|
|
2343
2446
|
})
|
|
2344
2447
|
};
|
|
2345
2448
|
}
|
|
2449
|
+
/** Internal stream subscription method */
|
|
2450
|
+
async subscribe() {
|
|
2451
|
+
const args = DdbObj.to_ddbobjs([
|
|
2452
|
+
new DdbVectorString(this.autologin ?
|
|
2453
|
+
[this.username, this.password]
|
|
2454
|
+
:
|
|
2455
|
+
// 不自动登录也要传空的 string vector, 否则 server 无法解析
|
|
2456
|
+
[]),
|
|
2457
|
+
// todo: 还有用吗?需要获取客户端 IP 吗
|
|
2458
|
+
'localhost',
|
|
2459
|
+
// todo: 端口还有用吗?
|
|
2460
|
+
new DdbInt(0),
|
|
2461
|
+
this.streaming.table,
|
|
2462
|
+
(this.streaming.action ||= `api_js_${new Date().getTime()}`),
|
|
2463
|
+
// new DdbInt(-1), // offset
|
|
2464
|
+
// filter
|
|
2465
|
+
// allow exists
|
|
2466
|
+
]);
|
|
2467
|
+
return new Promise((resolve, reject) => {
|
|
2468
|
+
let first = true;
|
|
2469
|
+
let second = true;
|
|
2470
|
+
// 先准备好收到 websocket message 的 callback
|
|
2471
|
+
this.on_message = ({ data: buffer }) => {
|
|
2472
|
+
if (first) {
|
|
2473
|
+
first = false;
|
|
2474
|
+
try {
|
|
2475
|
+
const dv = new DataView(buffer);
|
|
2476
|
+
const status = dv.getUint8(1);
|
|
2477
|
+
this.le = Boolean(dv.getUint8(2));
|
|
2478
|
+
const nobjs = dv.getUint32(3, this.le);
|
|
2479
|
+
// 解析返回数据,从 server 实现看其实只有一个 DdbObj
|
|
2480
|
+
let offset = 7;
|
|
2481
|
+
let objs = new Array(nobjs);
|
|
2482
|
+
const buf = new Uint8Array(buffer);
|
|
2483
|
+
for (let i = 0; i < nobjs; i++) {
|
|
2484
|
+
const obj = DdbObj.parse(buf.subarray(offset), this.le);
|
|
2485
|
+
offset += obj.length;
|
|
2486
|
+
objs[i] = obj;
|
|
2487
|
+
console.log(`订阅流表的响应数据: objs[${i}]:`, obj);
|
|
2488
|
+
}
|
|
2489
|
+
this.streaming.colnames = objs[0].value;
|
|
2490
|
+
if (status === StreamingStatusCode.ok)
|
|
2491
|
+
console.log('Subscribed to streaming table:', { status: StreamingStatusCode[status], result: objs[0] });
|
|
2492
|
+
else
|
|
2493
|
+
reject(new Error(`Failed to subscribe to streaming table: { status: ${StreamingStatusCode[status]}, error: ${objs[0]?.value} }`));
|
|
2494
|
+
}
|
|
2495
|
+
catch (error) {
|
|
2496
|
+
reject(error);
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
else {
|
|
2500
|
+
try {
|
|
2501
|
+
const dv = new DataView(buffer);
|
|
2502
|
+
const buf = new Uint8Array(buffer);
|
|
2503
|
+
let { streaming } = this;
|
|
2504
|
+
streaming.time = dv.getBigInt64(1, this.le);
|
|
2505
|
+
streaming.id = dv.getBigInt64(9, this.le);
|
|
2506
|
+
const i_topic_end = buf.indexOf(0, 17);
|
|
2507
|
+
streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
|
|
2508
|
+
if (second) {
|
|
2509
|
+
second = false;
|
|
2510
|
+
// 是 table
|
|
2511
|
+
streaming.schema = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2512
|
+
console.log('Received streaming table schema:', streaming.schema);
|
|
2513
|
+
streaming.window = {
|
|
2514
|
+
offset: 0,
|
|
2515
|
+
rows: 0,
|
|
2516
|
+
segments: [],
|
|
2517
|
+
};
|
|
2518
|
+
assert(streaming.schema.rows === 0, 'schema.rows === 0');
|
|
2519
|
+
resolve(streaming.schema);
|
|
2520
|
+
}
|
|
2521
|
+
else {
|
|
2522
|
+
// 是 column 片段组成的 any vector
|
|
2523
|
+
const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2524
|
+
let { window: win } = streaming;
|
|
2525
|
+
win.rows += data.rows;
|
|
2526
|
+
win.segments.push(data);
|
|
2527
|
+
if (win.rows >= winsize * 2 && win.segments.length >= 2) {
|
|
2528
|
+
let winsize_ = 0;
|
|
2529
|
+
let i = win.segments.length - 1;
|
|
2530
|
+
// 往前移动至首个累计 winsize_ 超过 winsize 的位置
|
|
2531
|
+
for (; winsize_ < winsize; i--)
|
|
2532
|
+
winsize_ += win.segments[i].rows;
|
|
2533
|
+
win.segments = win.segments.slice(i);
|
|
2534
|
+
win.offset += win.rows - winsize_;
|
|
2535
|
+
win.rows = winsize_;
|
|
2536
|
+
console.log('exceeds winsize, shrink window.segments', win);
|
|
2537
|
+
}
|
|
2538
|
+
streaming.handler(streaming);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
catch (error) {
|
|
2542
|
+
reject(error);
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
2546
|
+
// 发送订阅 websocket message
|
|
2547
|
+
this.websocket.send(concat([
|
|
2548
|
+
Uint8Array.of(1, // from = SubscriberFromType::FROM_API
|
|
2549
|
+
1, // type = SubscriberRPCType::RPC_START
|
|
2550
|
+
Number(DDB.le_client)),
|
|
2551
|
+
Uint32Array.of(args.length),
|
|
2552
|
+
...args.map(obj => obj.pack())
|
|
2553
|
+
]));
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2346
2556
|
}
|
|
2347
2557
|
//# sourceMappingURL=index.js.map
|