diff --git a/packages/app/src/Const.ts b/packages/app/src/Const.ts index db961bc6..a412edcc 100644 --- a/packages/app/src/Const.ts +++ b/packages/app/src/Const.ts @@ -47,7 +47,7 @@ export const DefaultRelays = new Map([ /** * Default search relays */ -export const SearchRelays = new Map([["wss://relay.nostr.band", { read: true, write: false }]]); +export const SearchRelays = ["wss://relay.nostr.band"]; /** * List of recommended follows for new users diff --git a/packages/app/src/Feed/EventFeed.ts b/packages/app/src/Feed/EventFeed.ts index 2a9c908f..e06ada00 100644 --- a/packages/app/src/Feed/EventFeed.ts +++ b/packages/app/src/Feed/EventFeed.ts @@ -17,7 +17,10 @@ export default function useEventFeed(link: NostrLink) { f.kinds([unwrap(link.kind)]); } } else { - const f = b.withFilter().id(link.id, link.relays?.at(0)); + const f = b.withFilter().ids([link.id]); + if (link.relays) { + link.relays.slice(0, 2).forEach(r => f.relay(r)); + } if (link.author) { f.authors([link.author]); } diff --git a/packages/app/src/Feed/ThreadFeed.ts b/packages/app/src/Feed/ThreadFeed.ts index 160c8e3b..f06ffc97 100644 --- a/packages/app/src/Feed/ThreadFeed.ts +++ b/packages/app/src/Feed/ThreadFeed.ts @@ -22,9 +22,12 @@ export default function useThreadFeed(link: NostrLink) { leaveOpen: true, }); if (trackingEvents.length > 0) { - const fTracking = sub.withFilter(); for (const te of trackingEvents) { - fTracking.id(te.id, te.relay); + const fTracking = sub.withFilter(); + fTracking.ids([te.id]); + if (te.relay) { + fTracking.relay(te.relay); + } } } if (allEvents.length > 0) { diff --git a/packages/app/src/Feed/TimelineFeed.ts b/packages/app/src/Feed/TimelineFeed.ts index f8a0a377..0f60d76f 100644 --- a/packages/app/src/Feed/TimelineFeed.ts +++ b/packages/app/src/Feed/TimelineFeed.ts @@ -6,6 +6,7 @@ import { unixNow, unwrap, tagFilterOfTextRepost } from "SnortUtils"; import useTimelineWindow from "Hooks/useTimelineWindow"; import useLogin from "Hooks/useLogin"; import { System } from "index"; +import { SearchRelays } from "Const"; export interface TimelineFeedOptions { method: "TIME_RANGE" | "LIMIT_UNTIL"; @@ -64,10 +65,12 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel } case "profile_keyword": { f.search(subject.items[0] + " sort:popular"); + SearchRelays.forEach(r => f.relay(r)); break; } case "post_keyword": { f.search(subject.items[0]); + SearchRelays.forEach(r => f.relay(r)); break; } } diff --git a/packages/app/src/Pages/SearchPage.tsx b/packages/app/src/Pages/SearchPage.tsx index 28ddd82b..87192ccc 100644 --- a/packages/app/src/Pages/SearchPage.tsx +++ b/packages/app/src/Pages/SearchPage.tsx @@ -4,8 +4,7 @@ import Timeline from "Element/Timeline"; import { Tab, TabElement } from "Element/Tabs"; import { useEffect, useState } from "react"; import { debounce } from "SnortUtils"; -import { System, router } from "index"; -import { SearchRelays } from "Const"; +import { router } from "index"; import TrendingUsers from "Element/TrendingUsers"; import TrendingNotes from "Element/TrendingPosts"; @@ -39,21 +38,6 @@ const SearchPage = () => { return debounce(500, () => setKeyword(search)); }, [search]); - useEffect(() => { - const addedRelays: string[] = []; - for (const [k, v] of SearchRelays) { - if (!System.Sockets.some(v => v.address === k)) { - System.ConnectToRelay(k, v); - addedRelays.push(k); - } - } - return () => { - for (const r of addedRelays) { - System.DisconnectRelay(r); - } - }; - }, []); - function tabContent() { if (!keyword) { switch (tab.value) { diff --git a/packages/system/src/RequestBuilder.ts b/packages/system/src/RequestBuilder.ts index df34c39d..088acf1c 100644 --- a/packages/system/src/RequestBuilder.ts +++ b/packages/system/src/RequestBuilder.ts @@ -1,6 +1,6 @@ import debug from "debug"; import { v4 as uuid } from "uuid"; -import { appendDedupe, dedupe, unixNowMs } from "@snort/shared"; +import { appendDedupe, sanitizeRelayUrl, unixNowMs } from "@snort/shared"; import { ReqFilter, u256, HexKey, EventKind } from "."; import { diffFilters } from "./RequestSplitter"; @@ -24,9 +24,9 @@ export enum RequestStrategy { AuthorsRelays = 2, /** - * Relay hints are usually provided when using replies + * Use pre-determined relays for query */ - RelayHintedEventIds = 3, + ExplicitRelays = 3, } /** @@ -152,14 +152,21 @@ export class RequestBuilder { */ export class RequestFilterBuilder { #filter: ReqFilter = {}; - #relayHints = new Map>(); + #relays = new Set(); get filter() { return { ...this.#filter }; } - get relayHints() { - return new Map(this.#relayHints); + /** + * Use a specific relay for this request filter + */ + relay(u: string) { + const uClean = sanitizeRelayUrl(u); + if (uClean) { + this.#relays.add(uClean); + } + return this; } ids(ids: Array) { @@ -167,13 +174,6 @@ export class RequestFilterBuilder { return this; } - id(id: u256, relay?: string) { - if (relay) { - this.#relayHints.set(id, appendDedupe(this.#relayHints.get(id), [relay])); - } - return this.ids([id]); - } - authors(authors?: Array) { if (!authors) return this; this.#filter.authors = appendDedupe(this.#filter.authors, authors); @@ -220,20 +220,13 @@ export class RequestFilterBuilder { * Build/expand this filter into a set of relay specific queries */ build(relays: RelayCache, id: string): Array { - // when querying for specific event ids with relay hints - // take the first approach which is to split the filter by relay - if (this.#filter.ids && this.#relayHints.size > 0) { - const relays = dedupe([...this.#relayHints.values()].flat()); - return relays.map(r => { + // use the explicit relay list first + if (this.#relays.size > 0) { + return [...this.#relays].map(r => { return { - filters: [ - { - ...this.#filter, - ids: [...this.#relayHints.entries()].filter(([, v]) => v.includes(r)).map(([k]) => k), - }, - ], + filters: [this.#filter], relay: r, - strategy: RequestStrategy.RelayHintedEventIds, + strategy: RequestStrategy.ExplicitRelays, }; }); } diff --git a/packages/system/tests/GossipModel.test.ts b/packages/system/tests/GossipModel.test.ts index 90f154ca..eaf9f20f 100644 --- a/packages/system/tests/GossipModel.test.ts +++ b/packages/system/tests/GossipModel.test.ts @@ -3,8 +3,14 @@ import { splitAllByWriteRelays } from "../src/GossipModel" describe("GossipModel", () => { it("should not output empty", () => { const Relays = { - get: (pk?: string) => { - return []; + getFromCache: (pk?: string) => { + if (pk) { + return { + pubkey: pk, + created_at: 0, + relays: [] + }; + } } } const a = [{ diff --git a/packages/system/tests/RequestBuilder.test.ts b/packages/system/tests/RequestBuilder.test.ts index 530d7e0b..5ab725c7 100644 --- a/packages/system/tests/RequestBuilder.test.ts +++ b/packages/system/tests/RequestBuilder.test.ts @@ -2,22 +2,26 @@ import { RelayCache } from "../src/GossipModel"; import { RequestBuilder, RequestStrategy } from "../src/RequestBuilder"; import { describe, expect } from "@jest/globals"; import { expandFilter } from "../src/RequestExpander"; -import { unixNowMs } from "../src/Utils"; import { bytesToHex } from "@noble/curves/abstract/utils"; +import { unixNow, unixNowMs } from "@snort/shared"; const DummyCache = { - get: (pk?: string) => { + getFromCache: (pk?: string) => { if (!pk) return undefined; - return [ - { - url: `wss://${pk}.com/`, - settings: { - read: true, - write: true, + return { + pubkey: pk, + created_at: unixNow(), + relays: [ + { + url: `wss://${pk}.com/`, + settings: { + read: true, + write: true, + }, }, - }, - ]; + ] + }; }, } as RelayCache;