mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-17 21:31:43 +01:00
reconnect timeline on mount
This commit is contained in:
parent
8266e4f72a
commit
66b94d954d
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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] });
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -33,7 +33,6 @@ class EventCountService {
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
const eventCountService = new EventCountService();
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
|
@ -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<string, Subject<boolean>>(() => new Subject());
|
||||
private filters = new Map<string, NostrRequestFilter>();
|
||||
|
||||
asked = new SuperMap<string, Set<string>>(() => new Set());
|
||||
pending = new SuperMap<string, Set<string>>(() => 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;
|
@ -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"
|
||||
>
|
||||
<TabList overflowX="auto" overflowY="hidden" flexShrink={0}>
|
||||
{filteredTabs.map(({ label }) => (
|
||||
{tabs.map(({ label }) => (
|
||||
<Tab key={label} whiteSpace="pre">
|
||||
{label}
|
||||
</Tab>
|
||||
@ -143,7 +107,7 @@ const UserView = () => {
|
||||
</TabList>
|
||||
|
||||
<TabPanels>
|
||||
{filteredTabs.map(({ label }) => (
|
||||
{tabs.map(({ label }) => (
|
||||
<TabPanel key={label} p={0}>
|
||||
<ErrorBoundary>
|
||||
<Suspense fallback={<Spinner />}>
|
||||
|
26
yarn.lock
26
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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user