From c35b144dba48f641e593a87efa175f438926ff4d Mon Sep 17 00:00:00 2001 From: Kieran Date: Fri, 10 Feb 2023 18:25:17 +0000 Subject: [PATCH 1/4] 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 7d3b0f60..4cc114c7 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 871adaac..880aba8c 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 40fb3487..582db175 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 e2b72eef..5c0e5b91 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 e84a463d..8d9cc48f 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 549507b6..00d213c9 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()} ); From 6fef29a41ee5dfa67fcf28f3d92f2ddba6f75ad7 Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 14 Feb 2023 11:04:11 +0000 Subject: [PATCH 2/4] add more paid relays --- src/Const.ts | 6 ++++-- src/Pages/Root.tsx | 32 ++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Const.ts b/src/Const.ts index 1fabf33d..24801372 100644 --- a/src/Const.ts +++ b/src/Const.ts @@ -40,8 +40,10 @@ export const ProfileCacheExpire = 1_000 * 60 * 5; */ export const DefaultRelays = new Map([ ["wss://relay.snort.social", { read: true, write: true }], - ["wss://eden.nostr.land", { read: true, write: true }], - ["wss://atlas.nostr.land", { read: true, write: true }], + ["wss://nostr.wine", { read: true, write: false }], + ["wss://eden.nostr.land", { read: true, write: false }], + ["wss://atlas.nostr.land", { read: true, write: false }], + ["wss://relay.orangepill.dev", { read: true, write: false }], ]); /** diff --git a/src/Pages/Root.tsx b/src/Pages/Root.tsx index 00d213c9..df0a2681 100644 --- a/src/Pages/Root.tsx +++ b/src/Pages/Root.tsx @@ -1,5 +1,5 @@ import "./Root.css"; -import { useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import { useSelector } from "react-redux"; import { Link } from "react-router-dom"; import { useIntl, FormattedMessage } from "react-intl"; @@ -11,10 +11,11 @@ import { TimelineSubject } from "Feed/TimelineFeed"; import messages from "./messages"; import { System } from "Nostr/System"; +import { debounce } from "Util"; export default function RootPage() { const { formatMessage } = useIntl(); - const { loggedOut, publicKey: pubKey, follows, tags } = useSelector((s: RootState) => s.login); + const { loggedOut, publicKey: pubKey, follows, tags, relays } = useSelector((s: RootState) => s.login); const RootTab: Record = { Posts: { text: formatMessage(messages.Posts), @@ -31,6 +32,7 @@ export default function RootPage() { }; const [tab, setTab] = useState(RootTab.Posts); const [relay, setRelay] = useState(); + const [globalRelays, setGlobalRelays] = useState([]); const tagTabs = tags.map((t, idx) => { return { text: `#${t}`, value: idx + 3 }; }); @@ -53,18 +55,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); - } - }); + useEffect(() => { + return debounce(1_000, () => { + 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; + if (ret.length > 0 && !relay) { + setRelay(ret[0]); + } + setGlobalRelays(ret); + }); }, [relays, relay]); const isGlobal = loggedOut || tab.value === RootTab.Global.value; @@ -109,7 +113,7 @@ export default function RootPage() { subject={timelineSubect} postsOnly={tab.value === RootTab.Posts.value} method={"TIME_RANGE"} - window={isGlobal ? 60 : undefined} + window={undefined} relay={isGlobal ? relay : undefined} /> From d7dabecde4fdbb3559dd14e47df63b0e59207415 Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 14 Feb 2023 11:05:56 +0000 Subject: [PATCH 3/4] disable reactions for logged out --- src/State/Login.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/State/Login.ts b/src/State/Login.ts index 9ae50d41..02ef763b 100644 --- a/src/State/Login.ts +++ b/src/State/Login.ts @@ -283,6 +283,11 @@ const LoginSlice = createSlice({ if (pref) { state.preferences = JSON.parse(pref); } + + // disable reactions for logged out + if (state.loggedOut === true) { + state.preferences.enableReactions = false; + } }, setPrivateKey: (state, action: PayloadAction) => { state.loggedOut = false; From f6a01e541498448e1f38cb460872b917e6275346 Mon Sep 17 00:00:00 2001 From: Kieran Date: Tue, 14 Feb 2023 11:08:25 +0000 Subject: [PATCH 4/4] formatting --- src/Pages/Layout.tsx | 13 ++++++++----- src/index.tsx | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Pages/Layout.tsx b/src/Pages/Layout.tsx index 9fa85ae8..34d5abc2 100644 --- a/src/Pages/Layout.tsx +++ b/src/Pages/Layout.tsx @@ -65,9 +65,9 @@ export default function Layout() { () => publicKey ? totalUnread( - dms.filter(a => !isMuted(a.pubkey)), - publicKey - ) + dms.filter(a => !isMuted(a.pubkey)), + publicKey + ) : 0, [dms, publicKey] ); @@ -141,8 +141,11 @@ export default function Layout() { try { if ("registerProtocolHandler" in window.navigator) { - window.navigator.registerProtocolHandler("web+nostr", `${window.location.protocol}//${window.location.host}/handler/%s`); - console.info("Registered protocol handler for \"nostr\""); + window.navigator.registerProtocolHandler( + "web+nostr", + `${window.location.protocol}//${window.location.host}/handler/%s` + ); + console.info("Registered protocol handler for 'web+nostr'"); } } catch (e) { console.error("Failed to register protocol handler", e); diff --git a/src/index.tsx b/src/index.tsx index bef709ab..585ff3e8 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -25,7 +25,7 @@ import HashTagsPage from "Pages/HashTagsPage"; import SearchPage from "Pages/SearchPage"; import HelpPage from "Pages/HelpPage"; import { NewUserRoutes } from "Pages/new"; -import NostrLinkHandler from 'Pages/NostrLinkHandler'; +import NostrLinkHandler from "Pages/NostrLinkHandler"; import { IntlProvider } from "./IntlProvider"; import { unwrap } from "Util"; @@ -96,7 +96,7 @@ export const router = createBrowserRouter([ }, { path: "/handler/*", - element: + element: , }, ...NewUserRoutes, ],