@@ -55,7 +55,10 @@ export class RelayLists extends DerivedPlugin<RelayList> {
|
||||
return this.app.use(Thunks).publishToOutbox({event})
|
||||
}
|
||||
|
||||
addRelay = (url: string, mode: RelayMode) => this.update(builder => builder.addUrl(url, mode))
|
||||
addRelay = (url: string, mode: RelayMode) =>
|
||||
this.update(builder =>
|
||||
mode === RelayMode.Read ? builder.addReadUrl(url) : builder.addWriteUrl(url),
|
||||
)
|
||||
|
||||
setReadRelays = (urls: string[]) => this.update(builder => builder.setReadUrls(urls))
|
||||
|
||||
@@ -64,7 +67,9 @@ export class RelayLists extends DerivedPlugin<RelayList> {
|
||||
removeRelay = async (url: string, mode: RelayMode) => {
|
||||
const user = User.require(this.app)
|
||||
const builder = new RelayListBuilder(await this.forceLoad(user.pubkey))
|
||||
const event = await builder.removeUrl(url, mode).toTemplate(user.signer)
|
||||
const event = await (
|
||||
mode === RelayMode.Read ? builder.removeReadUrl(url) : builder.removeWriteUrl(url)
|
||||
).toTemplate(user.signer)
|
||||
|
||||
// publishToOutbox is outbox-only, so build relays here to also notify the
|
||||
// removed relay of its removal
|
||||
|
||||
@@ -60,10 +60,10 @@ describe("RelayList", () => {
|
||||
|
||||
it("adds modeless and single-mode relays via a fresh builder", async () => {
|
||||
const tmpl = await new RelayListBuilder()
|
||||
.addUrl(read, RelayMode.Read)
|
||||
.addUrl(write, RelayMode.Write)
|
||||
.addUrl(both, RelayMode.Read)
|
||||
.addUrl(both, RelayMode.Write)
|
||||
.addReadUrl(read)
|
||||
.addWriteUrl(write)
|
||||
.addReadUrl(both)
|
||||
.addWriteUrl(both)
|
||||
.toTemplate(signer)
|
||||
|
||||
expect(tmpl.kind).toBe(RELAYS)
|
||||
@@ -75,9 +75,9 @@ describe("RelayList", () => {
|
||||
|
||||
it("downgrades a modeless relay when one mode is removed", async () => {
|
||||
const tmpl = await new RelayListBuilder()
|
||||
.addUrl(both, RelayMode.Read)
|
||||
.addUrl(both, RelayMode.Write)
|
||||
.removeUrl(both, RelayMode.Read)
|
||||
.addReadUrl(both)
|
||||
.addWriteUrl(both)
|
||||
.removeReadUrl(both)
|
||||
.toTemplate(signer)
|
||||
|
||||
expect(tmpl.tags).toContainEqual(["r", both, RelayMode.Write])
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
import {uniq, uniqBy} from "@welshman/lib"
|
||||
import {RELAYS, RelayMode, getRelayTags, getRelayTagValues, normalizeRelayUrl} from "@welshman/util"
|
||||
import {nth, uniq, uniqBy, remove} from "@welshman/lib"
|
||||
import {RELAYS, getRelayTags, normalizeRelayUrl} from "@welshman/util"
|
||||
import {ListReader} from "../ListReader.js"
|
||||
import {ListBuilder} from "../ListBuilder.js"
|
||||
|
||||
const getUrls = (tags: string[][], mode?: string) =>
|
||||
uniqBy(
|
||||
normalizeRelayUrl,
|
||||
getRelayTags(tags)
|
||||
.filter(t => !mode || !t[2] || t[2] === mode)
|
||||
.map(nth(1)),
|
||||
)
|
||||
|
||||
// NIP-65 kind-10002 relay list.
|
||||
export class RelayList extends ListReader {
|
||||
readonly kind = RELAYS
|
||||
|
||||
urls() {
|
||||
return uniqBy(normalizeRelayUrl, getRelayTagValues(this.tags()))
|
||||
return getUrls(this.tags())
|
||||
}
|
||||
|
||||
readUrls() {
|
||||
return uniqBy(
|
||||
normalizeRelayUrl,
|
||||
getRelayTags(this.tags())
|
||||
.filter(t => !t[2] || t[2] === RelayMode.Read)
|
||||
.map(t => t[1]),
|
||||
)
|
||||
return getUrls(this.tags(), "read")
|
||||
}
|
||||
|
||||
writeUrls() {
|
||||
return uniqBy(
|
||||
normalizeRelayUrl,
|
||||
getRelayTags(this.tags())
|
||||
.filter(t => !t[2] || t[2] === RelayMode.Write)
|
||||
.map(t => t[1]),
|
||||
)
|
||||
return getUrls(this.tags(), "write")
|
||||
}
|
||||
|
||||
builder() {
|
||||
@@ -37,73 +35,62 @@ export class RelayList extends ListReader {
|
||||
export class RelayListBuilder extends ListBuilder<RelayList> {
|
||||
readonly kind = RELAYS
|
||||
|
||||
readUrls() {
|
||||
return uniqBy(
|
||||
normalizeRelayUrl,
|
||||
getRelayTags(this.publicTags)
|
||||
.filter(t => !t[2] || t[2] === RelayMode.Read)
|
||||
.map(t => t[1]),
|
||||
)
|
||||
addReadUrl(url: string) {
|
||||
return this.addUrlForMode(url, "read")
|
||||
}
|
||||
|
||||
writeUrls() {
|
||||
return uniqBy(
|
||||
normalizeRelayUrl,
|
||||
getRelayTags(this.publicTags)
|
||||
.filter(t => !t[2] || t[2] === RelayMode.Write)
|
||||
.map(t => t[1]),
|
||||
)
|
||||
addWriteUrl(url: string) {
|
||||
return this.addUrlForMode(url, "write")
|
||||
}
|
||||
|
||||
addUrl(url: string, mode: RelayMode) {
|
||||
removeReadUrl(url: string) {
|
||||
return this.removeUrlForMode(url, "read")
|
||||
}
|
||||
|
||||
removeWriteUrl(url: string) {
|
||||
return this.removeUrlForMode(url, "write")
|
||||
}
|
||||
|
||||
private findUrlTag(url: string) {
|
||||
const normalized = normalizeRelayUrl(url)
|
||||
const existing = getRelayTags(this.publicTags).filter(
|
||||
t => normalizeRelayUrl(t[1]) === normalized,
|
||||
)
|
||||
|
||||
const priorModes = new Set<RelayMode | undefined>(
|
||||
existing.map(t => t[2] as RelayMode | undefined),
|
||||
)
|
||||
return this.publicTags.find(t => t[0] === "r" && normalizeRelayUrl(t[1]) === normalized)
|
||||
}
|
||||
|
||||
const alt = mode === RelayMode.Read ? RelayMode.Write : RelayMode.Read
|
||||
const coversAlt = priorModes.has(undefined) || priorModes.has(alt)
|
||||
private addUrlForMode(url: string, mode: "read" | "write") {
|
||||
const existing = this.findUrlTag(url)
|
||||
const alt = mode === "read" ? "write" : "read"
|
||||
|
||||
this.publicTags = this.publicTags.filter(
|
||||
t => !(t[0] === "r" && normalizeRelayUrl(t[1]) === normalized),
|
||||
)
|
||||
|
||||
this.publicTags.push(coversAlt ? ["r", url] : ["r", url, mode])
|
||||
if (!existing) {
|
||||
this.publicTags.push(["r", normalizeRelayUrl(url), mode])
|
||||
} else if (existing[2] === alt) {
|
||||
existing.splice(2)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
removeUrl(url: string, mode: RelayMode) {
|
||||
const normalized = normalizeRelayUrl(url)
|
||||
const existing = getRelayTags(this.publicTags).filter(
|
||||
t => normalizeRelayUrl(t[1]) === normalized,
|
||||
)
|
||||
private removeUrlForMode(url: string, mode: "read" | "write") {
|
||||
const existing = this.findUrlTag(url)
|
||||
const alt = mode === "read" ? "write" : "read"
|
||||
|
||||
const alt = mode === RelayMode.Read ? RelayMode.Write : RelayMode.Read
|
||||
|
||||
const keepAlt = existing.some(t => !t[2] || t[2] === alt)
|
||||
|
||||
this.publicTags = this.publicTags.filter(
|
||||
t => !(t[0] === "r" && normalizeRelayUrl(t[1]) === normalized),
|
||||
)
|
||||
|
||||
if (keepAlt) {
|
||||
this.publicTags.push(["r", url, alt])
|
||||
if (existing) {
|
||||
if (!existing[2]) {
|
||||
existing[2] = alt
|
||||
} else if (existing[2] === mode) {
|
||||
this.publicTags = remove(existing, this.publicTags)
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
setReadUrls(urls: string[]) {
|
||||
return this.setUrlsForModes(urls, this.writeUrls())
|
||||
return this.setUrlsForModes(urls, getUrls(this.publicTags, "write"))
|
||||
}
|
||||
|
||||
setWriteUrls(urls: string[]) {
|
||||
return this.setUrlsForModes(this.readUrls(), urls)
|
||||
return this.setUrlsForModes(getUrls(this.publicTags, "read"), urls)
|
||||
}
|
||||
|
||||
private setUrlsForModes(readUrls: string[], writeUrls: string[]) {
|
||||
@@ -114,8 +101,8 @@ export class RelayListBuilder extends ListBuilder<RelayList> {
|
||||
read.has(url) && write.has(url)
|
||||
? ["r", url]
|
||||
: read.has(url)
|
||||
? ["r", url, RelayMode.Read]
|
||||
: ["r", url, RelayMode.Write],
|
||||
? ["r", url, "read"]
|
||||
: ["r", url, "write"],
|
||||
)
|
||||
|
||||
this.publicTags = [...otherTags, ...relayTags]
|
||||
|
||||
Reference in New Issue
Block a user