hypha-rpc 0.20.48 → 0.20.50

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.
@@ -548,22 +548,24 @@ class RPC extends _utils__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
548
548
 
549
549
  async get_manager_service(config) {
550
550
  config = config || {};
551
-
551
+
552
552
  // Add retry logic
553
553
  const maxRetries = 20;
554
554
  const retryDelay = 500; // 500ms
555
-
555
+
556
556
  for (let attempt = 0; attempt < maxRetries; attempt++) {
557
557
  if (!this._connection.manager_id) {
558
558
  if (attempt < maxRetries - 1) {
559
- console.warn(`Manager ID not set, retrying in ${retryDelay}ms (attempt ${attempt+1}/${maxRetries})`);
560
- await new Promise(resolve => setTimeout(resolve, retryDelay));
559
+ console.warn(
560
+ `Manager ID not set, retrying in ${retryDelay}ms (attempt ${attempt + 1}/${maxRetries})`,
561
+ );
562
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
561
563
  continue;
562
564
  } else {
563
565
  throw new Error("Manager ID not set after maximum retries");
564
566
  }
565
567
  }
566
-
568
+
567
569
  try {
568
570
  const svc = await this.get_remote_service(
569
571
  `*/${this._connection.manager_id}:default`,
@@ -572,8 +574,10 @@ class RPC extends _utils__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
572
574
  return svc;
573
575
  } catch (e) {
574
576
  if (attempt < maxRetries - 1) {
575
- console.warn(`Failed to get manager service, retrying in ${retryDelay}ms: ${e.message}`);
576
- await new Promise(resolve => setTimeout(resolve, retryDelay));
577
+ console.warn(
578
+ `Failed to get manager service, retrying in ${retryDelay}ms: ${e.message}`,
579
+ );
580
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
577
581
  } else {
578
582
  throw e;
579
583
  }
@@ -1519,7 +1523,59 @@ class RPC extends _utils__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
1519
1523
  return bObject;
1520
1524
  }
1521
1525
 
1522
- if (typeof aObject === "function") {
1526
+ if ((0,_utils__WEBPACK_IMPORTED_MODULE_0__.isGenerator)(aObject) || (0,_utils__WEBPACK_IMPORTED_MODULE_0__.isAsyncGenerator)(aObject)) {
1527
+ // Handle generator functions and generator objects
1528
+ (0,_utils__WEBPACK_IMPORTED_MODULE_0__.assert)(
1529
+ session_id && typeof session_id === "string",
1530
+ "Session ID is required for generator encoding",
1531
+ );
1532
+ const object_id = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.randId)();
1533
+
1534
+ // Get the session store
1535
+ const store = this._get_session_store(session_id, true);
1536
+ (0,_utils__WEBPACK_IMPORTED_MODULE_0__.assert)(
1537
+ store !== null,
1538
+ `Failed to create session store ${session_id} due to invalid parent`,
1539
+ );
1540
+
1541
+ // Check if it's an async generator
1542
+ const isAsync = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.isAsyncGenerator)(aObject);
1543
+
1544
+ // Define method to get next item from the generator
1545
+ const nextItemMethod = async () => {
1546
+ if (isAsync) {
1547
+ const iterator = aObject;
1548
+ const result = await iterator.next();
1549
+ if (result.done) {
1550
+ delete store[object_id];
1551
+ return { _rtype: "stop_iteration" };
1552
+ }
1553
+ return result.value;
1554
+ } else {
1555
+ const iterator = aObject;
1556
+ const result = iterator.next();
1557
+ if (result.done) {
1558
+ delete store[object_id];
1559
+ return { _rtype: "stop_iteration" };
1560
+ }
1561
+ return result.value;
1562
+ }
1563
+ };
1564
+
1565
+ // Store the next_item method in the session
1566
+ store[object_id] = nextItemMethod;
1567
+
1568
+ // Create a method that will be used to fetch the next item from the generator
1569
+ bObject = {
1570
+ _rtype: "generator",
1571
+ _rserver: this._server_base_url,
1572
+ _rtarget: this._client_id,
1573
+ _rmethod: `${session_id}.${object_id}`,
1574
+ _rpromise: "*",
1575
+ _rdoc: "Remote generator",
1576
+ };
1577
+ return bObject;
1578
+ } else if (typeof aObject === "function") {
1523
1579
  if (this._method_annotations.has(aObject)) {
1524
1580
  let annotation = this._method_annotations.get(aObject);
1525
1581
  bObject = {
@@ -1765,6 +1821,38 @@ class RPC extends _utils__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
1765
1821
  remote_workspace,
1766
1822
  local_workspace,
1767
1823
  );
1824
+ } else if (aObject._rtype === "generator") {
1825
+ // Create a method to fetch next items from the remote generator
1826
+ const gen_method = this._generate_remote_method(
1827
+ aObject,
1828
+ remote_parent,
1829
+ local_parent,
1830
+ remote_workspace,
1831
+ local_workspace,
1832
+ );
1833
+
1834
+ // Create an async generator proxy
1835
+ async function* asyncGeneratorProxy() {
1836
+ try {
1837
+ while (true) {
1838
+ try {
1839
+ const next_item = await gen_method();
1840
+ // Check for StopIteration signal
1841
+ if (next_item && next_item._rtype === "stop_iteration") {
1842
+ break;
1843
+ }
1844
+ yield next_item;
1845
+ } catch (error) {
1846
+ console.error("Error in generator:", error);
1847
+ throw error;
1848
+ }
1849
+ }
1850
+ } catch (error) {
1851
+ console.error("Error in generator:", error);
1852
+ throw error;
1853
+ }
1854
+ }
1855
+ bObject = asyncGeneratorProxy();
1768
1856
  } else if (aObject._rtype === "ndarray") {
1769
1857
  /*global nj tf*/
1770
1858
  //create build array/tensor if used in the plugin
@@ -1935,6 +2023,8 @@ __webpack_require__.r(__webpack_exports__);
1935
2023
  /* harmony export */ convertCase: () => (/* binding */ convertCase),
1936
2024
  /* harmony export */ dtypeToTypedArray: () => (/* binding */ dtypeToTypedArray),
1937
2025
  /* harmony export */ expandKwargs: () => (/* binding */ expandKwargs),
2026
+ /* harmony export */ isAsyncGenerator: () => (/* binding */ isAsyncGenerator),
2027
+ /* harmony export */ isGenerator: () => (/* binding */ isGenerator),
1938
2028
  /* harmony export */ loadRequirements: () => (/* binding */ loadRequirements),
1939
2029
  /* harmony export */ loadRequirementsInWebworker: () => (/* binding */ loadRequirementsInWebworker),
1940
2030
  /* harmony export */ loadRequirementsInWindow: () => (/* binding */ loadRequirementsInWindow),
@@ -2456,6 +2546,40 @@ class Semaphore {
2456
2546
  }
2457
2547
  }
2458
2548
 
2549
+ /**
2550
+ * Check if the object is a generator
2551
+ * @param {Object} obj - Object to check
2552
+ * @returns {boolean} - True if the object is a generator
2553
+ */
2554
+ function isGenerator(obj) {
2555
+ if (!obj) return false;
2556
+
2557
+ return (
2558
+ typeof obj === "object" &&
2559
+ typeof obj.next === "function" &&
2560
+ typeof obj.throw === "function" &&
2561
+ typeof obj.return === "function"
2562
+ );
2563
+ }
2564
+
2565
+ /**
2566
+ * Check if an object is an async generator object
2567
+ * @param {any} obj - Object to check
2568
+ * @returns {boolean} True if object is an async generator object
2569
+ */
2570
+ function isAsyncGenerator(obj) {
2571
+ if (!obj) return false;
2572
+ // Check if it's an async generator object
2573
+ return (
2574
+ typeof obj === "object" &&
2575
+ typeof obj.next === "function" &&
2576
+ typeof obj.throw === "function" &&
2577
+ typeof obj.return === "function" &&
2578
+ Symbol.asyncIterator in Object(obj) &&
2579
+ obj[Symbol.toStringTag] === "AsyncGenerator"
2580
+ );
2581
+ }
2582
+
2459
2583
 
2460
2584
  /***/ }),
2461
2585
 
@@ -2522,7 +2646,13 @@ class WebRTCConnection {
2522
2646
  this._handle_disconnected = null;
2523
2647
  this._handle_connected = () => {};
2524
2648
  this.manager_id = null;
2649
+ this._last_message = null;
2525
2650
  this._data_channel.onopen = async () => {
2651
+ if (this._last_message) {
2652
+ console.info("Resending last message after connection established");
2653
+ this._data_channel.send(this._last_message);
2654
+ this._last_message = null;
2655
+ }
2526
2656
  this._handle_connected &&
2527
2657
  this._handle_connected({ channel: this._data_channel });
2528
2658
  };
@@ -2557,15 +2687,17 @@ class WebRTCConnection {
2557
2687
  async emit_message(data) {
2558
2688
  (0,_utils__WEBPACK_IMPORTED_MODULE_1__.assert)(this._handle_message, "No handler for message");
2559
2689
  try {
2690
+ this._last_message = data;
2560
2691
  this._data_channel.send(data);
2692
+ this._last_message = null;
2561
2693
  } catch (exp) {
2562
- // data = msgpack_unpackb(data);
2563
2694
  console.error(`Failed to send data, error: ${exp}`);
2564
2695
  throw exp;
2565
2696
  }
2566
2697
  }
2567
2698
 
2568
2699
  async disconnect(reason) {
2700
+ this._last_message = null;
2569
2701
  this._data_channel = null;
2570
2702
  console.info(`data channel connection disconnected (${reason})`);
2571
2703
  }
@@ -4800,6 +4932,7 @@ class WebsocketRPCConnection {
4800
4932
  this._token_refresh_interval = token_refresh_interval;
4801
4933
  this.manager_id = null;
4802
4934
  this._refresh_token_task = null;
4935
+ this._last_message = null; // Store the last sent message
4803
4936
  }
4804
4937
 
4805
4938
  on_message(handler) {
@@ -5038,6 +5171,12 @@ class WebsocketRPCConnection {
5038
5171
  `Reconnecting to ${this._server_url.split("?")[0]} (attempt #${retry})`,
5039
5172
  );
5040
5173
  await this.open();
5174
+ // Resend last message if there was one
5175
+ if (this._last_message) {
5176
+ console.info("Resending last message after reconnection");
5177
+ this._websocket.send(this._last_message);
5178
+ this._last_message = null;
5179
+ }
5041
5180
  console.warn(
5042
5181
  `Successfully reconnected to server ${this._server_url}`,
5043
5182
  );
@@ -5083,7 +5222,9 @@ class WebsocketRPCConnection {
5083
5222
  await this.open();
5084
5223
  }
5085
5224
  try {
5225
+ this._last_message = data; // Store the message before sending
5086
5226
  this._websocket.send(data);
5227
+ this._last_message = null; // Clear after successful send
5087
5228
  } catch (exp) {
5088
5229
  console.error(`Failed to send data, error: ${exp}`);
5089
5230
  throw exp;
@@ -5092,6 +5233,7 @@ class WebsocketRPCConnection {
5092
5233
 
5093
5234
  disconnect(reason) {
5094
5235
  this._closed = true;
5236
+ this._last_message = null; // Clear last message on disconnect
5095
5237
  if (this._websocket && this._websocket.readyState === WebSocket.OPEN) {
5096
5238
  this._websocket.close(1000, reason);
5097
5239
  }
@@ -5213,20 +5355,20 @@ async function connectToServer(config) {
5213
5355
  "Failed to connect to the server, no connection info obtained. This issue is most likely due to an outdated Hypha server version. Please use `imjoy-rpc` for compatibility, or upgrade the Hypha server to the latest version.",
5214
5356
  );
5215
5357
  // wait for 0.5 seconds
5216
- await new Promise(resolve => setTimeout(resolve, 100));
5358
+ await new Promise((resolve) => setTimeout(resolve, 100));
5217
5359
  // Ensure manager_id is set before proceeding
5218
5360
  if (!connection.manager_id) {
5219
5361
  console.warn("Manager ID not set immediately, waiting...");
5220
-
5362
+
5221
5363
  // Wait for manager_id to be set with timeout
5222
5364
  const maxWaitTime = 5000; // 5 seconds
5223
5365
  const checkInterval = 100; // 100ms
5224
5366
  const startTime = Date.now();
5225
-
5226
- while (!connection.manager_id && (Date.now() - startTime) < maxWaitTime) {
5227
- await new Promise(resolve => setTimeout(resolve, checkInterval));
5367
+
5368
+ while (!connection.manager_id && Date.now() - startTime < maxWaitTime) {
5369
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
5228
5370
  }
5229
-
5371
+
5230
5372
  if (!connection.manager_id) {
5231
5373
  console.error("Manager ID still not set after waiting");
5232
5374
  throw new Error("Failed to get manager ID from server");
@@ -5239,7 +5381,7 @@ async function connectToServer(config) {
5239
5381
  `Connected to the wrong workspace: ${connection_info.workspace}, expected: ${config.workspace}`,
5240
5382
  );
5241
5383
  }
5242
-
5384
+
5243
5385
  const workspace = connection_info.workspace;
5244
5386
  const rpc = new _rpc_js__WEBPACK_IMPORTED_MODULE_0__.RPC(connection, {
5245
5387
  client_id: clientId,