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