dolphindb 2.0.801 → 2.0.901

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -126,12 +126,15 @@ export interface DdbArrayVectorBlock {
126
126
  lengths: Uint8Array | Uint16Array | Uint32Array;
127
127
  data: Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array;
128
128
  }
129
+ export type DdbArrayVectorValue = DdbArrayVectorBlock[] & /* decimal32, decimal64 会有这个属性 */ {
130
+ scale?: number;
131
+ };
129
132
  export interface DdbMatrixValue {
130
133
  rows: DdbVectorObj;
131
134
  cols: DdbVectorObj;
132
135
  data: DdbVectorValue;
133
136
  }
134
- export declare type DdbDictValue = [DdbVectorObj, DdbVectorObj];
137
+ export type DdbDictValue = [DdbVectorObj, DdbVectorObj];
135
138
  export declare enum DdbChartType {
136
139
  area = 0,
137
140
  bar = 1,
@@ -166,24 +169,24 @@ export interface DdbChartValue {
166
169
  };
167
170
  data: DdbMatrixObj;
168
171
  }
169
- export declare type DdbScalarValue = null | boolean | number | bigint | string | Uint8Array | // uuid, ipaddr, int128, blob
172
+ export type DdbScalarValue = null | boolean | number | bigint | string | Uint8Array | // uuid, ipaddr, int128, blob
170
173
  [
171
174
  number,
172
175
  number
173
176
  ] | // complex, point
174
177
  DdbFunctionDefValue | DdbDurationValue | DdbDecimal32Value | DdbDecimal64Value;
175
- export declare type DdbVectorValue = Uint8Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | string[] | // string[]
178
+ export type DdbVectorValue = Uint8Array | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array | BigInt64Array | string[] | // string[]
176
179
  Uint8Array[] | // blob
177
180
  DdbObj[] | // any
