nostr-relaypool
Version:
A Nostr RelayPool implementation in TypeScript using only nostr-tools library as a dependency.
68 lines (65 loc) • 2.35 kB
text/typescript
import {type Event, type Filter, matchFilters} from "nostr-tools";
import {WebSocket, WebSocketServer} from "isomorphic-ws";
const _ = WebSocket; // Importing WebSocket is needed for WebSocketServer to work
export class InMemoryRelayServer {
events: (Event & {id: string})[] = [];
auth?: string;
wss: WebSocketServer;
subs: Map<string, Filter[]> = new Map();
connections: Set<WebSocket> = new Set();
totalSubscriptions = 0;
constructor(port = 8081, host = "localhost") {
this.wss = new WebSocketServer({port, host});
this.wss.on("connection", (ws) => {
this.connections.add(ws);
// console.log('connected')
ws.on("message", (message) => {
const data = JSON.parse(message.toString());
// console.log('received: %s', JSON.stringify(data))
if (data && data[0] === "REQ") {
const sub = data[1];
const filters = data.slice(2);
this.totalSubscriptions++;
this.subs.set(sub, filters);
for (const event of this.events) {
if (matchFilters(filters, event)) {
// console.log('sending event to sub %s', sub, JSON.stringify(['EVENT', sub, event]))
ws.send(JSON.stringify(["EVENT", sub, event]));
}
}
// console.log('sending eose to sub %s', sub, JSON.stringify(['EOSE', sub]))
ws.send(JSON.stringify(["EOSE", sub]));
} else if (data && data[0] === "EVENT") {
const event = data[1];
this.events.push(event);
for (const [sub, filters] of this.subs) {
if (matchFilters(filters, event)) {
// console.log('sending event to sub %s', sub, JSON.stringify(['EVENT', sub, event]))
ws.send(JSON.stringify(["EVENT", sub, event]));
}
}
} else if (data && data[0] === "CLOSE") {
const sub = data[1];
this.subs.delete(sub);
}
});
if (this.auth) {
ws.send(JSON.stringify(["AUTH", this.auth]));
}
});
}
async close(): Promise<void> {
new Promise((resolve) => this.wss.close(resolve));
}
clear() {
this.events = [];
this.subs = new Map();
this.totalSubscriptions = 0;
this.auth = undefined;
}
disconnectAll() {
for (const ws of this.connections) {
ws.close();
}
}
}