Ask a search relay whether it supports search before offering to drop it (#659)
This commit is contained in:
parent
1c934576fe
commit
653664751f
4 changed files with 86 additions and 4 deletions
|
|
@ -1724,6 +1724,18 @@ Acceptance:
|
||||||
- The section fills from the relays that answer. One that takes the connection
|
- The section fills from the relays that answer. One that takes the connection
|
||||||
and then says nothing does not hold it empty.
|
and then says nothing does not hold it empty.
|
||||||
|
|
||||||
|
### US-133 — Keep the search relays that work
|
||||||
|
|
||||||
|
As alice, I want the search health check to leave alone the relays that do
|
||||||
|
support search, so that fixing it does not cost me the ones I chose.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- The check reads each search relay's own metadata, so a relay that advertises
|
||||||
|
search is never offered for removal, and neither is one whose metadata never
|
||||||
|
arrives.
|
||||||
|
- A relay that answers and advertises no search is.
|
||||||
|
|
||||||
### US-106 — Share text into the app
|
### US-106 — Share text into the app
|
||||||
|
|
||||||
As alice, I want to hand text to Flotilla and choose where it lands, so that I
|
As alice, I want to hand text to Flotilla and choose where it lands, so that I
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,15 @@ import {neventEncode, npubEncode} from "nostr-tools/nip19"
|
||||||
import {DAY, HOUR, MINUTE} from "@welshman/lib"
|
import {DAY, HOUR, MINUTE} from "@welshman/lib"
|
||||||
import {POLL, displayRelayUrl} from "@welshman/util"
|
import {POLL, displayRelayUrl} from "@welshman/util"
|
||||||
import {RelayMessageType} from "@welshman/net"
|
import {RelayMessageType} from "@welshman/net"
|
||||||
import {Classified, Comment, FollowList, Note, Poll, Thread} from "@welshman/domain"
|
import {
|
||||||
|
Classified,
|
||||||
|
Comment,
|
||||||
|
FollowList,
|
||||||
|
Note,
|
||||||
|
Poll,
|
||||||
|
SearchRelayList,
|
||||||
|
Thread,
|
||||||
|
} from "@welshman/domain"
|
||||||
import type {Locator, Page} from "@playwright/test"
|
import type {Locator, Page} from "@playwright/test"
|
||||||
import {
|
import {
|
||||||
composer,
|
composer,
|
||||||
|
|
@ -560,6 +568,54 @@ test("US-117 read the network feed when one relay never answers", async ({seed,
|
||||||
await expect(network.getByText("Bob Barker")).toBeVisible()
|
await expect(network.getByText("Bob Barker")).toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// A url the container does not serve, so its nip-11 document never arrives and nothing knows what it supports.
|
||||||
|
const unreachableRelayUrl = "wss://unreachable.test/"
|
||||||
|
|
||||||
|
test("US-133 keep the search relays that support search", async ({seed, as}) => {
|
||||||
|
const scenario = await seed(({relay, open, user}) => {
|
||||||
|
const space = relay("space")
|
||||||
|
const indexer = open("indexer")
|
||||||
|
const outbox = open("outbox")
|
||||||
|
|
||||||
|
space.room("general", {name: "General"})
|
||||||
|
space.join(user.alice, "general")
|
||||||
|
|
||||||
|
indexer.relayList(user.alice, {
|
||||||
|
read: [space.url, indexer.url],
|
||||||
|
write: [space.url, indexer.url],
|
||||||
|
})
|
||||||
|
|
||||||
|
// No search relay of hers is a space, so the health check is the only thing asking for their metadata.
|
||||||
|
indexer.event(user.alice, () =>
|
||||||
|
indexer
|
||||||
|
.kind(SearchRelayList)
|
||||||
|
.writer()
|
||||||
|
.setUrls([indexer.url, outbox.url, unreachableRelayUrl])
|
||||||
|
.renderTemplate(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const indexer = scenario.open("indexer")
|
||||||
|
const outbox = scenario.open("outbox")
|
||||||
|
|
||||||
|
const page = await as(users.alice, "/home", {
|
||||||
|
relayInfo: {[indexer.url]: {supported_nips: [1, 50]}},
|
||||||
|
})
|
||||||
|
|
||||||
|
const healthCheck = page.getByRole("group", {name: "Invalid Search Relays"})
|
||||||
|
|
||||||
|
await expect(healthCheck).toBeVisible()
|
||||||
|
|
||||||
|
await healthCheck.getByRole("button", {name: "Fix"}).click()
|
||||||
|
|
||||||
|
const review = dialog(page, "Review changes")
|
||||||
|
|
||||||
|
// Outbox answered and advertised no search; the other two are a relay that does and one nobody can ask.
|
||||||
|
await expect(review.getByText(displayRelayUrl(outbox.url))).toBeVisible()
|
||||||
|
await expect(review.getByText(displayRelayUrl(indexer.url))).toHaveCount(0)
|
||||||
|
await expect(review.getByText(displayRelayUrl(unreachableRelayUrl))).toHaveCount(0)
|
||||||
|
})
|
||||||
|
|
||||||
test("US-106 share text into the app", async ({seed, as}) => {
|
test("US-106 share text into the app", async ({seed, as}) => {
|
||||||
const shared = "the offsite is moving to the 14th"
|
const shared = "the offsite is moving to the 14th"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,13 +109,15 @@ export class HealthChecks {
|
||||||
)
|
)
|
||||||
|
|
||||||
this.pending = projection(
|
this.pending = projection(
|
||||||
derived([this.context.$, forceHealthChecks], ([$context, $forceHealthChecks]) =>
|
derived(
|
||||||
this.checks.filter(check => $forceHealthChecks[check.id] ?? check.isPending($context)),
|
[this.context.$, forceHealthChecks, app.use(Relays).index.$],
|
||||||
|
([$context, $forceHealthChecks]) =>
|
||||||
|
this.checks.filter(check => $forceHealthChecks[check.id] ?? check.isPending($context)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private supportsSearch = (url: string) => this.app.use(Relays).get(url)?.hasNip(50)
|
private supportsSearch = (url: string) => this.app.use(Relays).get(url)?.hasNip(50) ?? true
|
||||||
|
|
||||||
private checks: HealthCheck[] = [
|
private checks: HealthCheck[] = [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import {
|
||||||
MessagingRelayLists,
|
MessagingRelayLists,
|
||||||
RelayLists,
|
RelayLists,
|
||||||
RoomLists,
|
RoomLists,
|
||||||
|
SearchRelayLists,
|
||||||
Sync,
|
Sync,
|
||||||
makeRoomKey,
|
makeRoomKey,
|
||||||
} from "@welshman/app"
|
} from "@welshman/app"
|
||||||
|
|
@ -53,6 +54,7 @@ import {
|
||||||
relays,
|
relays,
|
||||||
roomLists,
|
roomLists,
|
||||||
router,
|
router,
|
||||||
|
searchRelayLists,
|
||||||
} from "@app/core"
|
} from "@app/core"
|
||||||
import {LIVEKIT_PARTICIPANTS} from "@app/call"
|
import {LIVEKIT_PARTICIPANTS} from "@app/call"
|
||||||
import {REACTION_KINDS, CONTENT_KINDS, makeCommentFilter} from "@app/content"
|
import {REACTION_KINDS, CONTENT_KINDS, makeCommentFilter} from "@app/content"
|
||||||
|
|
@ -100,6 +102,8 @@ const userFollowList = deriveUserItem(FollowLists)
|
||||||
|
|
||||||
const userMessagingRelayList = deriveUserItem(MessagingRelayLists)
|
const userMessagingRelayList = deriveUserItem(MessagingRelayLists)
|
||||||
|
|
||||||
|
const userSearchRelayList = deriveUserItem(SearchRelayLists)
|
||||||
|
|
||||||
const getSpaceUrls = ($roomList: Maybe<RoomListReader>) =>
|
const getSpaceUrls = ($roomList: Maybe<RoomListReader>) =>
|
||||||
PLATFORM_RELAYS.length > 0 ? PLATFORM_RELAYS : ($roomList?.urls() ?? [])
|
PLATFORM_RELAYS.length > 0 ? PLATFORM_RELAYS : ($roomList?.urls() ?? [])
|
||||||
|
|
||||||
|
|
@ -125,9 +129,16 @@ const syncRelays = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const unsubscribeSearchRelayUrls = userSearchRelayList.subscribe($searchRelayList => {
|
||||||
|
for (const url of $searchRelayList?.urls() ?? []) {
|
||||||
|
relays.get().load(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribePage()
|
unsubscribePage()
|
||||||
unsubscribeSpaceUrls()
|
unsubscribeSpaceUrls()
|
||||||
|
unsubscribeSearchRelayUrls()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,6 +224,7 @@ const syncUserData = () => {
|
||||||
roomLists.get().load($pubkey)
|
roomLists.get().load($pubkey)
|
||||||
muteLists.get().load($pubkey)
|
muteLists.get().load($pubkey)
|
||||||
profiles.get().load($pubkey)
|
profiles.get().load($pubkey)
|
||||||
|
searchRelayLists.get().load($pubkey)
|
||||||
app.get().use(Settings).load($pubkey)
|
app.get().use(Settings).load($pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue