dolphindb 2.0.947 → 2.0.949

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 CHANGED
@@ -103,6 +103,11 @@ In the above example, two parameters 1 (corresponding to the int type in Dolphin
103
103
  - result.type is a `DdbType.int`
104
104
  - result.value is native `number` in JavaScript (the value range and precision of int can be accurately represented by JavaScript number)
105
105
 
106
+ It is recommended to first understand the concepts related to TypedArray in JavaScript, you can refer to:
107
+ https://stackoverflow.com/questions/42416783/where-to-use-arraybuffer-vs-typed-array-in-javascript
108
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
109
+
110
+
106
111
  ```ts
107
112
  /** Can represent all data types in DolphinDB databases */
108
113
  class DdbObj <T extends DdbValue = DdbValue> {
package/README.zh.md CHANGED
@@ -100,6 +100,10 @@ console.log(result.value === 2) // true
100
100
  - result.type 是 `DdbType.int`
101
101
  - result.value 是 JavaScript 中原生的 `number` (int 的取值范围及精度可以用 JavaScript 的 number 准确表示)
102
102
 
103
+ 建议先了解一下 JavaScript 中的 TypedArray 相关的概念,可以参考:
104
+ https://stackoverflow.com/questions/42416783/where-to-use-arraybuffer-vs-typed-array-in-javascript
105
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
106
+
103
107
  ```ts
104
108
  /** 可以表示所有 DolphinDB 数据库中的数据类型 */
105
109
  class DdbObj <T extends DdbValue = DdbValue> {
package/browser.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import 'xshell/prototype.browser.js';
2
+ import { Lock } from 'xshell/utils.browser.js';
2
3
  import { type WebSocketConnectionError } from 'xshell/net.browser.js';
3
4
  export declare enum DdbForm {
4
5
  scalar = 0,
@@ -469,6 +470,7 @@ export interface DdbRpcOptions {
469
470
  urgent?: boolean;
470
471
  listener?: DdbMessageListener;
471
472
  parse_object?: boolean;
473
+ skip_connection_check?: boolean;
472
474
  }
473
475
  export declare class DdbConnectionError extends Error {
474
476
  name: string;
@@ -493,7 +495,8 @@ export declare class DDB {
493
495
  e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
494
496
  */
495
497
  url: string;
496
- websocket: WebSocket;
498
+ /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
499
+ lwebsocket: Lock<WebSocket>;
497
500
  /** little endian (server) */
498
501
  le: boolean;
499
502
  /** little endian (client) */
@@ -522,12 +525,12 @@ export declare class DDB {
522
525
  error: DdbConnectionError;
523
526
  /** DdbMessage listeners */
524
527
  listeners: DdbMessageListener[];
525
- /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
526
- pwebsocket: import("xshell/utils.browser.js").Deferred<void>;
527
- /** 为定义 pnode_run 函数加锁,避免重复定义 */
528
- ppnode_run: import("xshell/utils.browser.js").Deferred<void>;
528
+ /** 首次 connect 连接的 promise, 后面的 connect 调用都返回这个 */
529
+ pconnect: Promise<void>;
530
+ /** 首次定义 pnode_run 的 promise,保证并发调用 rpc 时只定义一次 pnode_run */
531
+ ppnode_run: Promise<DdbVoid>;
529
532
  get connected(): boolean;
530
- get errored(): boolean | DdbConnectionError;
533
+ get errored(): boolean;
531
534
  /**
532
535
  使用 WebSocket URL 初始化连接到 DolphinDB 的实例(不建立实际的网络连接)
533
536
  Initialize an instance of DolphinDB Client using the WebSocket URL (without establishing an actual network connection)
@@ -611,7 +614,9 @@ export declare class DDB {
611
614
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
612
615
  - listener?: 处理本次 rpc 期间的消息 (DdbMessage)
613
616
  - parse_object?: 在本次 rpc 期间设置 parse_object, 结束后恢复原有
614
- 为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化 */
617
+ 为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
618
+ - skip_connection_check?: 在首次 await ddb.connect() 建立连接时不能再次调用 await this.connect() 确保连接状态,会导致循环依赖,
619
+ 将这个 flag 设为 true 跳过连接状态检查 */
615
620
  rpc<TResult extends DdbObj = DdbObj>(type: DdbRpcType, options: DdbRpcOptions): Promise<TResult>;
616
621
  /** eval script through websocket (script command)
617
622
  - script?: 执行的脚本 Script to execute
@@ -652,8 +657,11 @@ export declare class DDB {
652
657
  Set parse_object during this rpc, and restore the original after the end.
653
658
  When it is false, the returned DdbObj only contains buffer and le without parsing,
654
659
  so as to facilitate subsequent forwarding and serialization
655
- */
656
- call<TResult extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, }?: {
660
+ - skip_connection_check?: (内部使用) 在首次 await ddb.connect() 建立连接时不能再次调用 await this.connect() 确保连接状态,会导致循环依赖,
661
+ 将这个 flag 设为 true 跳过连接状态检查
662
+ (internal use) When await ddb.connect() establishes a connection for the first time, you cannot call await this.connect() again to ensure the connection status, which will lead to circular dependencies.
663
+ Set this flag to true to skip connection status checks */
664
+ call<TResult extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check }?: {
657
665
  urgent?: boolean;
658
666
  node?: string;
659
667
  nodes?: string[];
@@ -661,6 +669,7 @@ export declare class DDB {
661
669
  add_node_alias?: boolean;
662
670
  listener?: DdbMessageListener;
663
671
  parse_object?: boolean;
672
+ skip_connection_check?: boolean;
664
673
  }): Promise<TResult>;
665
674
  /** upload variable through websocket (variable command) */
666
675
  upload(
package/browser.js CHANGED
@@ -5,7 +5,7 @@ import ipaddrjs from 'ipaddr.js';
5
5
  const { fromByteArray: buf2ipaddr } = ipaddrjs;
6
6
  import 'xshell/prototype.browser.js';
7
7
  import { blue, cyan, green, grey, magenta } from 'xshell/chalk.browser.js';
8
- import { concat, assert, defer } from 'xshell/utils.browser.js';
8
+ import { concat, assert, Lock } from 'xshell/utils.browser.js';
9
9
  import { connect_websocket } from 'xshell/net.browser.js';
10
10
  import { t } from './i18n/index.js';
11
11
  export var DdbForm;
@@ -121,7 +121,7 @@ export const nulls = {
121
121
  bytes16: Uint8Array.from(new Array(16).fill(0))
122
122
  };
123
123
  /** 可以表示所有 DolphinDB 数据库中的数据类型 Can represent data types in all DolphinDB databases */
124
- export class DdbObj {
124
+ class DdbObj {
125
125
  static dec = new TextDecoder('utf-8');
126
126
  static enc = new TextEncoder();
127
127
  /** 维护已解析的 symbol base,比如流数据中后续的 symbol 向量可能只发送一个 base.id, base.size == 0, 依赖之前发送的 symbol base ?
@@ -1284,6 +1284,7 @@ export class DdbObj {
1284
1284
  return obj;
1285
1285
  }
1286
1286
  }
1287
+ export { DdbObj };
1287
1288
  /** 整数一定用这个 number formatter, InspectOptions.decimals 不传也用这个 Integer must use this number formatter, InspectOptions.decimals also use this if not passed */
1288
1289
  let default_formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
1289
1290
  let _decimals = 20;
@@ -2172,7 +2173,7 @@ export class DdbDatabaseError extends Error {
2172
2173
  this.options = options;
2173
2174
  }
2174
2175
  }
2175
- export class DDB {
2176
+ class DDB {
2176
2177
  /** 当前的 session id (http 或 tcp) */
2177
2178
  sid = '0';
2178
2179
  /** utf-8 text decoder */
@@ -2182,7 +2183,8 @@ export class DDB {
2182
2183
  e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
2183
2184
  */
2184
2185
  url;
2185
- websocket = null;
2186
+ /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
2187
+ lwebsocket = new Lock();
2186
2188
  /** little endian (server) */
2187
2189
  le = true;
2188
2190
  /** little endian (client) */
@@ -2212,15 +2214,15 @@ export class DDB {
2212
2214
  error;
2213
2215
  /** DdbMessage listeners */
2214
2216
  listeners = [];
2215
- /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
2216
- pwebsocket = defer(null);
2217
- /** 为定义 pnode_run 函数加锁,避免重复定义 */
2218
- ppnode_run = defer(null);
2217
+ /** 首次 connect 连接的 promise, 后面的 connect 调用都返回这个 */
2218
+ pconnect;
2219
+ /** 首次定义 pnode_run 的 promise,保证并发调用 rpc 时只定义一次 pnode_run */
2220
+ ppnode_run;
2219
2221
  get connected() {
2220
- return !this.error && this.websocket?.readyState === WebSocket.OPEN;
2222
+ return !this.error && this.lwebsocket.resource?.readyState === WebSocket.OPEN;
2221
2223
  }
2222
2224
  get errored() {
2223
- return this.error || (this.websocket && this.websocket.readyState !== WebSocket.OPEN);
2225
+ return Boolean(this.error || (this.lwebsocket.resource && this.lwebsocket.resource.readyState !== WebSocket.OPEN));
2224
2226
  }
2225
2227
  /**
2226
2228
  使用 WebSocket URL 初始化连接到 DolphinDB 的实例(不建立实际的网络连接)
@@ -2287,62 +2289,46 @@ export class DDB {
2287
2289
  throw this.error || new DdbConnectionError(this);
2288
2290
  if (this.connected)
2289
2291
  return;
2290
- // 准备进入 websocket 临界区
2291
- const ptail = this.pwebsocket;
2292
- let pwebsocket = this.pwebsocket = defer();
2293
- // 避免 pwebsocket.reject 后出现 triggerUncaughtException
2294
- pwebsocket.catch(() => { });
2295
- // 上一个请求出现了 websocket 错误,那么直接抛出异常,且通过 reject 当前锁 (pwebsocket),安全退出临界区
2296
- try {
2297
- await ptail;
2298
- // 已进入 websocket 临界区
2299
- }
2300
- catch (error) {
2301
- pwebsocket.reject(error);
2302
- throw error;
2303
- }
2304
- if (this.errored) {
2305
- const error = this.error || new DdbConnectionError(this);
2306
- pwebsocket.reject(error);
2307
- throw error;
2308
- }
2309
- if (this.connected) {
2310
- pwebsocket.resolve();
2311
- return;
2312
- }
2313
- this.on_error = () => {
2314
- pwebsocket.reject(this.error /* 一定有,不需要再 || new DdbConnectionError(this) */);
2315
- };
2316
- try {
2317
- this.websocket = await connect_websocket(this.url, {
2318
- protocols: (() => {
2319
- if (this.streaming)
2320
- return 'streaming';
2321
- if (this.python)
2322
- return 'python';
2323
- })(),
2324
- on_message: (buffer, websocket) => {
2325
- this.on_message(buffer, websocket);
2326
- },
2327
- on_error: error => {
2328
- this.error ??= new DdbConnectionError(this, error);
2329
- this.on_error();
2330
- }
2331
- });
2332
- }
2333
- catch (error) {
2334
- this.error ??= new DdbConnectionError(this, error);
2335
- pwebsocket.reject(error);
2336
- throw this.error;
2337
- }
2338
- assert(this.connected);
2339
- pwebsocket.resolve();
2340
- // websocket 临界区结束
2341
- await this.rpc('connect', {});
2342
- if (this.autologin)
2343
- await this.call('login', [this.username, this.password], { urgent: true });
2344
- if (this.streaming)
2345
- await this.subscribe();
2292
+ return this.pconnect ??= new Promise(async (resolve, reject) => {
2293
+ this.on_error = () => {
2294
+ reject(this.error /* 一定有,不需要再 || new DdbConnectionError(this) */);
2295
+ };
2296
+ try {
2297
+ // 连接建立之前应该不会有别的调用占用 this.lwebsocket
2298
+ this.lwebsocket.resource = await connect_websocket(this.url, {
2299
+ protocols: (() => {
2300
+ if (this.streaming)
2301
+ return 'streaming';
2302
+ if (this.python)
2303
+ return 'python';
2304
+ })(),
2305
+ on_message: (buffer, websocket) => {
2306
+ this.on_message(buffer, websocket);
2307
+ },
2308
+ on_error: error => {
2309
+ this.error ??= new DdbConnectionError(this, error);
2310
+ this.on_error();
2311
+ }
2312
+ });
2313
+ }
2314
+ catch (error) {
2315
+ this.error ??= new DdbConnectionError(this, error);
2316
+ reject(this.error);
2317
+ return;
2318
+ }
2319
+ try {
2320
+ assert(this.connected);
2321
+ await this.rpc('connect', { skip_connection_check: true });
2322
+ if (this.autologin)
2323
+ await this.call('login', [this.username, this.password], { urgent: true, skip_connection_check: true });
2324
+ if (this.streaming)
2325
+ await this.subscribe();
2326
+ resolve();
2327
+ }
2328
+ catch (error) {
2329
+ reject(error);
2330
+ }
2331
+ });
2346
2332
  }
2347
2333
  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, } = {}) {
2348
2334
  let flag = 0;
@@ -2377,7 +2363,8 @@ export class DDB {
2377
2363
  }
2378
2364
  disconnect() {
2379
2365
  if (this.connected)
2380
- this.websocket.close(1000);
2366
+ // 这里不获取 lock,直接关闭连接
2367
+ this.lwebsocket.resource.close(1000);
2381
2368
  }
2382
2369
  /** (内部使用的方法) rpc through websocket (function/script/variable command)
2383
2370
  未连接到 DDB 时调用会自动连接,连接断开时调用会抛出 DdbConnectionError
@@ -2388,165 +2375,138 @@ export class DDB {
2388
2375
  - vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
2389
2376
  - listener?: 处理本次 rpc 期间的消息 (DdbMessage)
2390
2377
  - parse_object?: 在本次 rpc 期间设置 parse_object, 结束后恢复原有
2391
- 为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化 */
2378
+ 为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
2379
+ - skip_connection_check?: 在首次 await ddb.connect() 建立连接时不能再次调用 await this.connect() 确保连接状态,会导致循环依赖,
2380
+ 将这个 flag 设为 true 跳过连接状态检查 */
2392
2381
  async rpc(type, options) {
2393
2382
  // 保留调用栈信息
2394
2383
  let error = new DdbDatabaseError('', this, type, options);
2395
- await this.connect();
2384
+ if (!options.skip_connection_check)
2385
+ await this.connect();
2396
2386
  const { script, func, args: _args = [], vars = [], urgent, listener, } = options;
2397
- if (func === 'pnode_run' && !this.pnode_run_defined) {
2398
- // 准备进入 pnode_run 临界区,保证并发调用 rpc 时只定义一次 pnode_run
2399
- const ptail = this.ppnode_run;
2400
- let ppnode_run = this.ppnode_run = defer();
2401
- // 避免 ppnode_run.reject 后出现 triggerUncaughtException
2402
- ppnode_run.catch(() => { });
2403
- // 如果之前的定义失败了,再定义一次也会失败,直接抛出之前的错误,且安全地退出临界区
2404
- try {
2405
- await ptail;
2406
- // 已进入 pnode_run 临界区
2407
- }
2408
- catch (error) {
2409
- ppnode_run.reject(error);
2410
- throw error;
2411
- }
2412
- if (!this.pnode_run_defined)
2413
- try {
2414
- await this.eval(this.python ?
2415
- 'def pnode_run (nodes, func_name, args, add_node_alias):\n' +
2416
- ' nargs = size(args)\n' +
2417
- ' func = funcByName(func_name)\n' +
2418
- ' \n' +
2419
- ' if not nargs:\n' +
2420
- ' return pnodeRun(func, nodes, add_node_alias)\n' +
2421
- ' \n' +
2422
- ' args_partial = [ ]\n' +
2423
- ' args_partial.append(func)\n' +
2424
- ' for a in args:\n' +
2425
- ' args_partial.append(a)\n' +
2426
- ' \n' +
2427
- ' return pnodeRun(\n' +
2428
- ' unifiedCall(partial, args_partial),\n' +
2429
- ' nodes,\n' +
2430
- ' add_node_alias\n' +
2431
- ' )\n'
2432
- :
2433
- 'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
2434
- ' nargs = size(args)\n' +
2435
- ' func = funcByName(func_name)\n' +
2436
- ' \n' +
2437
- ' if (!nargs)\n' +
2438
- ' return pnodeRun(func, nodes, add_node_alias)\n' +
2439
- ' \n' +
2440
- ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
2441
- ' args_partial[0] = func\n' +
2442
- ' args_partial[1:] = args\n' +
2443
- ' return pnodeRun(\n' +
2444
- ' unifiedCall(partial, args_partial),\n' +
2445
- ' nodes,\n' +
2446
- ' add_node_alias\n' +
2447
- ' )\n' +
2448
- '}\n', { urgent: true });
2449
- this.pnode_run_defined = true;
2450
- ppnode_run.resolve();
2451
- }
2452
- catch (error) {
2453
- // 这次失败了,之后的执行肯定也会失败
2454
- ppnode_run.reject(error);
2455
- throw error;
2456
- }
2457
- }
2387
+ if (func === 'pnode_run')
2388
+ await (this.ppnode_run ??= this.eval(this.python ?
2389
+ '\n' +
2390
+ 'def pnode_run (nodes, func_name, args, add_node_alias):\n' +
2391
+ ' nargs = size(args)\n' +
2392
+ ' func = funcByName(func_name)\n' +
2393
+ ' \n' +
2394
+ ' if not nargs:\n' +
2395
+ ' return pnodeRun(func, nodes, add_node_alias)\n' +
2396
+ ' \n' +
2397
+ ' args_partial = [ ]\n' +
2398
+ ' args_partial.append(func)\n' +
2399
+ ' for a in args:\n' +
2400
+ ' args_partial.append(a)\n' +
2401
+ ' \n' +
2402
+ ' return pnodeRun(\n' +
2403
+ ' unifiedCall(partial, args_partial),\n' +
2404
+ ' nodes,\n' +
2405
+ ' add_node_alias\n' +
2406
+ ' )\n'
2407
+ :
2408
+ // 这个开头的空行很重要,应该可以绕过 webLoginRequired = true 时禁止执行代码
2409
+ // 搜一下 APISocketConsole::execute
2410
+ // https://dolphindb1.atlassian.net/browse/D20-4991
2411
+ '\n' +
2412
+ 'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
2413
+ ' nargs = size(args)\n' +
2414
+ ' func = funcByName(func_name)\n' +
2415
+ ' \n' +
2416
+ ' if (!nargs)\n' +
2417
+ ' return pnodeRun(func, nodes, add_node_alias)\n' +
2418
+ ' \n' +
2419
+ ' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
2420
+ ' args_partial[0] = func\n' +
2421
+ ' args_partial[1:] = args\n' +
2422
+ ' return pnodeRun(\n' +
2423
+ ' unifiedCall(partial, args_partial),\n' +
2424
+ ' nodes,\n' +
2425
+ ' add_node_alias\n' +
2426
+ ' )\n' +
2427
+ '}\n', { urgent: true }));
2458
2428
  // this 上的当前配置需要在 message 到达后使用,先保存起来
2459
2429
  const _listeners = [...this.listeners].reverse();
2460
- // websocket 临界区:保证多个 rpc 并发时形成 promise 链
2430
+ // rpc 请求期间需要独占 websocket,所以设计了一个锁,申请之后才能使用
2461
2431
  // ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
2462
2432
  // 违反世界观可能造成:
2463
2433
  // 1. 并发多个请求只返回第一个结果(阻塞,需后续请求疏通)
2464
2434
  // 2. windows 下 ddb server 返回多个相同的结果
2465
- const ptail = this.pwebsocket;
2466
- let pwebsocket = this.pwebsocket = defer();
2467
- // 避免 pwebsocket.reject 后出现 triggerUncaughtException
2468
- pwebsocket.catch(() => { });
2469
- // 上一个请求出现了 websocket 错误,那么直接抛出异常,且通过 reject 当前锁 (pwebsocket),安全退出临界区
2470
- try {
2471
- await ptail;
2472
- // 已进入临界区,只有一个 rpc 函数调用运行到这里,可以独占 this.on_message 然后写 WebSocket
2473
- }
2474
- catch (error) {
2475
- pwebsocket.reject(error);
2476
- throw error;
2477
- }
2478
2435
  // 既然上一个请求没有出现 websocket error,且函数开头已经调用了 await this.connect() 检查过,
2479
2436
  // 这里也乐观的认为 this.connected && !this.errored 为 true
2480
- return new Promise((resolve, reject) => {
2481
- this.on_error = () => {
2482
- pwebsocket.reject(this.error /* 这里一定有了 this.error, 不需要再 || new DdbConnectionError(this) */);
2483
- reject(this.error);
2484
- };
2485
- this.on_message = buffer => {
2486
- try {
2487
- const buf = new Uint8Array(buffer);
2488
- if (this.print_message_buffer)
2489
- console.log(buf);
2490
- const message = this.parse_message(buf, error);
2491
- listener?.(message, this);
2492
- for (const listener of _listeners)
2493
- listener(message, this);
2494
- const { type, data } = message;
2437
+ return this.lwebsocket.request(async (websocket) => {
2438
+ // 独占资源后先检查状态
2439
+ if (this.errored || !this.connected)
2440
+ throw this.error || new DdbConnectionError(this);
2441
+ // 使用资源发送请求并等待请求完成
2442
+ return new Promise((resolve, reject) => {
2443
+ this.on_error = () => {
2444
+ // 这里一定有了 this.error, 不需要再 || new DdbConnectionError(this)
2445
+ reject(this.error);
2446
+ };
2447
+ this.on_message = buffer => {
2448
+ try {
2449
+ const buf = new Uint8Array(buffer);
2450
+ if (this.print_message_buffer)
2451
+ console.log(buf);
2452
+ const message = this.parse_message(buf, error);
2453
+ listener?.(message, this);
2454
+ for (const listener of _listeners)
2455
+ listener(message, this);
2456
+ const { type, data } = message;
2457
+ switch (type) {
2458
+ case 'print':
2459
+ if (this.print_message)
2460
+ console.log(data);
2461
+ break;
2462
+ case 'object':
2463
+ resolve(data);
2464
+ break;
2465
+ case 'error':
2466
+ reject(data);
2467
+ break;
2468
+ }
2469
+ }
2470
+ catch (error) {
2471
+ // 这里的错误并非 websocket 错误,而是 rpc 错误
2472
+ reject(error);
2473
+ }
2474
+ };
2475
+ const args = DdbObj.to_ddbobjs(_args);
2476
+ const command = this.enc.encode((() => {
2495
2477
  switch (type) {
2496
- case 'print':
2497
- if (this.print_message)
2498
- console.log(data);
2499
- break;
2500
- case 'object':
2501
- pwebsocket.resolve();
2502
- resolve(data);
2503
- break;
2504
- case 'error':
2505
- pwebsocket.resolve();
2506
- reject(data);
2507
- break;
2478
+ case 'function':
2479
+ if (this.verbose)
2480
+ console.log(func + args.map(arg => arg.toString()).join(', ').bracket());
2481
+ return 'function\n' +
2482
+ `${func}\n` +
2483
+ `${args.length}\n` +
2484
+ `${Number(DDB.le_client)}\n`;
2485
+ case 'script':
2486
+ if (this.verbose)
2487
+ console.log(script);
2488
+ return 'script\n' +
2489
+ script;
2490
+ case 'variable':
2491
+ if (this.verbose)
2492
+ for (let i = 0; i < vars.length; i++)
2493
+ console.log(`${vars[i]} = ${args[i].toString()}`);
2494
+ return 'variable\n' +
2495
+ `${vars.join(',')}\n` +
2496
+ `${vars.length}\n` +
2497
+ `${Number(DDB.le_client)}\n`;
2498
+ case 'connect':
2499
+ if (this.verbose)
2500
+ console.log('connect()');
2501
+ return 'connect\n';
2508
2502
  }
2509
- }
2510
- catch (error) {
2511
- pwebsocket.resolve();
2512
- // 这里的错误并非 websocket 错误,而是 rpc 错误
2513
- reject(error);
2514
- }
2515
- };
2516
- const args = DdbObj.to_ddbobjs(_args);
2517
- const command = this.enc.encode((() => {
2518
- switch (type) {
2519
- case 'function':
2520
- if (this.verbose)
2521
- console.log(func + args.map(arg => arg.toString()).join(', ').bracket());
2522
- return 'function\n' +
2523
- `${func}\n` +
2524
- `${args.length}\n` +
2525
- `${Number(DDB.le_client)}\n`;
2526
- case 'script':
2527
- if (this.verbose)
2528
- console.log(script);
2529
- return 'script\n' +
2530
- script;
2531
- case 'variable':
2532
- if (this.verbose)
2533
- for (let i = 0; i < vars.length; i++)
2534
- console.log(`${vars[i]} = ${args[i].toString()}`);
2535
- return 'variable\n' +
2536
- `${vars.join(',')}\n` +
2537
- `${vars.length}\n` +
2538
- `${Number(DDB.le_client)}\n`;
2539
- case 'connect':
2540
- if (this.verbose)
2541
- console.log('connect()');
2542
- return 'connect\n';
2543
- }
2544
- })());
2545
- this.websocket.send(concat([
2546
- this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
2547
- command,
2548
- ...args.map(arg => arg.pack())
2549
- ]));
2503
+ })());
2504
+ websocket.send(concat([
2505
+ this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
2506
+ command,
2507
+ ...args.map(arg => arg.pack())
2508
+ ]));
2509
+ });
2550
2510
  });
2551
2511
  }
2552
2512
  /** eval script through websocket (script command)
@@ -2586,8 +2546,11 @@ export class DDB {
2586
2546
  Set parse_object during this rpc, and restore the original after the end.
2587
2547
  When it is false, the returned DdbObj only contains buffer and le without parsing,
2588
2548
  so as to facilitate subsequent forwarding and serialization
2589
- */
2590
- async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, } = {}) {
2549
+ - skip_connection_check?: (内部使用) 在首次 await ddb.connect() 建立连接时不能再次调用 await this.connect() 确保连接状态,会导致循环依赖,
2550
+ 将这个 flag 设为 true 跳过连接状态检查
2551
+ (internal use) When await ddb.connect() establishes a connection for the first time, you cannot call await this.connect() again to ensure the connection status, which will lead to circular dependencies.
2552
+ Set this flag to true to skip connection status checks */
2553
+ async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check } = {}) {
2591
2554
  if (node) {
2592
2555
  assert(func_type in DdbFunctionType, t('指定 node 时必须设置 func_type'));
2593
2556
  args = [
@@ -2617,7 +2580,8 @@ export class DDB {
2617
2580
  args,
2618
2581
  urgent,
2619
2582
  listener,
2620
- parse_object
2583
+ parse_object,
2584
+ skip_connection_check
2621
2585
  });
2622
2586
  }
2623
2587
  /** upload variable through websocket (variable command) */
@@ -2709,7 +2673,7 @@ export class DDB {
2709
2673
  // new DdbInt(-1), // offset
2710
2674
  // filter
2711
2675
  // allow exists
2712
- ])).value);
2676
+ ], { skip_connection_check: true })).value);
2713
2677
  this.streaming.window = {
2714
2678
  offset: 0,
2715
2679
  rows: 0,
@@ -2751,4 +2715,5 @@ export class DDB {
2751
2715
  return this.streaming;
2752
2716
  }
2753
2717
  }
2718
+ export { DDB };
2754
2719
  //# sourceMappingURL=browser.js.map