Skip to content

Commit

Permalink
feat(client): try to reconnect to app websocket if closed (#283)
Browse files Browse the repository at this point in the history
* backport #279

* updated changelog

* workflow back to main branch
  • Loading branch information
matthme authored Oct 29, 2024
1 parent 2744691 commit 81effb8
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 157 deletions.
1 change: 0 additions & 1 deletion .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
pull_request:
push:
branches:
- "develop"
- "main"

concurrency:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ target
node_modules
/lib
.tsbuildinfo
.hc
.hc*
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## \[Unreleased\]

### Added
- Bring back a websocket reconnection automation for Admin and App websockets. When either of them is closed and a new request made, it will attempt to reconnect using the same app authentication token that was used to initially authenticate the websocket. A specific `InvalidTokenError` is returned if that fails.
### Changed
- Update to Holochain 0.4.0-rc.0
### Fixed
### Removed

## 2024-09-30: v0.18.0-dev.12
## 2024-09-30: v0.18.0-dev.13
### Fixed
- Type `RevokeAgentKeyResponse`, which returns an array of tuples with cell id and error message for all cells that key revocation failed for.

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ You need `holochain` and `hc` on your path, best to get them from nix with `nix-

To perform the pre-requisite DNA compilation steps, and run the Nodejs test, run:
```bash
nix-shell
./run-test.sh
nix develop
./build-fixture.sh
npm run test
```

## Contribute
Expand Down
4 changes: 2 additions & 2 deletions docs/client.wsclient.close.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Close the websocket connection.
**Signature:**

```typescript
close(code?: number): Promise<CloseEvent>;
close(code?: number): Promise<IsoWebSocket.CloseEvent>;
```

## Parameters
Expand Down Expand Up @@ -49,5 +49,5 @@ _(Optional)_
</tbody></table>
**Returns:**

Promise&lt;CloseEvent&gt;
Promise&lt;IsoWebSocket.CloseEvent&gt;

53 changes: 19 additions & 34 deletions src/api/app/websocket.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import Emittery, { UnsubscribeFunction } from "emittery";
import { omit } from "lodash-es";
import { AgentPubKey, CellId, InstalledAppId, RoleName } from "../../types.js";
import { AppInfo, CellType, MemproofMap } from "../admin/index.js";
import {
AppAuthenticationToken,
AppInfo,
CellType,
MemproofMap,
} from "../admin/index.js";
import {
catchError,
DEFAULT_TIMEOUT,
Expand Down Expand Up @@ -77,6 +82,7 @@ export class AppWebsocket implements AppClient {
CallZomeResponseGeneric<Uint8Array>,
CallZomeResponse
>;
private readonly appAuthenticationToken: AppAuthenticationToken;

cachedAppInfo?: AppInfo | null;

Expand Down Expand Up @@ -110,6 +116,7 @@ export class AppWebsocket implements AppClient {
private constructor(
client: WsClient,
appInfo: AppInfo,
token: AppAuthenticationToken,
callZomeTransform?: CallZomeTransform,
defaultTimeout?: number
) {
Expand All @@ -118,6 +125,7 @@ export class AppWebsocket implements AppClient {
this.installedAppId = appInfo.installed_app_id;
this.defaultTimeout = defaultTimeout ?? DEFAULT_TIMEOUT;
this.callZomeTransform = callZomeTransform ?? defaultCallZomeTransform;
this.appAuthenticationToken = token;
this.emitter = new Emittery<AppEvents>();
this.cachedAppInfo = appInfo;

Expand Down Expand Up @@ -204,18 +212,15 @@ export class AppWebsocket implements AppClient {

const client = await WsClient.connect(options.url, options.wsClientOptions);

if (env?.APP_INTERFACE_TOKEN) {
// Note: This will only work for multiple connections if a single_use = false token is provided
await client.authenticate({ token: env.APP_INTERFACE_TOKEN });
} else {
if (!options.token) {
throw new HolochainError(
"AppAuthenticationTokenMissing",
`unable to connect to Conductor API - no app authentication token provided.`
);
}
await client.authenticate({ token: options.token });
}
const token = options.token ?? env?.APP_INTERFACE_TOKEN;

if (!token)
throw new HolochainError(
"AppAuthenticationTokenMissing",
`unable to connect to Conductor API - no app authentication token provided.`
);

await client.authenticate({ token });

const appInfo = await (
AppWebsocket.requester(client, "app_info", DEFAULT_TIMEOUT) as Requester<
Expand All @@ -233,6 +238,7 @@ export class AppWebsocket implements AppClient {
return new AppWebsocket(
client,
appInfo,
token,
options.callZomeTransform,
options.defaultTimeout
);
Expand Down Expand Up @@ -443,27 +449,6 @@ export class AppWebsocket implements AppClient {
transformer
);
}

private containsCell(cellId: CellId) {
const appInfo = this.cachedAppInfo;
if (!appInfo) {
return false;
}
for (const roleName of Object.keys(appInfo.cell_info)) {
for (const cellInfo of appInfo.cell_info[roleName]) {
const currentCellId =
CellType.Provisioned in cellInfo
? cellInfo[CellType.Provisioned].cell_id
: CellType.Cloned in cellInfo
? cellInfo[CellType.Cloned].cell_id
: undefined;
if (currentCellId && isSameCell(currentCellId, cellId)) {
return true;
}
}
}
return false;
}
}

const defaultCallZomeTransform: Transformer<
Expand Down
Loading

0 comments on commit 81effb8

Please sign in to comment.