hypha-rpc 0.1.3 → 0.1.5

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.
@@ -172,7 +172,6 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
172
172
  connection,
173
173
  {
174
174
  client_id = null,
175
- manager_id = null,
176
175
  default_context = null,
177
176
  name = null,
178
177
  codecs = null,
@@ -192,7 +191,6 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
192
191
  this._name = name;
193
192
  this._app_id = app_id || "*";
194
193
  this._local_workspace = workspace;
195
- this.manager_id = manager_id;
196
194
  this._silent = silent;
197
195
  this.default_context = default_context || {};
198
196
  this._method_annotations = new WeakMap();
@@ -226,20 +224,28 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
226
224
  this.on("error", console.error);
227
225
 
228
226
  (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.assert)(connection.emit_message && connection.on_message);
227
+ (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.assert)(
228
+ connection.manager_id !== undefined,
229
+ "Connection must have manager_id",
230
+ );
229
231
  this._emit_message = connection.emit_message.bind(connection);
230
232
  connection.on_message(this._on_message.bind(this));
231
233
  this._connection = connection;
232
234
  const updateServices = async () => {
233
- if (!this._silent && this.manager_id) {
235
+ if (!this._silent && this._connection.manager_id) {
234
236
  console.log("Connection established, reporting services...");
235
237
  for (let service of Object.values(this._services)) {
236
238
  const serviceInfo = this._extract_service_info(service);
237
239
  await this.emit({
238
240
  type: "service-added",
239
- to: "*/" + this.manager_id,
241
+ to: "*/" + this._connection.manager_id,
240
242
  service: serviceInfo,
241
243
  });
242
244
  }
245
+ } else {
246
+ console.log(
247
+ "Connection established, no manager id to report services",
248
+ );
243
249
  }
244
250
  };
245
251
  connection.on_connect(updateServices);
@@ -366,11 +372,10 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
366
372
  }
367
373
 
368
374
  _on_message(message) {
369
- if(typeof message === "string"){
375
+ if (typeof message === "string") {
370
376
  const main = JSON.parse(message);
371
377
  this._fire(main["type"], main);
372
- }
373
- else if (message instanceof ArrayBuffer) {
378
+ } else if (message instanceof ArrayBuffer) {
374
379
  let unpacker = (0,_msgpack_msgpack__WEBPACK_IMPORTED_MODULE_1__.decodeMulti)(message);
375
380
  const { done, value } = unpacker.next();
376
381
  const main = value;
@@ -382,8 +387,7 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
382
387
  Object.assign(main, extra.value);
383
388
  }
384
389
  this._fire(main["type"], main);
385
- }
386
- else{
390
+ } else {
387
391
  throw new Error("Invalid message format");
388
392
  }
389
393
  }
@@ -399,9 +403,9 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
399
403
  }
400
404
 
401
405
  async get_manager_service(timeout) {
402
- (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.assert)(this.manager_id, "Manager id is not set");
406
+ (0,_utils_js__WEBPACK_IMPORTED_MODULE_0__.assert)(this._connection.manager_id, "Manager id is not set");
403
407
  const svc = await this.get_remote_service(
404
- `*/${this.manager_id}:default`,
408
+ `*/${this._connection.manager_id}:default`,
405
409
  timeout,
406
410
  );
407
411
  return svc;
@@ -440,8 +444,8 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
440
444
  }
