From c35b144dba48f641e593a87efa175f438926ff4d Mon Sep 17 00:00:00 2001 From: Kieran Date: Fri, 10 Feb 2023 18:25:17 +0000 Subject: [PATCH] feat: read global from specific (paid) relays --- src/Element/Timeline.tsx | 3 +++ src/Feed/Subscription.ts | 13 ++++++++++--- src/Feed/TimelineFeed.ts | 16 +++++++++++---- src/Nostr/RelayInfo.ts | 3 +++ src/Nostr/System.ts | 4 ++++ src/Pages/Root.tsx | 42 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/Element/Timeline.tsx b/src/Element/Timeline.tsx index 7d3b0f6..4cc114c 100644 --- a/src/Element/Timeline.tsx +++ b/src/Element/Timeline.tsx @@ -23,6 +23,7 @@ export interface TimelineProps { method: "TIME_RANGE" | "LIMIT_UNTIL"; ignoreModeration?: boolean; window?: number; + relay?: string; } /** @@ -34,11 +35,13 @@ export default function Timeline({ method, ignoreModeration = false, window, + relay, }: TimelineProps) { const { muted, isMuted } = useModeration(); const { main, related, latest, parent, loadMore, showLatest } = useTimelineFeed(subject, { method, window: window, + relay, }); const filterPosts = useCallback( diff --git a/src/Feed/Subscription.ts b/src/Feed/Subscription.ts index 871adaa..880aba8 100644 --- a/src/Feed/Subscription.ts +++ b/src/Feed/Subscription.ts @@ -13,6 +13,7 @@ export type NoteStore = { export type UseSubscriptionOptions = { leaveOpen: boolean; cache: boolean; + relay?: string; }; interface ReducerArg { @@ -130,10 +131,16 @@ export default function useSubscription( }); }; - console.debug("Adding sub: ", subDebounce.ToObject()); - System.AddSubscription(subDebounce); + const subObj = subDebounce.ToObject(); + console.debug("Adding sub: ", subObj); + if (options?.relay) { + System.AddSubscriptionToRelay(subDebounce, options.relay); + } else { + System.AddSubscription(subDebounce); + } return () => { - console.debug("Removing sub: ", subDebounce.ToObject()); + console.debug("Removing sub: ", subObj); + subDebounce.OnEvent = () => undefined; System.RemoveSubscription(subDebounce.Id); }; } diff --git a/src/Feed/TimelineFeed.ts b/src/Feed/TimelineFeed.ts index 40fb348..582db17 100644 --- a/src/Feed/TimelineFeed.ts +++ b/src/Feed/TimelineFeed.ts @@ -11,6 +11,7 @@ import { UserPreferences } from "State/Login"; export interface TimelineFeedOptions { method: "TIME_RANGE" | "LIMIT_UNTIL"; window?: number; + relay?: string; } export interface TimelineSubject { @@ -56,7 +57,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel } } return sub; - }, [subject.type, subject.items, subject.discriminator]); + }, [subject.type, subject.items, subject.discriminator, options.relay]); const sub = useMemo(() => { const sub = createSub(); @@ -89,7 +90,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel return sub; }, [until, since, options.method, pref, createSub]); - const main = useSubscription(sub, { leaveOpen: true, cache: true }); + const main = useSubscription(sub, { leaveOpen: true, cache: subject.type !== "global", relay: options.relay }); const subRealtime = useMemo(() => { const subLatest = createSub(); @@ -104,8 +105,15 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel const latest = useSubscription(subRealtime, { leaveOpen: true, cache: false, + relay: options.relay, }); + useEffect(() => { + // clear store if chaning relays + main.clear(); + latest.clear(); + }, [options.relay]); + const subNext = useMemo(() => { let sub: Subscriptions | undefined; if (trackingEvents.length > 0 && pref.enableReactions) { @@ -117,7 +125,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel return sub ?? null; }, [trackingEvents, pref, subject.type]); - const others = useSubscription(subNext, { leaveOpen: true, cache: true }); + const others = useSubscription(subNext, { leaveOpen: true, cache: subject.type !== "global", relay: options.relay }); const subParents = useMemo(() => { if (trackingParentEvents.length > 0) { @@ -129,7 +137,7 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel return null; }, [trackingParentEvents, subject.type]); - const parent = useSubscription(subParents); + const parent = useSubscription(subParents, { leaveOpen: false, cache: false, relay: options.relay }); useEffect(() => { if (main.store.notes.length > 0) { diff --git a/src/Nostr/RelayInfo.ts b/src/Nostr/RelayInfo.ts index e2b72ee..5c0e5b9 100644 --- a/src/Nostr/RelayInfo.ts +++ b/src/Nostr/RelayInfo.ts @@ -6,4 +6,7 @@ export interface RelayInfo { supported_nips?: number[]; software?: string; version?: string; + limitation?: { + payment_required: boolean; + }; } diff --git a/src/Nostr/System.ts b/src/Nostr/System.ts index e84a463..8d9cc48 100644 --- a/src/Nostr/System.ts +++ b/src/Nostr/System.ts @@ -75,6 +75,10 @@ export class NostrSystem { } } + AddSubscriptionToRelay(sub: Subscriptions, relay: string) { + this.Sockets.get(relay)?.AddSubscription(sub); + } + AddSubscription(sub: Subscriptions) { for (const [, s] of this.Sockets) { s.AddSubscription(sub); diff --git a/src/Pages/Root.tsx b/src/Pages/Root.tsx index 549507b..00d213c 100644 --- a/src/Pages/Root.tsx +++ b/src/Pages/Root.tsx @@ -1,5 +1,5 @@ import "./Root.css"; -import { useState } from "react"; +import { useMemo, useState } from "react"; import { useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { useIntl, FormattedMessage } from "react-intl"; @@ -10,6 +10,7 @@ import Timeline from "Element/Timeline"; import { TimelineSubject } from "Feed/TimelineFeed"; import messages from "./messages"; +import { System } from "Nostr/System"; export default function RootPage() { const { formatMessage } = useIntl(); @@ -29,6 +30,7 @@ export default function RootPage() { }, }; const [tab, setTab] = useState(RootTab.Posts); + const [relay, setRelay] = useState(); const tagTabs = tags.map((t, idx) => { return { text: `#${t}`, value: idx + 3 }; }); @@ -51,6 +53,20 @@ export default function RootPage() { } } + const globalRelays = useMemo(() => { + const ret: string[] = []; + System.Sockets.forEach((v, k) => { + if (v.Info?.limitation?.payment_required === true) { + ret.push(k); + } + }); + + if (ret.length > 0 && !relay) { + setRelay(ret[0]); + } + return ret; + }, [relays, relay]); + const isGlobal = loggedOut || tab.value === RootTab.Global.value; const timelineSubect: TimelineSubject = (() => { if (isGlobal) { @@ -63,16 +79,38 @@ export default function RootPage() { return { type: "pubkey", items: follows, discriminator: "follows" }; })(); + + if (isGlobal && globalRelays.length === 0) return null; return ( <>
{pubKey && }
+ {isGlobal && ( +
+
+ +
+
+ +
+
+ )} {followHints()} );