Skip to content

Commit

Permalink
refactor(websocket)!: change .connect() api (#225)
Browse files Browse the repository at this point in the history
* feat: allow url to be undefined in .connect functions

* doc: update docs

* doc: clarify optional url parameter

* refactor: .connect() functions all take the same optional WebsocketOptions arg for specifying url & timeout

* test: update tests to reflect new api

* chore: remove accidental doc change
  • Loading branch information
mattyg authored Feb 23, 2024
1 parent d922ed6 commit 7d1cc0c
Show file tree
Hide file tree
Showing 21 changed files with 167 additions and 82 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ npm install --save-exact @holochain/client
```typescript
import { ActionHash, AdminWebsocket, AppAgentWebsocket, CellType } from "@holochain/client";

const adminWs = await AdminWebsocket.connect("ws://127.0.0.1:65000");
const adminWs = await AdminWebsocket.connect({url: "ws://127.0.0.1:65000"});
const agent_key = await adminWs.generateAgentPubKey();
const role_name = "role";
const installed_app_id = "test-app";
Expand All @@ -51,10 +51,7 @@ if (!(CellType.Provisioned in appInfo.cell_info[role_name][0])) {
const { cell_id } = appInfo.cell_info[role_name][0][CellType.Provisioned];
await adminWs.authorizeSigningCredentials(cell_id);
await adminWs.attachAppInterface({ port: 65001 });
const appAgentWs = await AppAgentWebsocket.connect(
"ws://127.0.0.1:65001",
installed_app_id
);
const appAgentWs = await AppAgentWebsocket.connect(installed_app_id, {url: "ws://127.0.0.1:65001"});

const zomeCallPayload: CallZomeRequest = {
cell_id,
Expand All @@ -74,7 +71,7 @@ await adminWs.client.close();
```typescript
import { AdminWebsocket, AppWebsocket, CellType } from "@holochain/client";

const adminWs = await AdminWebsocket.connect("ws://127.0.0.1:65000");
const adminWs = await AdminWebsocket.connect({url: "ws://127.0.0.1:65000"});
const agent_key = await adminWs.generateAgentPubKey();
const installed_app_id = "test-app";
const appInfo = await adminWs.installApp({
Expand All @@ -90,7 +87,7 @@ if (!(CellType.Provisioned in appInfo.cell_info["role"][0])) {
const { cell_id } = appInfo.cell_info["role"][0][CellType.Provisioned];
await adminWs.authorizeSigningCredentials(cell_id);
await adminWs.attachAppInterface({ port: 65001 });
const appWs = await AppWebsocket.connect("ws://127.0.0.1:65001");
const appWs = await AppWebsocket.connect({url: "ws://127.0.0.1:65001"});

let signalCb;
const signalReceived = new Promise<void>((resolve) => {
Expand Down
5 changes: 2 additions & 3 deletions docs/client.adminwebsocket.connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ Factory mehtod to create a new instance connected to the given URL.
**Signature:**

```typescript
static connect(url: URL, defaultTimeout?: number): Promise<AdminWebsocket>;
static connect(options?: WebsocketConnectionOptions): Promise<AdminWebsocket>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| url | URL | A <code>ws://</code> URL used as the connection address. |
| defaultTimeout | number | _(Optional)_ The default timeout for any request. |
| options | [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) | _(Optional)_ [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) |

**Returns:**

Expand Down
2 changes: 1 addition & 1 deletion docs/client.adminwebsocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ export declare class AdminWebsocket implements AdminApi
| Method | Modifiers | Description |
| --- | --- | --- |
| [\_requester(tag, transformer)](./client.adminwebsocket._requester.md) | | |
| [connect(url, defaultTimeout)](./client.adminwebsocket.connect.md) | <code>static</code> | Factory mehtod to create a new instance connected to the given URL. |
| [connect(options)](./client.adminwebsocket.connect.md) | <code>static</code> | Factory mehtod to create a new instance connected to the given URL. |
5 changes: 2 additions & 3 deletions docs/client.appagentwebsocket.connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ Instance factory for creating AppAgentWebsockets.
**Signature:**

```typescript
static connect(url: URL, installed_app_id: InstalledAppId, defaultTimeout?: number): Promise<AppAgentWebsocket>;
static connect(installed_app_id: InstalledAppId, options?: WebsocketConnectionOptions): Promise<AppAgentWebsocket>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| url | URL | The <code>ws://</code> URL of the App API to connect to. |
| installed\_app\_id | [InstalledAppId](./client.installedappid.md) | ID of the App to link to. |
| defaultTimeout | number | _(Optional)_ Timeout to default to for all operations. |
| options | [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) | _(Optional)_ [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) |

**Returns:**

Expand Down
2 changes: 1 addition & 1 deletion docs/client.appagentwebsocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export declare class AppAgentWebsocket implements AppAgentClient
| --- | --- | --- |
| [appInfo()](./client.appagentwebsocket.appinfo.md) | | Request the app's info, including all cell infos. |
| [callZome(request, timeout)](./client.appagentwebsocket.callzome.md) | | Call a zome. |
| [connect(url, installed\_app\_id, defaultTimeout)](./client.appagentwebsocket.connect.md) | <code>static</code> | Instance factory for creating AppAgentWebsockets. |
| [connect(installed\_app\_id, options)](./client.appagentwebsocket.connect.md) | <code>static</code> | Instance factory for creating AppAgentWebsockets. |
| [createCloneCell(args)](./client.appagentwebsocket.createclonecell.md) | | Clone an existing provisioned cell. |
| [disableCloneCell(args)](./client.appagentwebsocket.disableclonecell.md) | | Disable an enabled clone cell. |
| [enableCloneCell(args)](./client.appagentwebsocket.enableclonecell.md) | | Enable a disabled clone cell. |
Expand Down
5 changes: 2 additions & 3 deletions docs/client.appwebsocket.connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ Instance factory for creating AppWebsockets.
**Signature:**

```typescript
static connect(url: URL, defaultTimeout?: number): Promise<AppWebsocket>;
static connect(options?: WebsocketConnectionOptions): Promise<AppWebsocket>;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| url | URL | The <code>ws://</code> URL of the App API to connect to. |
| defaultTimeout | number | _(Optional)_ Timeout to default to for all operations. |
| options | [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) | _(Optional)_ [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) |

**Returns:**

Expand Down
2 changes: 1 addition & 1 deletion docs/client.appwebsocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ export declare class AppWebsocket extends Emittery implements AppApi
| Method | Modifiers | Description |
| --- | --- | --- |
| [\_requester(tag, transformer)](./client.appwebsocket._requester.md) | | |
| [connect(url, defaultTimeout)](./client.appwebsocket.connect.md) | <code>static</code> | Instance factory for creating AppWebsockets. |
| [connect(options)](./client.appwebsocket.connect.md) | <code>static</code> | Instance factory for creating AppWebsockets. |
1 change: 1 addition & 0 deletions docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
| [StorageInfo](./client.storageinfo.md) | |
| [Update](./client.update.md) | |
| [UpdateBase](./client.updatebase.md) | |
| [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) | Options for a Websocket connection. |
| [ZomeCallCapGrant](./client.zomecallcapgrant.md) | |
| [ZomeDependency](./client.zomedependency.md) | |

Expand Down
13 changes: 13 additions & 0 deletions docs/client.websocketconnectionoptions.defaulttimeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@holochain/client](./client.md) &gt; [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) &gt; [defaultTimeout](./client.websocketconnectionoptions.defaulttimeout.md)

## WebsocketConnectionOptions.defaultTimeout property

Timeout to default to for all operations.

**Signature:**

```typescript
defaultTimeout?: number;
```
21 changes: 21 additions & 0 deletions docs/client.websocketconnectionoptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@holochain/client](./client.md) &gt; [WebsocketConnectionOptions](./client.websocketconnectionoptions.md)

## WebsocketConnectionOptions interface

Options for a Websocket connection.

**Signature:**

```typescript
export interface WebsocketConnectionOptions
```

## Properties

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [defaultTimeout?](./client.websocketconnectionoptions.defaulttimeout.md) | | number | _(Optional)_ Timeout to default to for all operations. |
| [url?](./client.websocketconnectionoptions.url.md) | | URL | _(Optional)_ The <code>ws://</code> URL of the Websocket server to connect to. Not required when connecting to App API from a Launcher or Kangaroo environment. |

13 changes: 13 additions & 0 deletions docs/client.websocketconnectionoptions.url.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@holochain/client](./client.md) &gt; [WebsocketConnectionOptions](./client.websocketconnectionoptions.md) &gt; [url](./client.websocketconnectionoptions.url.md)

## WebsocketConnectionOptions.url property

The `ws://` URL of the Websocket server to connect to. Not required when connecting to App API from a Launcher or Kangaroo environment.

**Signature:**

```typescript
url?: URL;
```
4 changes: 2 additions & 2 deletions docs/client.wsclient._constructor_.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ Constructs a new instance of the `WsClient` class
**Signature:**

```typescript
constructor(socket: IsoWebSocket, url: URL);
constructor(socket: IsoWebSocket, url?: URL);
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| socket | IsoWebSocket | |
| url | URL | |
| url | URL | _(Optional)_ |

19 changes: 12 additions & 7 deletions src/api/admin/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import type { AgentPubKey, CellId } from "../../types.js";
import { WsClient } from "../client.js";
import {
WebsocketConnectionOptions,
catchError,
DEFAULT_TIMEOUT,
promiseTimeout,
Expand Down Expand Up @@ -90,23 +91,27 @@ export class AdminWebsocket implements AdminApi {
/**
* Factory mehtod to create a new instance connected to the given URL.
*
* @param url - A `ws://` URL used as the connection address.
* @param defaultTimeout - The default timeout for any request.
* @param options - {@link (WebsocketConnectionOptions:interface)}
* @returns A promise for a new connected instance.
*/
static async connect(
url: URL,
defaultTimeout?: number
options: WebsocketConnectionOptions = {}
): Promise<AdminWebsocket> {
// Check if we are in the launcher's environment, and if so, redirect the url to connect to
const env = getLauncherEnvironment();

if (env?.ADMIN_INTERFACE_PORT) {
url = new URL(`ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}`);
options.url = new URL(`ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}`);
}

const wsClient = await WsClient.connect(url);
return new AdminWebsocket(wsClient, defaultTimeout);
if (!options.url) {
throw new Error(
"Unable to connect to Admin Websocket: No url provided and not in a Launcher environment."
);
}

const wsClient = await WsClient.connect(options.url);
return new AdminWebsocket(wsClient, options.defaultTimeout);
}

_requester<ReqI, ReqO, ResI, ResO>(
Expand Down
14 changes: 8 additions & 6 deletions src/api/app-agent/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import {
NetworkInfoResponse,
} from "../app/types.js";
import { AppWebsocket } from "../app/websocket.js";
import { getBaseRoleNameFromCloneId, isCloneId } from "../common.js";
import {
WebsocketConnectionOptions,
getBaseRoleNameFromCloneId,
isCloneId,
} from "../common.js";
import {
AppAgentCallZomeRequest,
AppAgentClient,
Expand Down Expand Up @@ -88,17 +92,15 @@ export class AppAgentWebsocket implements AppAgentClient {
/**
* Instance factory for creating AppAgentWebsockets.
*
* @param url - The `ws://` URL of the App API to connect to.
* @param installed_app_id - ID of the App to link to.
* @param defaultTimeout - Timeout to default to for all operations.
* @param options - {@link (WebsocketConnectionOptions:interface)}
* @returns A new instance of an AppAgentWebsocket.
*/
static async connect(
url: URL,
installed_app_id: InstalledAppId,
defaultTimeout?: number
options: WebsocketConnectionOptions = {}
) {
const appWebsocket = await AppWebsocket.connect(url, defaultTimeout);
const appWebsocket = await AppWebsocket.connect(options);
const appInfo = await appWebsocket.appInfo({
installed_app_id: installed_app_id,
});
Expand Down
18 changes: 12 additions & 6 deletions src/api/app/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { InstalledAppId } from "../../types.js";
import { encodeHashToBase64 } from "../../utils/base64.js";
import { WsClient } from "../client.js";
import {
WebsocketConnectionOptions,
DEFAULT_TIMEOUT,
Requester,
Transformer,
Expand Down Expand Up @@ -79,23 +80,28 @@ export class AppWebsocket extends Emittery implements AppApi {
/**
* Instance factory for creating AppWebsockets.
*
* @param url - The `ws://` URL of the App API to connect to.
* @param defaultTimeout - Timeout to default to for all operations.
* @param options - {@link (WebsocketConnectionOptions:interface)}
* @returns A new instance of an AppWebsocket.
*/
static async connect(url: URL, defaultTimeout?: number) {
static async connect(options: WebsocketConnectionOptions = {}) {
// Check if we are in the launcher's environment, and if so, redirect the url to connect to
const env = getLauncherEnvironment();

if (env?.APP_INTERFACE_PORT) {
url = new URL(`ws://127.0.0.1:${env.APP_INTERFACE_PORT}`);
options.url = new URL(`ws://127.0.0.1:${env.APP_INTERFACE_PORT}`);
}

const wsClient = await WsClient.connect(url);
if (!options.url) {
throw new Error(
"Unable to connect to App Websocket: No url provided and not in a Launcher environment."
);
}

const wsClient = await WsClient.connect(options.url);

const appWebsocket = new AppWebsocket(
wsClient,
defaultTimeout,
options.defaultTimeout,
env?.INSTALLED_APP_ID
);

Expand Down
2 changes: 1 addition & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class WsClient extends Emittery {
private pendingRequests: Record<number, HolochainRequest>;
private index: number;

constructor(socket: IsoWebSocket, url: URL) {
constructor(socket: IsoWebSocket, url?: URL) {
super();
this.socket = socket;
this.url = url;
Expand Down
17 changes: 17 additions & 0 deletions src/api/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,20 @@ export class CloneId {
return this.roleName;
}
}

/**
* Options for a Websocket connection.
*
* @public
*/
export interface WebsocketConnectionOptions {
/**
* The `ws://` URL of the Websocket server to connect to. Not required when connecting to App API from a Launcher or Kangaroo environment.
*/
url?: URL;

/**
* Timeout to default to for all operations.
*/
defaultTimeout?: number;
}
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export {
HolochainError,
Requester,
Transformer,
WebsocketConnectionOptions,
getBaseRoleNameFromCloneId,
isCloneId,
} from "./common.js";
Expand Down
16 changes: 10 additions & 6 deletions test/e2e/app-agent-websocket.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from "node:assert";
import test, { Test } from "tape";
import test from "tape";
import {
AdminWebsocket,
AppAgentCallZomeRequest,
Expand Down Expand Up @@ -127,9 +127,9 @@ test(
"cells only receive their own signals",
withConductor(ADMIN_PORT, async (t) => {
const role_name = "foo";
const admin = await AdminWebsocket.connect(
new URL(`ws://127.0.0.1:${ADMIN_PORT}`)
);
const admin = await AdminWebsocket.connect({
url: new URL(`ws://127.0.0.1:${ADMIN_PORT}`),
});
const path = `${FIXTURE_PATH}/test.happ`;
const { port: appPort } = await admin.attachAppInterface({ port: 0 });

Expand Down Expand Up @@ -168,8 +168,12 @@ test(
await admin.authorizeSigningCredentials(cell_id1);

const clientUrl = new URL(`ws://127.0.0.1:${appPort}`);
const appAgentWs1 = await AppAgentWebsocket.connect(clientUrl, app_id1);
const appAgentWs2 = await AppAgentWebsocket.connect(clientUrl, app_id2);
const appAgentWs1 = await AppAgentWebsocket.connect(app_id1, {
url: clientUrl,
});
const appAgentWs2 = await AppAgentWebsocket.connect(app_id2, {
url: clientUrl,
});

appAgentWs1.on("signal", signalCb1);
appAgentWs2.on("signal", signalCb2);
Expand Down
Loading

0 comments on commit 7d1cc0c

Please sign in to comment.