From 66b94d954d5014e54009914e590b8d3f8448249c Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 14 May 2024 13:58:53 -0500 Subject: [PATCH] reconnect timeline on mount --- package.json | 4 +- src/classes/multi-subscription.ts | 7 +- .../components/repost-button.tsx | 5 +- src/hooks/use-event-exists.ts | 13 --- src/providers/global/publish-provider.tsx | 2 - src/services/event-count.ts | 1 - src/services/event-exists.ts | 108 ------------------ src/views/user/index.tsx | 46 +------- yarn.lock | 26 ++--- 9 files changed, 23 insertions(+), 189 deletions(-) delete mode 100644 src/hooks/use-event-exists.ts delete mode 100644 src/services/event-exists.ts diff --git a/package.json b/package.json index 98fe6308a..ff62e0934 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,8 @@ "@uiw/react-codemirror": "^4.21.21", "@webscopeio/react-textarea-autocomplete": "^4.9.2", "bech32": "^2.0.0", - "blossom-client-sdk": "^0.6.0", - "blossom-drive-sdk": "^0.3.0", + "blossom-client-sdk": "^0.7.0", + "blossom-drive-sdk": "^0.4.0", "blurhash": "^2.0.5", "chart.js": "^4.4.1", "cheerio": "^1.0.0-rc.12", diff --git a/src/classes/multi-subscription.ts b/src/classes/multi-subscription.ts index 5f2fc7dd1..7637e2a29 100644 --- a/src/classes/multi-subscription.ts +++ b/src/classes/multi-subscription.ts @@ -91,7 +91,7 @@ export default class MultiSubscription { // else open and update subscriptions for (const relay of this.relays) { let subscription = this.subscriptions.get(relay); - if (!subscription || !isFilterEqual(subscription.filters, this.filters)) { + if (!subscription || !isFilterEqual(subscription.filters, this.filters) || subscription.closed) { if (!subscription) { subscription = new PersistentSubscription(relay, { onevent: (event) => this.handleEvent(event), @@ -118,7 +118,10 @@ export default class MultiSubscription { } // update cache sub filters if they changed - if (this.cacheSubscription && !isFilterEqual(this.cacheSubscription.filters, this.filters)) { + if ( + this.cacheSubscription && + (!isFilterEqual(this.cacheSubscription.filters, this.filters) || this.cacheSubscription.closed) + ) { this.cacheSubscription.filters = this.filters; this.cacheSubscription.update(); } diff --git a/src/components/note/timeline-note/components/repost-button.tsx b/src/components/note/timeline-note/components/repost-button.tsx index 2693c6035..090ce08cb 100644 --- a/src/components/note/timeline-note/components/repost-button.tsx +++ b/src/components/note/timeline-note/components/repost-button.tsx @@ -4,7 +4,6 @@ import { kinds } from "nostr-tools"; import { NostrEvent } from "../../../../types/nostr-event"; import { RepostIcon } from "../../../icons"; import useEventCount from "../../../../hooks/use-event-count"; -import useEventExists from "../../../../hooks/use-event-exists"; import useCurrentAccount from "../../../../hooks/use-current-account"; import RepostModal from "./repost-modal"; @@ -12,10 +11,8 @@ export default function RepostButton({ event }: { event: NostrEvent }) { const { isOpen, onClose, onOpen } = useDisclosure(); const account = useCurrentAccount(); - const hasReposted = useEventExists( + const hasReposted = useEventCount( account ? { "#e": [event.id], kinds: [kinds.Repost, kinds.GenericRepost], authors: [account.pubkey] } : undefined, - [], //only check the cache - false, ); const repostCount = useEventCount({ "#e": [event.id], kinds: [kinds.Repost, kinds.GenericRepost] }); diff --git a/src/hooks/use-event-exists.ts b/src/hooks/use-event-exists.ts deleted file mode 100644 index b1e5f0462..000000000 --- a/src/hooks/use-event-exists.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMemo } from "react"; -import stringify from "json-stringify-deterministic"; -import eventExistsService from "../services/event-exists"; -import { NostrRequestFilter } from "../types/nostr-relay"; -import useSubject from "./use-subject"; - -export default function useEventExists(filter?: NostrRequestFilter, relays: string[] = [], fallback = true) { - const sub = useMemo( - () => filter && eventExistsService.requestExists(filter, relays), - [stringify(filter), relays.join("|")], - ); - return useSubject(sub) ?? fallback; -} diff --git a/src/providers/global/publish-provider.tsx b/src/providers/global/publish-provider.tsx index d3af9bd84..f88f03b71 100644 --- a/src/providers/global/publish-provider.tsx +++ b/src/providers/global/publish-provider.tsx @@ -9,7 +9,6 @@ import clientRelaysService from "../../services/client-relays"; import RelaySet from "../../classes/relay-set"; import { getAllRelayHints, isReplaceable } from "../../helpers/nostr/event"; import replaceableEventsService from "../../services/replaceable-events"; -import eventExistsService from "../../services/event-exists"; import eventReactionsService from "../../services/event-reactions"; import { localRelay } from "../../services/local-relay"; import { handleEventFromRelay } from "../../services/event-relays"; @@ -95,7 +94,6 @@ export default function PublishProvider({ children }: PropsWithChildren) { if (localRelay) localRelay.publish(signed); // pass it to other services - eventExistsService.handleEvent(signed); if (isReplaceable(signed.kind)) replaceableEventsService.handleEvent(signed); if (signed.kind === kinds.Reaction) eventReactionsService.handleEvent(signed); if (signed.kind === kinds.EventDeletion) deleteEventService.handleEvent(signed); diff --git a/src/services/event-count.ts b/src/services/event-count.ts index 672de0f12..0a188edb8 100644 --- a/src/services/event-count.ts +++ b/src/services/event-count.ts @@ -33,7 +33,6 @@ class EventCountService { } } -/** @deprecated */ const eventCountService = new EventCountService(); if (import.meta.env.DEV) { diff --git a/src/services/event-exists.ts b/src/services/event-exists.ts deleted file mode 100644 index f28cbbc83..000000000 --- a/src/services/event-exists.ts +++ /dev/null @@ -1,108 +0,0 @@ -import stringify from "json-stringify-deterministic"; - -import Subject from "../classes/subject"; -import { NostrRequestFilter } from "../types/nostr-relay"; -import SuperMap from "../classes/super-map"; -import relayScoreboardService from "./relay-scoreboard"; -import { logger } from "../helpers/debug"; -import { matchFilter, matchFilters } from "nostr-tools"; -import { NostrEvent } from "../types/nostr-event"; -import { relayRequest } from "../helpers/relay"; -import { localRelay } from "./local-relay"; -import relayPoolService from "./relay-pool"; - -function hashFilter(filter: NostrRequestFilter) { - return stringify(filter); -} - -class EventExistsService { - log = logger.extend("EventExistsService"); - answers = new SuperMap>(() => new Subject()); - private filters = new Map(); - - asked = new SuperMap>(() => new Set()); - pending = new SuperMap>(() => new Set()); - - getExists(filter: NostrRequestFilter) { - const key = hashFilter(filter); - return this.answers.get(key); - } - - requestExists(filter: NostrRequestFilter, relays: string[]) { - const key = hashFilter(filter); - const sub = this.answers.get(key); - const asked = this.asked.get(key); - const pending = this.pending.get(key); - - if (!this.filters.has(key)) this.filters.set(key, filter); - - if (sub.value !== true) { - const p = localRelay ? relayRequest(localRelay, Array.isArray(filter) ? filter : [filter]) : Promise.resolve([]); - - p.then((cached) => { - if (cached.length > 0) { - for (const e of cached) this.handleEvent(e, false); - } else { - for (const url of relays) { - if (!asked.has(url) && !pending.has(url)) { - pending.add(url); - } - } - } - }); - } - - return sub; - } - - nextRequests() { - for (const [key, relays] of this.pending) { - const filter = JSON.parse(key) as NostrRequestFilter; - const nextRelay = relayScoreboardService.getRankedRelays(Array.from(relays))[0]; - - if (!nextRelay) continue; - relays.delete(nextRelay); - - (async () => { - const subject = this.answers.get(key); - const limitFilter = Array.isArray(filter) ? filter.map((f) => ({ ...f, limit: 1 })) : [{ ...filter, limit: 1 }]; - const subscription = relayPoolService.requestRelay(nextRelay).subscribe(limitFilter, { - eoseTimeout: 500, - onevent: () => { - this.log("Found event for", filter); - subject.next(true); - this.pending.delete(key); - }, - oneose: () => { - if (subject.value === undefined && this.asked.get(key).size > this.pending.get(key).size) { - this.log("Could not find event for", filter); - subject.next(false); - } - subscription.close(); - }, - }); - })(); - } - } - - handleEvent(event: NostrEvent, cache = true) { - for (const [key, filter] of this.filters) { - const doesMatch = Array.isArray(filter) ? matchFilters(filter, event) : matchFilter(filter, event); - if (doesMatch && this.answers.get(key).value !== true) { - this.answers.get(key).next(true); - } - } - - if (cache && localRelay) localRelay.publish(event); - } -} - -const eventExistsService = new EventExistsService(); -setInterval(() => eventExistsService.nextRequests(), 1000); - -if (import.meta.env.DEV) { - // @ts-ignore - window.eventExistsService = eventExistsService; -} - -export default eventExistsService; diff --git a/src/views/user/index.tsx b/src/views/user/index.tsx index 8f53c3e2b..59b51ed08 100644 --- a/src/views/user/index.tsx +++ b/src/views/user/index.tsx @@ -1,4 +1,4 @@ -import { Suspense, useMemo, useState } from "react"; +import { Suspense, useState } from "react"; import { Flex, FormControl, @@ -25,7 +25,6 @@ import { Tabs, useDisclosure, } from "@chakra-ui/react"; -import { kinds } from "nostr-tools"; import { Outlet, useMatches, useNavigate } from "react-router-dom"; import useUserMetadata from "../../hooks/use-user-metadata"; @@ -38,11 +37,6 @@ import { unique } from "../../helpers/array"; import { RelayFavicon } from "../../components/relay-favicon"; import Header from "./components/header"; import { ErrorBoundary } from "../../components/error-boundary"; -import useEventExists from "../../hooks/use-event-exists"; -import { STEMSTR_TRACK_KIND } from "../../helpers/nostr/stemstr"; -import { STREAM_KIND } from "../../helpers/nostr/stream"; -import { TORRENT_KIND } from "../../helpers/nostr/torrents"; -import { GOAL_KIND } from "../../helpers/nostr/goal"; import useParamsProfilePointer from "../../hooks/use-params-pubkey-pointer"; import useUserMailboxes from "../../hooks/use-user-mailboxes"; @@ -84,40 +78,10 @@ const UserView = () => { const metadata = useUserMetadata(pubkey, userTopRelays, { alwaysRequest: true }); useAppTitle(getDisplayName(metadata, pubkey)); - const hasTorrents = useEventExists({ kinds: [TORRENT_KIND], authors: [pubkey] }, readRelays); - const hasGoals = useEventExists({ kinds: [GOAL_KIND], authors: [pubkey] }, readRelays); - const hasTracks = useEventExists({ kinds: [STEMSTR_TRACK_KIND], authors: [pubkey] }, [ - "wss://relay.stemstr.app", - ...readRelays, - ]); - const hasArticles = useEventExists({ kinds: [kinds.LongFormArticle], authors: [pubkey] }, readRelays); - const hasStreams = useEventExists({ kinds: [STREAM_KIND], authors: [pubkey] }, [ - "wss://relay.snort.social", - "wss://nos.lol", - "wss://relay.damus.io", - "wss://nostr.wine", - ...readRelays, - ]); - - const filteredTabs = useMemo( - () => - tabs.filter((tab) => { - if (tab.path === "tracks" && hasTracks === false) return false; - if (tab.path === "articles" && hasArticles === false) return false; - if (tab.path === "streams" && hasStreams === false) return false; - if (tab.path === "torrents" && hasTorrents === false) return false; - if (tab.path === "goals" && hasGoals === false) return false; - return true; - }), - [hasTracks, hasArticles, hasStreams, hasTorrents, hasGoals, tabs], - ); - const matches = useMatches(); const lastMatch = matches[matches.length - 1]; - const activeTab = filteredTabs.indexOf( - filteredTabs.find((t) => lastMatch.pathname.endsWith(t.path)) ?? filteredTabs[0], - ); + const activeTab = tabs.indexOf(tabs.find((t) => lastMatch.pathname.endsWith(t.path)) ?? tabs[0]); return ( <> @@ -130,12 +94,12 @@ const UserView = () => { flexGrow="1" isLazy index={activeTab} - onChange={(v) => navigate(filteredTabs[v].path, { replace: true })} + onChange={(v) => navigate(tabs[v].path, { replace: true })} colorScheme="primary" h="full" > - {filteredTabs.map(({ label }) => ( + {tabs.map(({ label }) => ( {label} @@ -143,7 +107,7 @@ const UserView = () => { - {filteredTabs.map(({ label }) => ( + {tabs.map(({ label }) => ( }> diff --git a/yarn.lock b/yarn.lock index 41075bb9b..cf5c2315d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3419,28 +3419,22 @@ better-path-resolve@1.0.0: resolved "https://registry.yarnpkg.com/bezier-js/-/bezier-js-6.1.4.tgz#c7828f6c8900562b69d5040afb881bcbdad82001" integrity sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg== -blossom-client-sdk@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/blossom-client-sdk/-/blossom-client-sdk-0.5.1.tgz#9b07ed2ebd29903268a44ea1b7f1b54d2edace46" - integrity sha512-RuT+uyNLVToSivANQrrA2Kmio8l0Z2lEIs3e7OwBnd/gxcl+KoINwuZ/JVjsquOPNcjkXBVbsvmRzJnesmkjWg== +blossom-client-sdk@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/blossom-client-sdk/-/blossom-client-sdk-0.7.0.tgz#e9224f333c953d57cdfdf2aa41fbd99435da27a2" + integrity sha512-xG0HiuhFcK6UpmYjJ4vRPm3APMrRf+MQDfZWlNRTxs2gEETfqbhYm5pCl2hPfLjpEcFSDXgr3sLCh6C77ABKgg== dependencies: + "@noble/hashes" "^1.4.0" cross-fetch "^4.0.0" -blossom-client-sdk@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/blossom-client-sdk/-/blossom-client-sdk-0.6.0.tgz#e5fc2b17f3d76e3b8bb3d31a535db294ebce5a07" - integrity sha512-m1dAIQF0WceEvpxbl349IUeNTay6w/QF7RAUlELIFxES7fbRQB0dkbVhT58y+SW+tTQvgMfuPmMAAsghrGwGfg== - dependencies: - cross-fetch "^4.0.0" - -blossom-drive-sdk@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/blossom-drive-sdk/-/blossom-drive-sdk-0.3.0.tgz#35ab1afebbc8c79bd86af10628291b3e06935f35" - integrity sha512-K2mhnIO1WVSb7Ua9wcgv4ra3rnoIfp1X8oKdHOFNNosuCVI5dBZumDvYJlrn4ZztE9UZslIqlb/swr0PZcGmgw== +blossom-drive-sdk@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/blossom-drive-sdk/-/blossom-drive-sdk-0.4.0.tgz#c24a7dda7a540e9fda21372a34c5c764411f434b" + integrity sha512-bDOTFtsoT40+NbGYteG50PaKR0wDnMeCN4BmMDI5R/zkbvAz4Qh+OC3zVbsbZekQPM9L5tAH+wuF+Qe/vh3s7Q== dependencies: "@noble/hashes" "^1.4.0" "@scure/base" "^1.1.6" - blossom-client-sdk "^0.5.1" + blossom-client-sdk "^0.7.0" eventemitter3 "^5.0.1" mime "^4.0.1" nanoid "^5.0.6"