Skip to content

Commit

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

* add logic back to try to reconnect to the app websocket if socket is closed

* cleanup

* include error in test failure

* make arguments more aligned with conductor API

* fix ws options type

* fix test

* updated test to assert on error message

* refactor(app): remove unused fn containsCell

* refactor(client): unify usage of listeners & handle invalid app tokens

* docs: update changelog

* revert: make WsClientOptions optional

* fix(common): return request error without awaiting timeout

* fix(client): unset auth token on rejected connection attempt

* build(nix): update flake

---------

Co-authored-by: Jost Schulte <[email protected]>
Co-authored-by: Jost Schulte <jost-s@@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 28, 2024
1 parent 7a76a2a commit d6b8893
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 165 deletions.
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*
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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.
### Fixed
### Changed
### Removed
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
2 changes: 1 addition & 1 deletion docs/client.wsclient.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Description
</td><td>
[WsClientOptions](./client.wsclientoptions.md)
[WsClientOptions](./client.wsclientoptions.md) \| undefined
</td><td>
Expand Down
2 changes: 1 addition & 1 deletion docs/client.wsclient.options.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
**Signature:**

```typescript
options: WsClientOptions;
options: WsClientOptions | undefined;
```
20 changes: 10 additions & 10 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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 d6b8893

Please sign in to comment.