178
- DdbSymbolExtendedValue | DdbArrayVectorBlock[] | DdbDecimal32VectorValue | DdbDecimal64VectorValue;
179
- export declare type DdbValue = DdbScalarValue | DdbVectorValue | DdbMatrixValue | DdbDictValue | DdbChartValue;
180
- export declare type DdbVectorObj = DdbObj<DdbVectorValue>;
181
- export declare type DdbVectorAnyObj = DdbObj<DdbObj[]>;
182
- export declare type DdbVectorStringObj = DdbObj<string[]>;
183
- export declare type DdbTableObj = DdbObj<DdbVectorObj[]>;
184
- export declare type DdbDictObj = DdbObj<[DdbVectorObj, DdbVectorObj]>;
185
- export declare type DdbMatrixObj = DdbObj<DdbMatrixValue>;
186
- export declare type DdbChartObj = DdbObj<DdbChartValue>;
181
+ DdbSymbolExtendedValue | DdbArrayVectorValue | DdbDecimal32VectorValue | DdbDecimal64VectorValue;
182
+ export type DdbValue = DdbScalarValue | DdbVectorValue | DdbMatrixValue | DdbDictValue | DdbChartValue;
183
+ export type DdbVectorObj = DdbObj<DdbVectorValue>;
184
+ export type DdbVectorAnyObj = DdbObj<DdbObj[]>;
185
+ export type DdbVectorStringObj = DdbObj<string[]>;
186
+ export type DdbTableObj = DdbObj<DdbVectorObj[]>;
187
+ export type DdbDictObj = DdbObj<[DdbVectorObj, DdbVectorObj]>;
188
+ export type DdbMatrixObj = DdbObj<DdbMatrixValue>;
189
+ export type DdbChartObj = DdbObj<DdbChartValue>;
187
190
  export declare const nulls: {
188
191
  readonly int8: -128;
189
192
  readonly int16: -32768;
@@ -194,14 +197,6 @@ export declare const nulls: {
194
197
  readonly double: number;
195
198
  readonly bytes16: Uint8Array;
196
199
  };
197
- export declare const timezone_offset: number;
198
- export declare enum StreamingStatusCode {
199
- ok = 0,
200
- connection_existed = 1,
201
- not_leader = 2,
202
- other = 3,
203
- error = 4
204
- }
205
200
  /** Can represent data types in all DolphinDB databases */
206
201
  export declare class DdbObj<TValue extends DdbValue = DdbValue> {
207
202
  static dec: TextDecoder;
@@ -425,10 +420,10 @@ export interface StreamingData extends StreamingParams {
425
420
  It is a string consisting of the alias of the node where the subscription table is located, the stream data table name, and the subscription task name (if actionName is specified), separated by `/`
426
421
  */
427
422
  topic: string;
428
- /** The schema of the flow table, the type is table, there is no data in the column vector (rows === 0), only the column name and type */
429
- schema: DdbTableObj;
430
423
  /** Stream data, the type is any vector, each element of which corresponds to a column (without name) of the subscribed table, and the content in the column (DdbObj<DdbVectorValue>) is the new data value */
431
424
  data: DdbObj<DdbVectorObj[]>;
425
+ /** Number of new streaming data rows */
426
+ rows: number;
432
427
  window: {
433
428
  /** The establishment of the connection starts offset = 0, and gradually increases as the window moves */
434
429
  offset: number;
@@ -437,8 +432,10 @@ export interface StreamingData extends StreamingParams {
437
432
  /** An array of data received each time */
438
433
  segments: DdbObj<DdbVectorObj[]>[];
439
434
  };
435
+ /** After successfully subscribed, if the subsequently pushed message is parsed incorrectly, the error will be set and the handler will be called. */
436
+ error?: Error;
440
437
  }
441
- export declare const winsize: 40;
438
+ export declare const winsize: 100000;
442
439
  export declare class ConnectionError extends Error {
443
440
  ddb: DDB;
444
441
  constructor(ddb: DDB);
@@ -607,7 +604,7 @@ export declare class DDB {
607
604
  /** 解析服务端响应报文,返回去掉 header 的 data buf */
608
605
  parse_message(buf: Uint8Array, parse_object?: boolean): DdbMessage;
609
606
  /** Internal stream subscription method */
610
- subscribe(): Promise<DdbTableObj>;
607
+ subscribe(): Promise<StreamingData>;
611
608
  }
612
609
  export interface DdbMessageListener {
613
610
  (message: DdbMessage, _this: DDB): any;
@@ -624,4 +621,4 @@ export interface DdbErrorMessage {
624
621
  type: 'error';
625
622
  data: Error;
626
623
  }
627
- export declare type DdbMessage = DdbPrintMessage | DdbObjectMessage | DdbErrorMessage;
624
+ export type DdbMessage = DdbPrintMessage | DdbObjectMessage | DdbErrorMessage;
package/index.js CHANGED
@@ -117,15 +117,6 @@ export const nulls = {
117
117
  double: -Number.MAX_VALUE,
118
118
  bytes16: Uint8Array.from(new Array(16).fill(0))
119
119
  };
120
- export const timezone_offset = 1000 * 60 * new Date().getTimezoneOffset();
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
120
  /** Can represent data types in all DolphinDB databases */
130
121
  export class DdbObj {
131
122
  static dec = new TextDecoder('utf-8');
@@ -521,8 +512,37 @@ export class DdbObj {
521
512
  // 00 reserved
522
513
  // 70 11 01 00 block.lengths = [70000 (0x00011170)]
523
514
  // 01 00 00 00 02 00 00 00 ... 279992 more bytes> block.data
515
+ // decimal array vector
516
+ // a = array(DECIMAL32(2)[], 0, 10)
517
+ // append!(a, [
518
+ // [1, 2, 3],
519
+ // [4, 5],
520
+ // [6, 7, 8],
521
+ // [9, 10]
522
+ // ])
523
+ // print(a)
524
+ // a
525
+ // [[1.00,2.00,3.00],[4.00,5.00],[6.00,7.00,8.00],[9.00,10.00]]
526
+ // <Buffer 65 01 type = 101 = 64 + 37 (decimal32) , form = vector
527
+ // 04 00 00 00 0a 00 00 00 rows = 4, cols = 10
528
+ // scale (只有 decimal32 才有)
529
+ // 02 00 00 00 scale = 2
530
+ // block 0
531
+ // 04 00 block.rows = 4
532
+ // 01 block.unit = 1
533
+ // 00 reserved
534
+ // 03 02 03 02 block.lengths = [3, 2, 3, 2]
535
+ // 64 00 00 00 c8 00 00 00 2c 01 00 00 90 01 00 00 f4 01 00 00 58 02 00 00 bc 02 00 00 ... 12 more bytes> [100, 200, 300, ...]
536
+ // block 1
537
+ // ...
538
+ const type_ = type - 64;
524
539
  const cols = dv.getUint32(4, le);
525
540
  let blocks = [];
541
+ // decimal32/64 会在所有 blocks 之前多一个 scale
542
+ if (type_ === DdbType.decimal32 || type_ === DdbType.decimal64) {
543
+ blocks.scale = dv.getInt32(i_items_start, le);
544
+ i_items_start += 4;
545
+ }
526
546
  let i_block_start = i_items_start;
527
547
  // 解析一个 block
528
548
  for (let i_row = 0; i_row < rows;) {
@@ -551,7 +571,20 @@ export class DdbObj {
551
571
  let total_length = 0;
552
572
  for (const x of lengths)
553
573
  total_length += x;
554
- const [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
574
+ let len_items;
575
+ let data;
576
+ switch (type_) {
577
+ case DdbType.decimal32:
578
+ len_items = total_length * 4;
579
+ data = new Int32Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
580
+ break;
581
+ case DdbType.decimal64:
582
+ len_items = total_length * 8;
583
+ data = new BigInt64Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
584
+ break;
585
+ default:
586
+ [len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
587
+ }
555
588
  blocks.push({
556
589
  unit,
557
590
  rows,
@@ -866,6 +899,10 @@ export class DdbObj {
866
899
  if (form === DdbForm.vector && 64 <= type && type < 128)
867
900
  return [
868
901
  Uint32Array.of(this.rows, this.cols),
902
+ ...(type - 64 === DdbType.decimal32 || type - 64 === DdbType.decimal64) ?
903
+ [Int32Array.of(this.value.scale)]
904
+ :
905
+ [],
869
906
  ...this.value.map(block => ([
870
907
  Uint16Array.of(block.rows),
871
908
  Uint8Array.of(block.unit, 0),
@@ -924,10 +961,7 @@ export class DdbObj {
924
961
  })();
925
962
  if (!body)
926
963
  return new Uint8Array(0);
927
- return concat([
928
- header,
929
- ...body
930
- ]);
964
+ return concat([header, ...body]);
931
965
  }
932
966
  static pack_vector_body(value, type, length) {
933
967
  switch (type) {
@@ -1054,7 +1088,18 @@ export class DdbObj {
1054
1088
  for (const length of lengths) {
1055
1089
  let _items = new Array(Math.min(limit, length));
1056
1090
  for (let i = 0; i < _items.length; i++)
1057
- _items[i] = format(_type, data[acc_len + i], this.le, options);
1091
+ if (_type === DdbType.decimal32 || _type === DdbType.decimal64) {
1092
+ const x = data[acc_len + i];
1093
+ if (x === nulls.int64 && _type === DdbType.decimal64 ||
1094
+ x === nulls.int32 && _type === DdbType.decimal32)
1095
+ return '';
1096
+ const { scale } = this.value;
1097
+ const s = String(x < 0 ? -x : x).padStart(scale, '0');
1098
+ const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1099
+ _items[i] = options.colors ? str.green : str;
1100
+ }
1101
+ else
1102
+ _items[i] = format(_type, data[acc_len + i], this.le, options);
1058
1103
  items[i_items++] = format_array(_items, length > limit);
1059
1104
  acc_len += length;
1060
1105
  }
@@ -1423,6 +1468,7 @@ export function format(type, value, le, options = {}) {
1423
1468
  }
1424
1469
  /** formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
1425
1470
  export function formati(obj, index, options = {}) {
1471
+ assert(index < obj.rows, 'index < obj.rows');
1426
1472
  if (64 <= obj.type && obj.type < 128) { // array vector
1427
1473
  // 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
1428
1474
  // 都对应 TypedArray 中的一格,所以 lengths.length 等于 block 中的 row 的个数
@@ -1450,7 +1496,18 @@ export function formati(obj, index, options = {}) {
1450
1496
  const limit = 10;
1451
1497
  let items = new Array(Math.min(limit, length));
1452
1498
  for (let i = 0; i < items.length; i++)
1453
- items[i] = format(_type, data[acc_len + i], obj.le, options);
1499
+ if (_type === DdbType.decimal32 || _type === DdbType.decimal64) {
1500
+ const x = data[acc_len + i];
1501
+ if (x === nulls.int64 && _type === DdbType.decimal64 ||
1502
+ x === nulls.int32 && _type === DdbType.decimal32)
1503
+ return '';
1504
+ const { scale } = obj.value;
1505
+ const s = String(x < 0 ? -x : x).padStart(scale, '0');
1506
+ const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1507
+ items[i] = options.colors ? str.green : str;
1508
+ }
1509
+ else
1510
+ items[i] = format(_type, data[acc_len + i], obj.le, options);
1454
1511
  return (items.join(', ') + (length > limit ? ', ...' : '')).bracket('square');
1455
1512
  }
1456
1513
  }
@@ -1786,10 +1843,14 @@ export class DdbTable extends DdbObj {
1786
1843
  }
1787
1844
  }
1788
1845
  export function date2ms(date) {
1846
+ // 将 server 的本地时间 (以 ms 为单位,1970.01.01 00:00:00 作为零点) 当成是客户端这里的本地的时间,然后根据本地的时区信息转换为 utc 时间
1847
+ // 本地的时区与实际的时间值相关,timezone offset 可能会受到夏令时 (DST) 的影响
1848
+ // 得到的 utc 毫秒数交给 js date 或者 dayjs 去格式化
1849
+ const ms = 1000 * 3600 * 24 * date;
1789
1850
  return (date === null || date === nulls.int32) ?
1790
1851
  null
1791
1852
  :
1792
- timezone_offset + 1000 * 3600 * 24 * date;
1853
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1793
1854
  }
1794
1855
  export function date2str(date, format = 'YYYY.MM.DD') {
1795
1856
  return (date === null || date === nulls.int32) ?
@@ -1816,7 +1877,7 @@ export function time2ms(time) {
1816
1877
  return (time === null || time === nulls.int32) ?
1817
1878
  null
1818
1879
  :
1819
- timezone_offset + time;
1880
+ 1000 * 60 * new Date(time).getTimezoneOffset() + time;
1820
1881
  }
1821
1882
  export function time2str(time, format = 'HH:mm:ss.SSS') {
1822
1883
  return (time === null || time === nulls.int32) ?
@@ -1825,10 +1886,11 @@ export function time2str(time, format = 'HH:mm:ss.SSS') {
1825
1886
  dayjs(time2ms(time)).format(format);
1826
1887
  }
1827
1888
  export function minute2ms(minute) {
1889
+ const ms = 60 * 1000 * minute;
1828
1890
  return (minute === null || minute === nulls.int32) ?
1829
1891
  null
1830
1892
  :
1831
- timezone_offset + 60 * 1000 * minute;
1893
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1832
1894
  }
1833
1895
  export function minute2str(minute, format = 'HH:mm[m]') {
1834
1896
  return (minute === null || minute === nulls.int32) ?
@@ -1837,10 +1899,11 @@ export function minute2str(minute, format = 'HH:mm[m]') {
1837
1899
  dayjs(minute2ms(minute)).format(format);
1838
1900
  }
1839
1901
  export function second2ms(second) {
1902
+ const ms = 1000 * second;
1840
1903
  return (second === null || second === nulls.int32) ?
1841
1904
  null
1842
1905
  :
1843
- timezone_offset + 1000 * second;
1906
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1844
1907
  }
1845
1908
  export function second2str(second, format = 'HH:mm:ss') {
1846
1909
  return (second === null || second === nulls.int32) ?
@@ -1849,10 +1912,11 @@ export function second2str(second, format = 'HH:mm:ss') {
1849
1912
  dayjs(second2ms(second)).format(format);
1850
1913
  }
1851
1914
  export function datetime2ms(datetime) {
1915
+ const ms = 1000 * datetime;
1852
1916
  return (datetime === null || datetime === nulls.int32) ?
1853
1917
  null
1854
1918
  :
1855
- timezone_offset + 1000 * datetime;
1919
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1856
1920
  }
1857
1921
  export function datetime2str(datetime, format = 'YYYY.MM.DD HH:mm:ss') {
1858
1922
  return (datetime === null || datetime === nulls.int32) ?
@@ -1861,10 +1925,11 @@ export function datetime2str(datetime, format = 'YYYY.MM.DD HH:mm:ss') {
1861
1925
  dayjs(datetime2ms(datetime)).format(format);
1862
1926
  }
1863
1927
  export function timestamp2ms(timestamp) {
1928
+ const ms = Number(timestamp);
1864
1929
  return (timestamp === null || timestamp === nulls.int64) ?
1865
1930
  null
1866
1931
  :
1867
- timezone_offset + Number(timestamp);
1932
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1868
1933
  }
1869
1934
  /** format timestamp (bigint) to string
1870
1935
  - timestamp: bigint value
@@ -1879,16 +1944,18 @@ export function timestamp2str(timestamp, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
1879
1944
  dayjs(timestamp2ms(timestamp)).format(format);
1880
1945
  }
1881
1946
  export function datehour2ms(datehour) {
1947
+ const ms = 1000 * 3600 * datehour;
1882
1948
  return (datehour === null || datehour === nulls.int32) ?
1883
1949
  null
1884
1950
  :
1885
- timezone_offset + 1000 * 3600 * datehour;
1951
+ 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
1886
1952
  }
1887
1953
  export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
1954
+ const ms = 1000 * 3600 * datehour;
1888
1955
  return (datehour === null || datehour === nulls.int32) ?
1889
1956
  'null'
1890
1957
  :
1891
- dayjs(timezone_offset + 1000 * 3600 * datehour).format(format);
1958
+ dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format);
1892
1959
  }
1893
1960
  /** parse timestamp string to bigint value
1894
1961
  - str: timestamp string, If it is an empty string or 'null', it will return the corresponding empty value (nulls.int64)
@@ -1899,9 +1966,10 @@ export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
1899
1966
  export function str2timestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
1900
1967
  if (!str || str === 'null')
1901
1968
  return nulls.int64;
1902
- assert('The length of the timestamp string must be equal to the length of the format string');
1903
- return BigInt(-timezone_offset +
1904
- dayjs(str, format).valueOf());
1969
+ assert(str.length === format.length, 'The length of the timestamp string must be equal to the length of the format string');
1970
+ const ms = dayjs(str, format).valueOf();
1971
+ return BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
1972
+ ms);
1905
1973
  }
1906
1974
  export function nanotime2ns(nanotime) {
1907
1975
  return nanotimestamp2ns(nanotime);
@@ -1916,15 +1984,17 @@ export function nanotime2str(nanotime, format = 'HH:mm:ss.SSSSSSSSS') {
1916
1984
  const i_second_end = i_second_start + 2;
1917
1985
  const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
1918
1986
  assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
1919
- return (dayjs(timezone_offset + (Number(nanotime) / 1000000)).format(format.slice(0, i_second_end)) +
1987
+ const ms = Number(nanotime) / 1000000;
1988
+ return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format.slice(0, i_second_end)) +
1920
1989
  format.slice(i_second_end, i_nanosecond_start) +
1921
1990
  String(nanotime % 1000000000n).padStart(9, '0'));
1922
1991
  }
1923
1992
  export function nanotimestamp2ns(nanotimestamp) {
1993
+ const ms = Number(nanotimestamp / 1000000n);
1924
1994
  return (nanotimestamp === null || nanotimestamp === nulls.int64) ?
1925
1995
  null
1926
1996
  :
1927
- BigInt(timezone_offset) * 1000000n + nanotimestamp;
1997
+ BigInt(1000 * 60 * new Date(ms).getTimezoneOffset()) * 1000000n + nanotimestamp;
1928
1998
  }
1929
1999
  /** format nanotimestamp value (bigint) to string
1930
2000
  - nanotimestamp: bigint value
@@ -1949,7 +2019,8 @@ export function nanotimestamp2str(nanotimestamp, format = 'YYYY.MM.DD HH:mm:ss.S
1949
2019
  assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
1950
2020
  const remainder = nanotimestamp % 1000000000n;
1951
2021
  const borrow = remainder < 0n;
1952
- return (dayjs(timezone_offset +
2022
+ const ms = Number(nanotimestamp / 1000000n);
2023
+ return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() +
1953
2024
  // 去掉 9 位的纳秒部分,转化为毫秒
1954
2025
  Number((nanotimestamp - remainder + (borrow ? -1000000000n : 0n)) / 1000000n)).format(format.slice(0, i_second_end)) +
1955
2026
  format.slice(i_second_end, i_nanosecond_start) +
@@ -1974,8 +2045,9 @@ export function str2nanotimestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSSSSSSSS')
1974
2045
  const i_second_end = i_second_start + 2;
1975
2046
  const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
1976
2047
  assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
1977
- return (BigInt(-timezone_offset +
1978
- dayjs(str.slice(0, i_second_end), format.slice(0, i_second_end)).valueOf()) * 1000000n
2048
+ const ms = dayjs(str.slice(0, i_second_end), format.slice(0, i_second_end)).valueOf();
2049
+ return (BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
2050
+ ms) * 1000000n
1979
2051
  +
1980
2052
  BigInt(str.slice(i_nanosecond_start, i_nanosecond_start + 9)));
1981
2053
  }
@@ -2001,7 +2073,7 @@ export function int1282str(buffer, le = true) {
2001
2073
  return [...buf].map(x => x.toString(16)
2002
2074
  .padStart(2, '0')).join('');
2003
2075
  }
2004
- export const winsize = 40;
2076
+ export const winsize = 10_0000;
2005
2077
  export class ConnectionError extends Error {
2006
2078
  ddb;
2007
2079
  constructor(ddb) {
@@ -2374,8 +2446,9 @@ export class DDB {
2374
2446
  async cancel() {
2375
2447
  let ddb = new DDB(this.url, this);
2376
2448
  try {
2449
+ // 因为是新建的连接,而且执行完脚本之后马上就关闭了,所以不用考虑变量泄漏的问题
2377
2450
  await ddb.eval(`jobs = exec rootJobId from getConsoleJobs() where sessionId = ${this.sid}\n` +
2378
- 'if (size(jobs))\n' +
2451
+ (this.python ? 'if size(jobs):\n' : 'if (size(jobs))\n') +
2379
2452
  ' cancelConsoleJob(jobs)\n', { urgent: true });
2380
2453
  }
2381
2454
  finally {
@@ -2436,110 +2509,58 @@ export class DDB {
2436
2509
  }
2437
2510
  /** Internal stream subscription method */
2438
2511
  async subscribe() {
2439
- const args = DdbObj.to_ddbobjs([
2440
- new DdbVectorString(this.autologin ?
2441
- [this.username, this.password]
2442
- :
2443
- // 不自动登录也要传空的 string vector, 否则 server 无法解析
2444
- []),
2445
- // todo: 还有用吗?需要获取客户端 IP 吗
2512
+ await this.rpc('connect', {});
2513
+ if (this.autologin)
2514
+ await this.call('login', [this.username, this.password]);
2515
+ console.log('Subscribed to streaming table, colnames:',
2516
+ // string[3](['time', 'stock', 'price'])
2517
+ this.streaming.colnames = (await this.call('publishTable', [
2446
2518
  'localhost',
2447
- // todo: 端口还有用吗?
2448
2519
  new DdbInt(0),
2449
2520
  this.streaming.table,
2450
2521
  (this.streaming.action ||= `api_js_${new Date().getTime()}`),
2451
2522
  // new DdbInt(-1), // offset
2452
2523
  // filter
2453
2524
  // allow exists
2454
- ]);
2455
- return new Promise((resolve, reject) => {
2456
- let first = true;
2457
- let second = true;
2458
- // 先准备好收到 websocket message 的 callback
2459
- this.on_message = ({ data: buffer }) => {
2460
- if (first) {
2461
- first = false;
2462
- try {
2463
- const dv = new DataView(buffer);
2464
- const status = dv.getUint8(1);
2465
- this.le = Boolean(dv.getUint8(2));
2466
- const nobjs = dv.getUint32(3, this.le);
2467
- // 解析返回数据,从 server 实现看其实只有一个 DdbObj
2468
- let offset = 7;
2469
- let objs = new Array(nobjs);
2470
- const buf = new Uint8Array(buffer);
2471
- for (let i = 0; i < nobjs; i++) {
2472
- const obj = DdbObj.parse(buf.subarray(offset), this.le);
2473
- offset += obj.length;
2474
- objs[i] = obj;
2475
- console.log(`订阅流表的响应数据: objs[${i}]:`, obj);
2476
- }
2477
- this.streaming.colnames = objs[0].value;
2478
- if (status === StreamingStatusCode.ok)
2479
- console.log('Subscribed to streaming table:', { status: StreamingStatusCode[status], result: objs[0] });
2480
- else
2481
- reject(new Error(`Failed to subscribe to streaming table: { status: ${StreamingStatusCode[status]}, error: ${objs[0]?.value} }`));
2482
- }
2483
- catch (error) {
2484
- reject(error);
2485
- }
2486
- }
2487
- else {
2488
- try {
2489
- const dv = new DataView(buffer);
2490
- const buf = new Uint8Array(buffer);
2491
- let { streaming } = this;
2492
- streaming.time = dv.getBigInt64(1, this.le);
2493
- streaming.id = dv.getBigInt64(9, this.le);
2494
- const i_topic_end = buf.indexOf(0, 17);
2495
- streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
2496
- if (second) {
2497
- second = false;
2498
- // 是 table
2499
- streaming.schema = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2500
- console.log('Received streaming table schema:', streaming.schema);
2501
- streaming.window = {
2502
- offset: 0,
2503
- rows: 0,
2504
- segments: [],
2505
- };
2506
- assert(streaming.schema.rows === 0, 'schema.rows === 0');
2507
- resolve(streaming.schema);
2508
- }
2509
- else {
2510
- // 是 column 片段组成的 any vector
2511
- const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2512
- let { window: win } = streaming;
2513
- win.rows += data.value[0].rows;
2514
- win.segments.push(data);
2515
- if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2516
- let winsize_ = 0;
2517
- let i = win.segments.length - 1;
2518
- // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2519
- for (; winsize_ < winsize; i--)
2520
- winsize_ += win.segments[i].rows;
2521
- win.segments = win.segments.slice(i);
2522
- win.offset += win.rows - winsize_;
2523
- win.rows = winsize_;
2524
- console.log('exceeds winsize, shrink window.segments', win);
2525
- }
2526
- streaming.handler(streaming);
2527
- }
2528
- }
2529
- catch (error) {
2530
- reject(error);
2531
- }
2525
+ ])).value);
2526
+ this.streaming.window = {
2527
+ offset: 0,
2528
+ rows: 0,
2529
+ segments: [],
2530
+ };
2531
+ // 先准备好收到 websocket message 的 callback
2532
+ this.on_message = ({ data: buffer }) => {
2533
+ let { streaming } = this;
2534
+ try {
2535
+ const dv = new DataView(buffer);
2536
+ const buf = new Uint8Array(buffer);
2537
+ streaming.time = dv.getBigInt64(1, this.le);
2538
+ streaming.id = dv.getBigInt64(9, this.le);
2539
+ const i_topic_end = buf.indexOf(0, 17);
2540
+ streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
2541
+ // 是 column 片段组成的 any vector
2542
+ const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2543
+ let { window: win } = streaming;
2544
+ win.rows += streaming.rows = data.value[0].rows;
2545
+ win.segments.push(data);
2546
+ if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2547
+ let winsize_ = 0;
2548
+ let i = win.segments.length - 1;
2549
+ // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2550
+ for (; winsize_ < winsize; i--)
2551
+ winsize_ += win.segments[i].value[0].rows;
2552
+ win.segments = win.segments.slice(i);
2553
+ win.offset += win.rows - winsize_;
2554
+ win.rows = winsize_;
2532
2555
  }
2533
- };
2534
- // 发送订阅 websocket message
2535
- this.websocket.send(concat([
2536
- Uint8Array.of(1, // from = SubscriberFromType::FROM_API
2537
- 1, // type = SubscriberRPCType::RPC_START
2538
- Number(DDB.le_client)),
2539
- Uint32Array.of(args.length),
2540
- ...args.map(obj => obj.pack())
2541
- ]));
2542
- });
2556
+ }
2557
+ catch (error) {
2558
+ // 将 error 交给 handler 处理
2559
+ streaming.error = error;
2560
+ }
2561
+ this.streaming.handler(streaming);
2562
+ };
2563
+ return this.streaming;
2543
2564
  }
2544
2565
  }
2545
2566
  //# sourceMappingURL=index.js.map