Skip to content

Commit 72017ff

Browse files
committed
debug subs
1 parent 53732a2 commit 72017ff

File tree

9 files changed

+270
-58
lines changed

9 files changed

+270
-58
lines changed

src/debug/DebugApp.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ interface MediaFeedMemory {
5252
timestamp: number
5353
}
5454

55+
interface SubscriptionData {
56+
filters: unknown[]
57+
relays: string[]
58+
}
59+
5560
const DebugApp = () => {
5661
const [session, setSession] = useState<DebugSession | null>(null)
5762
const [sessionLink, setSessionLink] = useState<string>("")
@@ -66,6 +71,10 @@ const DebugApp = () => {
6671
MediaFeedPerformance[]
6772
>([])
6873
const [mediaFeedMemory, setMediaFeedMemory] = useState<MediaFeedMemory[]>([])
74+
const [subscriptions, setSubscriptions] = useState<Record<
75+
string,
76+
SubscriptionData
77+
> | null>(null)
6978
const [userAgent, setUserAgent] = useState<string>("")
7079
const [currentUrl, setCurrentUrl] = useState<string>("")
7180

@@ -109,6 +118,11 @@ const DebugApp = () => {
109118
}
110119
})
111120

121+
// Subscribe to subscriptions data
122+
const unsubscribeSubscriptions = debugSession.subscribe("subscriptions", (value) => {
123+
setSubscriptions(value as Record<string, SubscriptionData>)
124+
})
125+
112126
// Subscribe to heartbeat data to check if Iris browser is online
113127
const unsubscribeData = debugSession.subscribe("data", (value, event) => {
114128
const eventTime = event.created_at // Event timestamp in seconds
@@ -199,6 +213,7 @@ const DebugApp = () => {
199213
clearInterval(heartbeatInterval)
200214
unsubscribeTest()
201215
unsubscribeData()
216+
unsubscribeSubscriptions()
202217
unsubscribeMediaFeedDebug()
203218
unsubscribeMediaFeedPerformance()
204219
unsubscribeMediaFeedMemory()
@@ -319,6 +334,49 @@ const DebugApp = () => {
319334
</div>
320335
)}
321336

337+
{subscriptions && <div className="divider">Active Subscriptions</div>}
338+
339+
{subscriptions && (
340+
<div className="card bg-base-200 shadow">
341+
<div className="card-body">
342+
<h3 className="card-title">
343+
Subscription Details ({Object.keys(subscriptions).length} total)
344+
<span className="badge badge-warning badge-sm">Live</span>
345+
</h3>
346+
<div className="overflow-x-auto max-h-96">
347+
<table className="table table-xs">
348+
<thead>
349+
<tr>
350+
<th>ID</th>
351+
<th>Filters</th>
352+
<th>Relays</th>
353+
</tr>
354+
</thead>
355+
<tbody>
356+
{Object.entries(subscriptions).map(([id, data]) => (
357+
<tr key={id}>
358+
<td className="font-mono text-xs">{id}</td>
359+
<td className="text-xs max-w-md">
360+
<pre className="whitespace-pre-wrap break-all">
361+
{JSON.stringify(data.filters, null)}
362+
</pre>
363+
</td>
364+
<td className="text-xs">
365+
{data.relays.map((relay, i) => (
366+
<div key={i} className="truncate">
367+
{relay}
368+
</div>
369+
))}
370+
</td>
371+
</tr>
372+
))}
373+
</tbody>
374+
</table>
375+
</div>
376+
</div>
377+
</div>
378+
)}
379+
322380
{mediaFeedDebug && <div className="divider">MediaFeed Debug</div>}
323381

324382
{mediaFeedDebug && (

src/shared/components/event/FeedItem/FeedItem.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {eventsByIdCache, addSeenEventId} from "@/utils/memcache.ts"
22
import {useEffect, useMemo, useState, useRef, memo} from "react"
3-
import {NDKEvent} from "@nostr-dev-kit/ndk"
3+
import {NDKEvent, NDKSubscription} from "@nostr-dev-kit/ndk"
44
import classNames from "classnames"
55

6-
import {getEventReplyingTo, fetchEvent, getEventRoot, isRepost} from "@/utils/nostr.ts"
6+
import {getEventReplyingTo, getEventRoot, isRepost} from "@/utils/nostr.ts"
77
import {getEventIdHex, handleEventContent} from "@/shared/components/event/utils.ts"
88
import RepostHeader from "@/shared/components/event/RepostHeader.tsx"
99
import FeedItemActions from "../reactions/FeedItemActions.tsx"
@@ -18,6 +18,7 @@ import FeedItemTitle from "./FeedItemTitle.tsx"
1818
import {Link, useNavigate} from "react-router"
1919
import LikeHeader from "../LikeHeader"
2020
import {nip19} from "nostr-tools"
21+
import {ndk} from "@/utils/ndk"
2122

2223
const replySortFn = (a: NDKEvent, b: NDKEvent) => {
2324
const followDistanceA = socialGraph().getFollowDistance(a.pubkey)
@@ -64,6 +65,7 @@ function FeedItem({
6465
const [expanded, setExpanded] = useState(false)
6566
const [hasActualReplies, setHasActualReplies] = useState(false)
6667
const navigate = useNavigate()
68+
const subscriptionRef = useRef<NDKSubscription | null>(null)
6769

6870
if ((!initialEvent || !initialEvent.id) && !eventId) {
6971
throw new Error(
@@ -146,29 +148,58 @@ function FeedItem({
146148
}, [event])
147149

148150
useEffect(() => {
151+
// Clean up any existing subscription first
152+
if (subscriptionRef.current) {
153+
subscriptionRef.current.stop()
154+
// Force cleanup by removing from subscription manager (NDK bug workaround)
155+
if (subscriptionRef.current.ndk?.subManager) {
156+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
157+
}
158+
subscriptionRef.current = null
159+
}
160+
149161
if (!event && eventIdHex) {
150162
const cached = eventsByIdCache.get(eventIdHex)
151163
if (cached) {
152164
setEvent(cached)
153165
} else {
154-
fetchEvent({ids: [eventIdHex], authors: authorHints}).then((fetched) => {
155-
if (fetched) {
156-
setEvent(fetched)
157-
eventsByIdCache.set(eventIdHex, fetched)
166+
const sub = ndk().subscribe(
167+
{ids: [eventIdHex], authors: authorHints},
168+
{closeOnEose: true}
169+
)
170+
subscriptionRef.current = sub
171+
172+
sub.on("event", (fetchedEvent: NDKEvent) => {
173+
if (fetchedEvent && fetchedEvent.id) {
174+
setEvent(fetchedEvent)
175+
eventsByIdCache.set(eventIdHex, fetchedEvent)
158176
}
159177
})
160178
}
161179
}
180+
181+
return () => {
182+
if (subscriptionRef.current) {
183+
subscriptionRef.current.stop()
184+
// Force cleanup by removing from subscription manager (NDK bug workaround)
185+
if (subscriptionRef.current.ndk?.subManager) {
186+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
187+
}
188+
subscriptionRef.current = null
189+
}
190+
}
162191
}, [event, eventIdHex, authorHints])
163192

164193
useEffect(() => {
165194
if (event) {
166-
handleEventContent(event, (referred) => {
195+
const cleanup = handleEventContent(event, (referred) => {
167196
setReferredEvent(referred)
168197
eventsByIdCache.set(eventIdHex, referred)
169198
})
199+
200+
return cleanup
170201
}
171-
}, [event])
202+
}, [event, eventIdHex])
172203

173204
const wrapperClasses = classNames("relative max-w-[100vw]", {
174205
"h-[200px] overflow-hidden": asEmbed && !expanded,

src/shared/components/event/utils.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import {getTag, NDKEventFromRawEvent, fetchEvent} from "@/utils/nostr.ts"
1+
import {getTag, NDKEventFromRawEvent} from "@/utils/nostr.ts"
22
import {NDKEvent} from "@nostr-dev-kit/ndk"
33
import {nip19} from "nostr-tools"
4+
import {ndk} from "@/utils/ndk"
45

5-
export const handleEventContent = async (
6+
export const handleEventContent = (
67
event: NDKEvent,
78
setReferredEvent: (event: NDKEvent) => void
8-
) => {
9+
): (() => void) | undefined => {
910
try {
1011
if (event.kind === 6 || event.kind === 7) {
1112
let originalEvent
@@ -17,17 +18,33 @@ export const handleEventContent = async (
1718
if (originalEvent && originalEvent?.id) {
1819
const ndkEvent = NDKEventFromRawEvent(originalEvent)
1920
setReferredEvent(ndkEvent)
21+
return undefined // No cleanup needed
2022
} else {
2123
const eTag = getTag("e", event.tags)
2224
if (eTag) {
23-
const origEvent = await fetchEvent({ids: [eTag]})
24-
if (origEvent) setReferredEvent(origEvent)
25+
const sub = ndk().subscribe({ids: [eTag]}, {closeOnEose: true})
26+
27+
sub.on("event", (fetchedEvent: NDKEvent) => {
28+
if (fetchedEvent && fetchedEvent.id) {
29+
setReferredEvent(fetchedEvent)
30+
}
31+
})
32+
33+
return () => {
34+
sub.stop()
35+
// Force cleanup by removing from subscription manager (NDK bug workaround)
36+
if (sub.ndk?.subManager) {
37+
sub.ndk.subManager.subscriptions.delete(sub.internalId)
38+
}
39+
}
2540
}
2641
}
2742
}
2843
} catch (error) {
2944
console.warn(error)
3045
}
46+
47+
return undefined
3148
}
3249
export const getEventIdHex = (event?: NDKEvent, eventId?: string) => {
3350
if (event?.id) {

src/shared/components/feed/ImageGridItem.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import {useNavigate} from "react-router"
2-
import {useEffect, useState, useMemo, memo, MutableRefObject} from "react"
3-
import {NDKEvent} from "@nostr-dev-kit/ndk"
2+
import {useEffect, useState, useMemo, memo, MutableRefObject, useRef} from "react"
3+
import {NDKEvent, NDKSubscription} from "@nostr-dev-kit/ndk"
44
import {decode} from "blurhash"
55
import {nip19} from "nostr-tools"
66

77
import {eventsByIdCache} from "@/utils/memcache.ts"
8-
import {fetchEvent} from "@/utils/nostr.ts"
98
import {IMAGE_REGEX, VIDEO_REGEX} from "@/shared/components/embed/media/MediaEmbed.tsx"
109
import {useSettingsStore} from "@/stores/settings"
1110
import MarketGridItem from "../market/MarketGridItem"
1211
import {isMarketListing} from "@/shared/utils/marketUtils.ts"
1312
import ProxyImg from "../ProxyImg"
1413
import Icon from "../Icons/Icon"
1514
import {LRUCache} from "typescript-lru-cache"
15+
import {ndk} from "@/utils/ndk"
1616

1717
interface ImageGridItemProps {
1818
event: NDKEvent | {id: string}
@@ -74,12 +74,23 @@ const ImageGridItem = memo(function ImageGridItem({
7474
"content" in initialEvent ? initialEvent : undefined
7575
)
7676
const {content, imgproxy} = useSettingsStore()
77+
const subscriptionRef = useRef<NDKSubscription | null>(null)
7778

7879
const eventIdHex = useMemo(() => {
7980
return "content" in initialEvent ? initialEvent.id : initialEvent.id
8081
}, [initialEvent])
8182

8283
useEffect(() => {
84+
// Clean up any existing subscription first
85+
if (subscriptionRef.current) {
86+
subscriptionRef.current.stop()
87+
// Force cleanup by removing from subscription manager (NDK bug workaround)
88+
if (subscriptionRef.current.ndk?.subManager) {
89+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
90+
}
91+
subscriptionRef.current = null
92+
}
93+
8394
if (event) {
8495
onEventFetched?.(event)
8596
return
@@ -91,17 +102,27 @@ const ImageGridItem = memo(function ImageGridItem({
91102
setEvent(cached)
92103
onEventFetched?.(cached)
93104
} else {
94-
fetchEvent({ids: [eventIdHex]})
95-
.then((fetched) => {
96-
if (fetched) {
97-
setEvent(fetched)
98-
eventsByIdCache.set(eventIdHex, fetched)
99-
onEventFetched?.(fetched)
100-
}
101-
})
102-
.catch((error) => {
103-
console.warn("Failed to fetch event:", error)
104-
})
105+
const sub = ndk().subscribe({ids: [eventIdHex]}, {closeOnEose: true})
106+
subscriptionRef.current = sub
107+
108+
sub.on("event", (fetchedEvent: NDKEvent) => {
109+
if (fetchedEvent && fetchedEvent.id) {
110+
setEvent(fetchedEvent)
111+
eventsByIdCache.set(eventIdHex, fetchedEvent)
112+
onEventFetched?.(fetchedEvent)
113+
}
114+
})
115+
}
116+
}
117+
118+
return () => {
119+
if (subscriptionRef.current) {
120+
subscriptionRef.current.stop()
121+
// Force cleanup by removing from subscription manager (NDK bug workaround)
122+
if (subscriptionRef.current.ndk?.subManager) {
123+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
124+
}
125+
subscriptionRef.current = null
105126
}
106127
}
107128
}, [event, eventIdHex, onEventFetched])

src/shared/hooks/useFollows.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import socialGraph, {handleSocialGraphEvent} from "@/utils/socialGraph.ts"
22
import {PublicKey} from "@/shared/utils/PublicKey"
3-
import {useEffect, useState, useMemo} from "react"
3+
import {useEffect, useState, useMemo, useRef} from "react"
44
import {NostrEvent} from "nostr-social-graph"
5-
import {NDKEvent} from "@nostr-dev-kit/ndk"
5+
import {NDKEvent, NDKSubscription} from "@nostr-dev-kit/ndk"
66
import {ndk} from "@/utils/ndk"
77

88
const useFollows = (pubKey: string | null | undefined, includeSelf = false) => {
@@ -11,6 +11,7 @@ const useFollows = (pubKey: string | null | undefined, includeSelf = false) => {
1111
[pubKey]
1212
)
1313
const [follows, setFollows] = useState<string[]>([])
14+
const subscriptionRef = useRef<NDKSubscription | null>(null)
1415

1516
// Initialize follows when pubKeyHex changes
1617
useEffect(() => {
@@ -22,11 +23,22 @@ const useFollows = (pubKey: string | null | undefined, includeSelf = false) => {
2223
}, [pubKeyHex, includeSelf])
2324

2425
useEffect(() => {
26+
// Clean up any existing subscription first
27+
if (subscriptionRef.current) {
28+
subscriptionRef.current.stop()
29+
// Force cleanup by removing from subscription manager (NDK bug workaround)
30+
if (subscriptionRef.current.ndk?.subManager) {
31+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
32+
}
33+
subscriptionRef.current = null
34+
}
35+
2536
try {
2637
if (pubKeyHex) {
2738
const filter = {kinds: [3], authors: [pubKeyHex]}
2839

29-
const sub = ndk().subscribe(filter)
40+
const sub = ndk().subscribe(filter, {closeOnEose: true})
41+
subscriptionRef.current = sub
3042

3143
let latestTimestamp = 0
3244

@@ -50,13 +62,21 @@ const useFollows = (pubKey: string | null | undefined, includeSelf = false) => {
5062
setFollows(pubkeys)
5163
}
5264
})
53-
return () => {
54-
sub.stop()
55-
}
5665
}
5766
} catch (error) {
5867
console.warn(error)
5968
}
69+
70+
return () => {
71+
if (subscriptionRef.current) {
72+
subscriptionRef.current.stop()
73+
// Force cleanup by removing from subscription manager (NDK bug workaround)
74+
if (subscriptionRef.current.ndk?.subManager) {
75+
subscriptionRef.current.ndk.subManager.subscriptions.delete(subscriptionRef.current.internalId)
76+
}
77+
subscriptionRef.current = null
78+
}
79+
}
6080
}, [pubKeyHex, includeSelf, pubKey])
6181

6282
return follows

0 commit comments

Comments
 (0)