Add adapter to net2

This commit is contained in:
Jon Staab
2025-03-21 09:54:30 -07:00
parent 6e15f1f6c1
commit 34e22eaa27
6 changed files with 183 additions and 18 deletions
+31
View File
@@ -935,6 +935,13 @@ export const once = (f: (...args: any) => void) => {
}
}
/**
* Calls a function
* @param f - Function to call
* @returns Whatever f returns
*/
export const call = <T>(f: () => T, ...args: unknown[]) => f()
/**
* Memoizes function results based on arguments
* @param f - Function to memoize
@@ -1110,6 +1117,30 @@ export const pushToMapKey = <K, T>(m: Map<K, T[]>, k: K, v: T) => {
m.set(k, a)
}
/**
* A generic type-safe event listener function that auto-detects the appropriate methods
* for adding and removing event listeners.
*
* @param target - The event target object with add/remove listener methods
* @param eventName - The name of the event to listen for
* @param callback - The callback function to execute when the event occurs
* @returns A function that removes the event listener when called
*/
export const on = <EventName extends string, Args extends any[]>(
target: {
on: (event: EventName, handler: (...args: Args) => any, ...rest: any[]) => any
off: (event: EventName, handler: (...args: Args) => any, ...rest: any[]) => any
},
eventName: EventName,
callback: (...args: Args) => void,
): (() => void) => {
target.on(eventName, callback)
return () => {
target.off(eventName, callback)
}
}
/**
* Switches on key in object, with default fallback
* @param k - Key to look up
+3 -3
View File
@@ -30,9 +30,9 @@
"mocha": "^10.7.3"
},
"dependencies": {
"@welshman/lib": "~0.0.40",
"@welshman/util": "~0.0.59",
"@welshman/lib": "^0.1.0",
"@welshman/util": "^0.1.0",
"isomorphic-ws": "^5.0.0",
"ws": "^8.16.0"
"typed-emitter": "^2.1.0"
}
}
+102
View File
@@ -0,0 +1,102 @@
import {eq, on, call} from "@welshman/lib"
import {Relay} from "@welshman/util"
import {RelayMessage, ClientMessage} from "./message.js"
import {Socket} from "./socket.js"
type Unsubscriber = () => void
const trackUnsubscribers = (all: Unsubscriber[], local: Unsubscriber[]) => {
all.push(...local)
return () => {
local.forEach(call)
for (const f of local) {
all.splice(all.findIndex(eq(f)), 1)
}
}
}
type RelayMessageSub = (message: RelayMessage) => void
export interface IAdapter {
sockets: Socket[]
send(message: ClientMessage): void
onMessage(cb: RelayMessageSub): Unsubscriber
}
export class SocketsAdapter implements IAdapter {
_unsubscribers: Unsubscriber[] = []
constructor(readonly sockets: Socket[]) {}
send(message: ClientMessage) {
for (const socket of this.sockets) {
socket.send(message)
}
}
onMessage(cb: RelayMessageSub) {
return trackUnsubscribers(
this._unsubscribers,
this.sockets.map(s => s.onMessage(cb)),
)
}
cleanup() {
this._unsubscribers.splice(0).forEach(call)
}
}
export class LocalAdapter {
_unsubscribers: Unsubscriber[] = []
constructor(readonly relay: Relay) {}
get sockets() {
return []
}
send(message: ClientMessage) {
const [type, ...rest] = message
this.relay.send(type, ...rest)
}
onMessage(cb: RelayMessageSub) {
return trackUnsubscribers(this._unsubscribers, [
on(this.relay, "*", (...args: any[]) => cb(args)),
])
}
cleanup() {
this._unsubscribers.splice(0).forEach(call)
}
}
export class MultiAdapter {
_unsubscribers: Unsubscriber[] = []
constructor(readonly adapters: IAdapter[]) {}
get sockets() {
return this.adapters.flatMap(t => t.sockets)
}
send(message: ClientMessage) {
for (const adapter of this.adapters) {
adapter.send(message)
}
}
onMessage(cb: RelayMessageSub) {
return trackUnsubscribers(
this._unsubscribers,
this.adapters.map(a => a.onMessage(cb)),
)
}
cleanup() {
this._unsubscribers.splice(0).forEach(call)
}
}