Skip to content

Commit b7dea5c

Browse files
committed
feat(std/relays): WithPool to create relay pools
1 parent 493ee6a commit b7dea5c

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

std/relays.ts

+39
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import type {
44
ClientToRelayMessage,
55
EventKind,
66
NostrEvent,
7+
RelayUrl,
78
SubscriptionFilter,
89
} from "@lophus/core/protocol";
910
import {
11+
Relay,
1012
RelayLike,
1113
RelayLikeConfig,
1214
RelayLikeOptions,
15+
RelayOptions,
1316
SubscriptionOptions,
1417
} from "@lophus/core/relays";
1518

@@ -68,3 +71,39 @@ export class RelayGroup implements RelayLike {
6871
await Promise.resolve();
6972
}
7073
}
74+
75+
export interface WithPool<
76+
R extends typeof Relay,
77+
> {
78+
pool: Map<RelayUrl, InstanceType<R>>;
79+
new (url: RelayUrl, options?: RelayOptions): InstanceType<R>;
80+
}
81+
82+
export function WithPool<
83+
R extends typeof Relay,
84+
>(
85+
BaseRelay: R,
86+
): WithPool<R> {
87+
// @ts-ignore allow concrete arguments for constructor
88+
return class Self extends BaseRelay {
89+
static readonly pool = new Map<RelayUrl, InstanceType<R>>();
90+
91+
constructor(
92+
url: RelayUrl,
93+
options?: RelayOptions,
94+
) {
95+
const pooled = Self.pool.get(url);
96+
if (pooled) {
97+
return pooled;
98+
}
99+
super(url, options);
100+
Self.pool.set(url, this as InstanceType<R>);
101+
return this;
102+
}
103+
104+
override close() {
105+
Self.pool.delete(this.config.url);
106+
return super.close();
107+
}
108+
};
109+
}

std/relays_test.ts

+35-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import { afterAll, beforeAll, describe, it } from "@std/testing/bdd";
77
import { MockWebSocket } from "@lophus/lib/testing";
88
import { NostrEvent, Relay, SubscriptionId } from "@lophus/nips";
9-
import { RelayGroup } from "./relays.ts";
9+
import { RelayGroup, WithPool } from "./relays.ts";
1010

1111
describe("RelayGroup", () => {
1212
let relays: Relay[];
@@ -113,3 +113,37 @@ describe("RelayGroup", () => {
113113
});
114114
});
115115
});
116+
117+
describe("WithPool", () => {
118+
let Pooled: WithPool<typeof Relay>;
119+
120+
beforeAll(() => {
121+
globalThis.WebSocket = MockWebSocket;
122+
});
123+
124+
it("should accept a NIP-enabled relay as an argument", () => {
125+
Pooled = WithPool(Relay);
126+
});
127+
128+
it("should have no relays in the pool initially", () => {
129+
assertEquals(Pooled.pool.size, 0);
130+
});
131+
132+
it("should add a relay to the pool and return it", () => {
133+
const relay = new Pooled("ws://localhost:80");
134+
assertEquals(Pooled.pool.size, 1);
135+
assertEquals(Pooled.pool.has(relay.config.url), true);
136+
});
137+
138+
it("should return the pooled relay if it exists", () => {
139+
const relay = new Pooled("ws://localhost:80");
140+
assertEquals(Pooled.pool.size, 1);
141+
assertEquals(Pooled.pool.has(relay.config.url), true);
142+
});
143+
144+
it("should remove a relay from the pool when it is closed", async () => {
145+
const relay = new Pooled("ws://localhost:80");
146+
await relay.close();
147+
assertEquals(Pooled.pool.size, 0);
148+
});
149+
});

0 commit comments

Comments
 (0)