441
445
  async get_remote_service(service_uri, timeout) {
442
446
  timeout = timeout === undefined ? this._method_timeout : timeout;
443
- if (!service_uri && this.manager_id) {
444
- service_uri = "*/" + this.manager_id;
447
+ if (!service_uri && this._connection.manager_id) {
448
+ service_uri = "*/" + this._connection.manager_id;
445
449
  } else if (!service_uri.includes(":")) {
446
450
  service_uri = this._client_id + ":" + service_uri;
447
451
  }
@@ -616,10 +620,10 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
616
620
  const service = this.add_service(api, overwrite);
617
621
  const serviceInfo = this._extract_service_info(service);
618
622
  if (notify) {
619
- if (this.manager_id) {
623
+ if (this._connection.manager_id) {
620
624
  await this.emit({
621
625
  type: "service-added",
622
- to: "*/" + this.manager_id,
626
+ to: "*/" + this._connection.manager_id,
623
627
  service: serviceInfo,
624
628
  });
625
629
  } else {
@@ -643,10 +647,10 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
643
647
  delete this._services[service];
644
648
  if (notify) {
645
649
  const serviceInfo = this._extract_service_info(api);
646
- if (this.manager_id) {
650
+ if (this._connection.manager_id) {
647
651
  this.emit({
648
652
  type: "service-removed",
649
- to: "*/" + this.manager_id,
653
+ to: "*/" + this._connection.manager_id,
650
654
  service: serviceInfo,
651
655
  });
652
656
  } else {
@@ -1045,7 +1049,8 @@ class RPC extends _utils_js__WEBPACK_IMPORTED_MODULE_0__.MessageEmitter {
1045
1049
  if (this._method_annotations.get(method).visibility === "protected") {
1046
1050
  if (
1047
1051
  local_workspace !== remote_workspace &&
1048
- (remote_workspace !== "*" || remote_client_id !== this.manager_id)
1052
+ (remote_workspace !== "*" ||
1053
+ remote_client_id !== this._connection.manager_id)
1049
1054
  ) {
1050
1055
  throw new Error(
1051
1056
  "Permission denied for invoking protected method " +
@@ -1973,9 +1978,10 @@ class WebRTCConnection {
1973
1978
  this._reconnection_token = null;
1974
1979
  this._disconnect_handler = null;
1975
1980
  this._handle_connect = () => {};
1976
- this._data_channel.onopen = async ()=>{
1981
+ this.manager_id = null;
1982
+ this._data_channel.onopen = async () => {
1977
1983
  this._handle_connect && this._handle_connect();
1978
- }
1984
+ };
1979
1985
  this._data_channel.onmessage = async (event) => {
1980
1986
  let data = event.data;
1981
1987
  if (data instanceof Blob) {
@@ -1985,8 +1991,7 @@ class WebRTCConnection {
1985
1991
  };
1986
1992
  const self = this;
1987
1993
  this._data_channel.onclose = function () {
1988
- if(this._disconnect_handler)
1989
- this._disconnect_handler("closed");
1994
+ if (this._disconnect_handler) this._disconnect_handler("closed");
1990
1995
  console.log("websocket closed");
1991
1996
  self._data_channel = null;
1992
1997
  };
@@ -2032,7 +2037,6 @@ async function _setupRPC(config) {
2032
2037
  config.context.connection_type = "webrtc";
2033
2038
  const rpc = new _rpc_js__WEBPACK_IMPORTED_MODULE_0__.RPC(connection, {
2034
2039
  client_id: clientId,
2035
- manager_id: null,
2036
2040
  default_context: config.context,
2037
2041
  name: config.name,
2038
2042
  method_timeout: config.method_timeout || 10.0,
@@ -2059,7 +2063,7 @@ async function _createOffer(params, server, config, onInit, context) {
2059
2063
  pc.addEventListener("datachannel", async (event) => {
2060
2064
  const channel = event.channel;
2061
2065
  let ctx = null;
2062
- if (context && context.user) ctx = { user: context.user, ws: context.ws};
2066
+ if (context && context.user) ctx = { user: context.user, ws: context.ws };
2063
2067
  const rpc = await _setupRPC({
2064
2068
  channel: channel,
2065
2069
  client_id: channel.label,
@@ -2106,11 +2110,9 @@ async function getRTCService(server, service_id, config) {
2106
2110
  if (pc.connectionState === "failed") {
2107
2111
  pc.close();
2108
2112
  reject(new Error("WebRTC Connection failed"));
2109
- }
2110
- else if (pc.connectionState === "closed") {
2113
+ } else if (pc.connectionState === "closed") {
2111
2114
  reject(new Error("WebRTC Connection closed"));
2112
- }
2113
- else{
2115
+ } else {
2114
2116
  console.log("WebRTC Connection state: ", pc.connectionState);
2115
2117
  }
2116
2118
  },
@@ -4189,12 +4191,13 @@ class WebsocketRPCConnection {
4189
4191
  this._handle_message = null;
4190
4192
  this._handle_connect = null; // Connection open event handler
4191
4193
  this._disconnect_handler = null; // Disconnection event handler
4192
- this._timeout = timeout * 1000; // Convert seconds to milliseconds
4194
+ this._timeout = timeout;
4193
4195
  this._WebSocketClass = WebSocketClass || WebSocket; // Allow overriding the WebSocket class
4194
4196
  this._closed = false;
4195
4197
  this._legacy_auth = null;
4196
4198
  this.connection_info = null;
4197
4199
  this._enable_reconnect = false;
4200
+ this.manager_id = null;
4198
4201
  }
4199
4202
 
4200
4203
  on_message(handler) {
@@ -4223,7 +4226,7 @@ class WebsocketRPCConnection {
4223
4226
 
4224
4227
  websocket.onerror = (event) => {
4225
4228
  console.error("WebSocket connection error:", event);
4226
- reject(event);
4229
+ reject(new Error(`ConnectionAbortedError: ${event}`));
4227
4230
  };
4228
4231
 
4229
4232
  websocket.onclose = (event) => {
@@ -4274,61 +4277,61 @@ class WebsocketRPCConnection {
4274
4277
  const data = event.data;
4275
4278
  const first_message = JSON.parse(data);
4276
4279
  if (first_message.type == "connection_info") {
4277
- console.log(
4278
- "Successfully connected: " + JSON.stringify(first_message),
4279
- );
4280
4280
  this.connection_info = first_message;
4281
+ if (this._workspace) {
4282
+ (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.assert)(
4283
+ this.connection_info.workspace === this._workspace,
4284
+ `Connected to the wrong workspace: ${this.connection_info.workspace}, expected: ${this._workspace}`,
4285
+ );
4286
+ }
4281
4287
  if (this.connection_info.reconnection_token) {
4282
- this._reconnection_token =
4283
- this.connection_info.reconnection_token;
4288
+ this._reconnection_token = this.connection_info.reconnection_token;
4284
4289
  }
4290
+ this.manager_id = this.connection_info.manager_id || null;
4291
+ console.log(
4292
+ `Successfully connected to the server, workspace: ${this.connection_info.workspace}, manager_id: ${this.manager_id}`,
4293
+ );
4285
4294
  resolve(this.connection_info);
4286
- }
4287
- else if (first_message.type == "error") {
4295
+ } else if (first_message.type == "error") {
4288
4296
  const error = first_message.error || "Unknown error";
4289
4297
  console.error("Failed to connect, " + error);
4290
- this.connection_info = null;
4291
4298
  reject(new Error(error));
4292
4299
  return;
4293
4300
  } else {
4294
- console.error(
4295
- "Unexpected message received from the server:",
4296
- data,
4297
- );
4301
+ console.error("Unexpected message received from the server:", data);
4298
4302
  reject(new Error("Unexpected message received from the server"));
4299
4303
  return;
4300
4304
  }
4301
-
4302
4305
  };
4303
- })
4306
+ });
4304
4307
  }
4305
4308
 
4306
4309
  async open() {
4307
- if (this._closed){
4308
- throw new Error("Connection is closing");
4309
- }
4310
- console.log("Creating a new websocket connection to", this._server_url.split("?")[0]);
4310
+ console.log(
4311
+ "Creating a new websocket connection to",
4312
+ this._server_url.split("?")[0],
4313
+ );
4311
4314
  try {
4312
4315
  this._websocket = await this._attempt_connection(this._server_url);
4313
- if (!this._legacy_auth) {
4314
- // Send authentication info as the first message if connected without query params
4315
- const authInfo = JSON.stringify({
4316
- client_id: this._client_id,
4317
- workspace: this._workspace,
4318
- token: this._token,
4319
- reconnection_token: this._reconnection_token,
4320
- });
4321
- this._websocket.send(authInfo);
4322
- // Wait for the first message from the server
4323
- await (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.waitFor)(
4324
- this._establish_connection(),
4325
- this._timeout / 1000.0,
4326
- "Failed to receive the first message from the server",
4316
+ if (this._legacy_auth) {
4317
+ throw new Error(
4318
+ "NotImplementedError: Legacy authentication is not supported",
4327
4319
  );
4328
4320
  }
4329
- else{
4330
- throw new Error("Legacy authentication is not supported");
4331
- }
4321
+ // Send authentication info as the first message if connected without query params
4322
+ const authInfo = JSON.stringify({
4323
+ client_id: this._client_id,
4324
+ workspace: this._workspace,
4325
+ token: this._token,
4326
+ reconnection_token: this._reconnection_token,
4327
+ });
4328
+ this._websocket.send(authInfo);
4329
+ // Wait for the first message from the server
4330
+ await (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.waitFor)(
4331
+ this._establish_connection(),
4332
+ this._timeout,
4333
+ "Failed to receive the first message from the server",
4334
+ );
4332
4335
  // Listen to messages from the server
4333
4336
  this._enable_reconnect = true;
4334
4337
  this._closed = false;
@@ -4343,30 +4346,58 @@ class WebsocketRPCConnection {
4343
4346
  }
4344
4347
  return this.connection_info;
4345
4348
  } catch (error) {
4346
- console.error("Failed to connect to", this._server_url.split("?")[0], error);
4349
+ console.error(
4350
+ "Failed to connect to",
4351
+ this._server_url.split("?")[0],
4352
+ error,
4353
+ );
4347
4354
  throw error;
4348
4355
  }
4349
4356
  }
4350
4357
 
4351
4358
  _handle_close(event) {
4352
- if (!this._closed && this._websocket && this._websocket.readyState === WebSocket.CLOSED) {
4359
+ if (
4360
+ !this._closed &&
4361
+ this._websocket &&
4362
+ this._websocket.readyState === WebSocket.CLOSED
4363
+ ) {
4353
4364
  if ([1000].includes(event.code)) {
4354
- console.info("Websocket connection closed (code: %s): %s", event.code, event.reason);
4365
+ console.info(
4366
+ "Websocket connection closed (code: %s): %s",
4367
+ event.code,
4368
+ event.reason,
4369
+ );
4355
4370
  if (this._disconnect_handler) {
4356
4371
  this._disconnect_handler(event.reason);
4357
4372
  }
4358
4373
  this._closed = true;
4359
4374
  } else if (this._enable_reconnect) {
4360
- console.warn("Websocket connection closed unexpectedly (code: %s): %s", event.code, event.reason);
4375
+ console.warn(
4376
+ "Websocket connection closed unexpectedly (code: %s): %s",
4377
+ event.code,
4378
+ event.reason,
4379
+ );
4361
4380
  let retry = 0;
4362
4381
  const reconnect = async () => {
4363
4382
  try {
4364
- console.info("Reconnecting to", this._server_url.split("?")[0]);
4383
+ console.info(
4384
+ `Reconnecting to ${this._server_url.split("?")[0]} (attempt #${retry})`,
4385
+ );
4365
4386
  await this.open();
4366
4387
  } catch (e) {
4388
+ if (`${e}`.includes("ConnectionAbortedError")) {
4389
+ console.warn("Failed to reconnect, connection aborted:", e);
4390
+ return;
4391
+ } else if (`${e}`.includes("NotImplementedError")) {
4392
+ console.warn("Failed to reconnect, connection aborted:", e);
4393
+ return;
4394
+ }
4367
4395
  console.warn("Failed to reconnect:", e);
4368
4396
  await new Promise((resolve) => setTimeout(resolve, 1000));
4369
- if(this._websocket && this._websocket.readyState === WebSocket.CONNECTED){
4397
+ if (
4398
+ this._websocket &&
4399
+ this._websocket.readyState === WebSocket.CONNECTED
4400
+ ) {
4370
4401
  return;
4371
4402
  }
4372
4403
  retry += 1;
@@ -4405,7 +4436,6 @@ class WebsocketRPCConnection {
4405
4436
  this._closed = true;
4406
4437
  if (this._websocket && this._websocket.readyState === WebSocket.OPEN) {
4407
4438
  this._websocket.close(1000, reason);
4408
-
4409
4439
  }
4410
4440
  console.info(`WebSocket connection disconnected (${reason})`);
4411
4441
  }
@@ -4471,21 +4501,19 @@ async function connectToServer(config) {
4471
4501
  config.WebSocketClass,
4472
4502
  );
4473
4503
  const connection_info = await connection.open();
4474
- (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.assert)(connection_info, "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.");
4475
- if (
4476
- config.workspace &&
4477
- connection_info.workspace !== config.workspace
4478
- ) {
4504
+ (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__.assert)(
4505
+ connection_info,
4506
+ "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.",
4507
+ );
4508
+ if (config.workspace && connection_info.workspace !== config.workspace) {
4479
4509
  throw new Error(
4480
4510
  `Connected to the wrong workspace: ${connection_info.workspace}, expected: ${config.workspace}`,
4481
4511
  );
4482
4512
  }
4483
4513
  const workspace = connection_info.workspace;
4484
- const manager_id = connection_info.manager_id;
4485
4514
  const rpc = new _rpc_js__WEBPACK_IMPORTED_MODULE_0__.RPC(connection, {
4486
4515
  client_id: clientId,
4487
4516
  workspace,
4488
- manager_id,
4489
4517
  default_context: { connection_type: "websocket" },
4490
4518
  name: config.name,
4491
4519
  method_timeout: config.method_timeout,
@@ -4519,9 +4547,9 @@ async function connectToServer(config) {
4519
4547
  wm.registerCodec = rpc.register_codec.bind(rpc);
4520
4548
  wm.emit = rpc.emit;
4521
4549
  wm.on = rpc.on;
4522
- if (rpc.manager_id) {
4550
+ if (connection.manager_id) {
4523
4551
  rpc.on("force-exit", async (message) => {
4524
- if (message.from === "*/" + rpc.manager_id) {
4552
+ if (message.from === "*/" + connection.manager_id) {
4525
4553
  console.log("Disconnecting from server, reason:", message.reason);
4526
4554
  await disconnect();
4527
4555
  }