Skip to content

Commit f126a4f

Browse files
committed
Support glue-over-websockets
1 parent 591cc30 commit f126a4f

File tree

5 files changed

+190
-8
lines changed

5 files changed

+190
-8
lines changed

.eslintrc.cjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ module.exports = {
55
"plugin:@typescript-eslint/recommended-requiring-type-checking",
66
"prettier",
77
],
8+
rules: {
9+
"@typescript-eslint/no-unused-vars": [
10+
"warn",
11+
{ argsIgnorePattern: "^_" },
12+
],
13+
},
814
parser: "@typescript-eslint/parser",
915
plugins: ["@typescript-eslint"],
1016
root: true,

client/src/glue.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,34 @@ import {
44
ActivateChain,
55
AddEthereumChain,
66
AddEthereumChainEvent,
7+
EventMap,
78
Glue,
89
RequestAccounts,
910
RequestAccountsEvent,
1011
SwitchEthereumChain,
1112
SwitchEthereumChainEvent,
1213
} from "@wallet-test-framework/glue";
1314
import assert from "assert";
15+
import { Client as WebSocketClient } from "rpc-websockets";
16+
17+
type Events = { [k in keyof EventMap]: null };
18+
19+
const EVENTS: (keyof Events)[] = (() => {
20+
const helper: Events = {
21+
requestaccounts: null,
22+
addethereumchain: null,
23+
switchethereumchain: null,
24+
} as const;
25+
26+
const events: (keyof Events)[] = [];
27+
28+
let key: keyof Events;
29+
for (key in helper) {
30+
events.push(key);
31+
}
32+
33+
return events;
34+
})();
1435

1536
type TemplateContext = { [key: string]: string | HTMLElement };
1637

@@ -452,3 +473,63 @@ export class ManualGlue extends Glue {
452473
});
453474
}
454475
}
476+
477+
export class WebSocketGlue extends Glue {
478+
private readonly client: WebSocketClient;
479+
480+
public static async connect(address: string): Promise<WebSocketGlue> {
481+
const self = new WebSocketGlue(address);
482+
483+
const open = new Promise((res, rej) => {
484+
try {
485+
self.client.once("open", res);
486+
} catch (e: unknown) {
487+
rej(e);
488+
}
489+
});
490+
491+
self.client.connect();
492+
493+
await open;
494+
495+
for (const key of EVENTS) {
496+
self.client.on(key, (evt) => self.handle(key, evt));
497+
await self.client.subscribe(key);
498+
}
499+
500+
return self;
501+
}
502+
503+
private constructor(address: string) {
504+
super();
505+
this.client = new WebSocketClient(address);
506+
}
507+
508+
private handle(key: keyof EventMap, evt: unknown): void {
509+
if (!evt || typeof evt !== "object") {
510+
throw new TypeError("Event argument not object");
511+
}
512+
513+
// TODO: Validate the event object is correct.
514+
515+
/* eslint-disable-next-line @typescript-eslint/no-unsafe-argument,
516+
@typescript-eslint/no-explicit-any */
517+
this.emit(key, evt as any);
518+
}
519+
520+
async activateChain(action: ActivateChain): Promise<void> {
521+
await this.client.call("activateChain", [action]);
522+
}
523+
524+
async requestAccounts(action: RequestAccounts): Promise<void> {
525+
await this.client.call("requestAccounts", [action]);
526+
}
527+
528+
async switchEthereumChain(action: SwitchEthereumChain): Promise<void> {
529+
await this.client.call("switchEthereumChain", [action]);
530+
}
531+
532+
async addEthereumChain(action: AddEthereumChain): Promise<void> {
533+
await this.client.call("addEthereumChain", [action]);
534+
}
535+
}

client/src/index.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ManualGlue } from "./glue";
1+
import { ManualGlue, WebSocketGlue } from "./glue";
22
import * as tests from "./tests";
33
import { spawn } from "./util";
44
import { Glue } from "@wallet-test-framework/glue";
@@ -87,6 +87,9 @@ function main() {
8787
throw "no #connect element";
8888
}
8989

90+
// Reload the page when the glue address changes.
91+
window.addEventListener("hashchange", () => window.location.reload());
92+
9093
let webSocket: WebSocket | null;
9194

9295
connect.addEventListener(
@@ -158,11 +161,11 @@ function main() {
158161
};
159162

160163
let glue: Glue;
161-
const config = new URLSearchParams(window.location.hash);
164+
const config = new URLSearchParams(window.location.hash.slice(1));
162165
const wsGlueAddress = config.get("glue");
163166

164167
if (wsGlueAddress) {
165-
throw new Error("not implemented");
168+
glue = await WebSocketGlue.connect(wsGlueAddress);
166169
} else {
167170
const glueElem = document.getElementById("container");
168171
if (!glueElem) {

package-lock.json

Lines changed: 95 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"@types/ws": "^8.5.4",
6262
"@typescript-eslint/eslint-plugin": "5.57.1",
6363
"@typescript-eslint/parser": "^5.57.1",
64-
"@wallet-test-framework/glue": "^0.3.0",
64+
"@wallet-test-framework/glue": "^0.3.1",
6565
"assert": "^2.0.0",
6666
"esbuild": "0.17.15",
6767
"eslint": "8.37.0",
@@ -70,6 +70,7 @@
7070
"mocha": "^10.2.0",
7171
"prettier": "2.8.7",
7272
"process": "^0.11.10",
73+
"rpc-websockets": "^7.5.1",
7374
"solc": "0.8.19",
7475
"typescript": "^5.0.4",
7576
"viem": "^0.3.50"

0 commit comments

Comments
 (0)