Tweak relay lists

This commit is contained in:
Jon Staab
2026-06-18 11:15:02 -07:00
parent fafa3b172e
commit 772895e3ab
8 changed files with 39 additions and 12 deletions
+8 -1
View File
@@ -1,4 +1,4 @@
import {writable} from "svelte/store"
import {writable, derived} from "svelte/store"
import type {Readable, Unsubscriber} from "svelte/store"
import type {Maybe} from "@welshman/lib"
import type {Filter} from "@welshman/util"
@@ -212,4 +212,11 @@ export abstract class DerivedPlugin<T> implements ReadableMap<T>, Loadable<T>, D
values = () => this.index.get().values()
get = (key: string) => this.index.get().get(key)
/**
* Build a per-key `Projection` over this collection: snapshot synchronously
* with `.get()`, or subscribe via `.$` (which lazily loads the key).
*/
protected project = <U>(key: string, read: (item: Maybe<T>) => U): Projection<U> =>
projection(derived(this.one(key), read), () => read(this.get(key)))
}
@@ -10,6 +10,7 @@ import {
} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import {DerivedPlugin} from "./base.js"
import type {Projection} from "./base.js"
import {Network} from "./network.js"
import {Router} from "./router.js"
import {User} from "../user.js"
@@ -34,7 +35,8 @@ export class BlockedRelayLists extends DerivedPlugin<ReturnType<typeof readList>
return this.ctx.use(Network).loadUsingOutbox(pubkey, {kinds: [BLOCKED_RELAYS]}, relayHints)
}
getBlockedRelays = (pubkey: string) => getRelaysFromList(this.get(pubkey))
urls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list))
addRelay = async (url: string) => {
const user = User.require(this.ctx)
@@ -2,6 +2,7 @@ import {
MESSAGING_RELAYS,
asDecryptedEvent,
readList,
getRelaysFromList,
makeList,
makeEvent,
addToListPublicly,
@@ -9,6 +10,7 @@ import {
} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import {DerivedPlugin} from "./base.js"
import type {Projection} from "./base.js"
import {Network} from "./network.js"
import {Router} from "./router.js"
import {User} from "../user.js"
@@ -33,6 +35,9 @@ export class MessagingRelayLists extends DerivedPlugin<ReturnType<typeof readLis
return this.ctx.use(Network).loadUsingOutbox(pubkey, {kinds: [MESSAGING_RELAYS]}, relayHints)
}
urls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list))
addRelay = async (url: string) => {
const user = User.require(this.ctx)
const list = (await this.forceLoad(user.pubkey)) || makeList({kind: MESSAGING_RELAYS})
+9 -2
View File
@@ -13,6 +13,7 @@ import {
} from "@welshman/util"
import type {TrustedEvent, PublishedList} from "@welshman/util"
import {DerivedPlugin} from "./base.js"
import type {Projection} from "./base.js"
import {Router, addMinimalFallbacks} from "./router.js"
import {Network} from "./network.js"
import {User} from "../user.js"
@@ -44,8 +45,14 @@ export class RelayLists extends DerivedPlugin<PublishedList> {
])
}
getRelaysForPubkey = (pubkey: string, mode?: RelayMode) =>
getRelaysFromList(this.get(pubkey), mode)
urls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list))
readUrls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list, RelayMode.Read))
writeUrls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list, RelayMode.Write))
// NIP-65 relay-list mutations for the client's user
+1 -1
View File
@@ -64,7 +64,7 @@ export class RelayStats extends MapPlugin<RelayStatsItem> {
// Skip relays the user has blocked
const pubkey = this.ctx.user?.pubkey
if (pubkey && this.ctx.use(BlockedRelayLists).getBlockedRelays(pubkey).includes(url)) {
if (pubkey && this.ctx.use(BlockedRelayLists).urls(pubkey).get().includes(url)) {
return 0
}
+6 -6
View File
@@ -1,13 +1,9 @@
import {RelayMode} from "@welshman/util"
import {Router as BaseRouter} from "@welshman/router"
import {RelayLists} from "./relayLists.js"
import {RelayStats} from "./relayStats.js"
import type {IClient} from "../client.js"
// Re-export the upstream router surface (scenarios, fallback policies,
// makeSelection, getFilterSelections, types). The local `Router` below shadows
// the upstream `Router` in this re-export.
export * from "@welshman/router"
/**
* The upstream `@welshman/router` Router, wired to this client: relay lists come
* from the `RelayLists` collection, quality from `RelayStats`, and the user
@@ -19,7 +15,11 @@ export class Router extends BaseRouter {
constructor(ctx: IClient) {
super({
getUserPubkey: () => ctx.user?.pubkey,
getPubkeyRelays: (pubkey, mode) => ctx.use(RelayLists).getRelaysForPubkey(pubkey, mode),
getPubkeyRelays: (pubkey, mode) =>
(mode === RelayMode.Read
? ctx.use(RelayLists).readUrls(pubkey)
: ctx.use(RelayLists).writeUrls(pubkey)
).get(),
getRelayQuality: url => ctx.use(RelayStats).getQuality(url),
getDefaultRelays: ctx.config.getDefaultRelays,
getIndexerRelays: ctx.config.getIndexerRelays,
@@ -2,6 +2,7 @@ import {
SEARCH_RELAYS,
asDecryptedEvent,
readList,
getRelaysFromList,
makeList,
makeEvent,
addToListPublicly,
@@ -9,6 +10,7 @@ import {
} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util"
import {DerivedPlugin} from "./base.js"
import type {Projection} from "./base.js"
import {Network} from "./network.js"
import {Router} from "./router.js"
import {User} from "../user.js"
@@ -33,6 +35,9 @@ export class SearchRelayLists extends DerivedPlugin<ReturnType<typeof readList>>
return this.ctx.use(Network).loadUsingOutbox(pubkey, {kinds: [SEARCH_RELAYS]}, relayHints)
}
urls = (pubkey: string): Projection<string[]> =>
this.project(pubkey, list => getRelaysFromList(list))
addRelay = async (url: string) => {
const user = User.require(this.ctx)
const list = (await this.forceLoad(user.pubkey)) || makeList({kind: SEARCH_RELAYS})
+2 -1
View File
@@ -64,7 +64,8 @@ export const clientPolicyAuthUnlessBlocked = makeClientPolicyAuth((socket, clien
return !client
.use(BlockedRelayLists)
.getBlockedRelays(client.user.pubkey)
.urls(client.user.pubkey)
.get()
.includes(socket.url)
})