Skip to content

Commit

Permalink
fix most of the memory leaks in feeds, need to find a solution for ob…
Browse files Browse the repository at this point in the history
…serve
  • Loading branch information
dskvr committed Jan 27, 2025
1 parent 1726b48 commit 78d9b8d
Show file tree
Hide file tree
Showing 23 changed files with 375 additions and 120 deletions.
2 changes: 1 addition & 1 deletion apps/gui/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@nostrwatch/gui",
"description": "",
"version": "0.6.23",
"version": "0.6.24",
"license": "MIT",
"keywords": [
"svelte",
Expand Down
30 changes: 0 additions & 30 deletions apps/gui/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,5 @@ export default [
watch: {
clearScreen: false
}
},
{
treeshake: production,
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
inlineDynamicImports: true
},
plugins: [
svelte({
compilerOptions: {
dev: !production
}
}),
css({ output: 'bundle.css' }),
resolve({
browser: true,
dedupe: ['svelte', '@nostrwatch/route66', '@nostrwatch/route66-cacheadapter-dexieetl', '@nostrwatch/route66-wsadapter-nostrtools'],
exportConditions: ['svelte']
}),
commonjs(),
!production && livereload('public'),
production && terser()
],
watch: {
clearScreen: false
}
}
];
2 changes: 1 addition & 1 deletion apps/gui/src/lib/components/partials/Debugger.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
addDebug('route66:websocketAdapter', $route66?.websocketAdapter.isReady? true: false);
addDebug('route66:initialized', $route66?.initialized? true: false);
addDebug('route66:numSubscriptions', $route66?.websocketAdapter?.subscriptions.size);
addDebug('route66:subscriptions', Array.from($route66?.websocketAdapter?.subscriptions));
// addDebug('route66:subscriptions', Array.from($route66?.websocketAdapter?.subscriptions));
}
const debugCacheAdapter = async () => {
Expand Down
9 changes: 5 additions & 4 deletions apps/gui/src/lib/components/partials/Feed.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
const busy: Writable<boolean> = writable(false);
let items: Readable<NostrEvent[]> | undefined;
let [minColWidth, maxColWidth, gap] = [300, 500, 21]
let [minColWidth, maxColWidth, gap] = [400, 600, 21]
let width:number, height: number
const lastItemId = () => {
Expand All @@ -54,7 +54,10 @@
}
const destroy = () => {
$feedService!.unsubscribeAll();
$feedService!.unsubscribeAll().then( () => {
$feedService!.destroy();
feedService.set(null)
});
resumer?.()
}
Expand All @@ -71,8 +74,6 @@
</div>
{/if}

{$items?.length}

{#if $feedService && $items?.length}
<Masonry
items={$items as NostrEvent[]}
Expand Down
63 changes: 25 additions & 38 deletions apps/gui/src/lib/components/partials/FeedNote.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
import { observeViewport } from '$lib/utils/ux';
import { onDestroy, onMount } from 'svelte';
import { writable, type Readable, type Writable } from 'svelte/store';
import Bolt11 from 'light-bolt11-decoder';
import { pubkeyUserInstance } from '$stores/helpers/helpers-pubkey';
import type { SvelteMemoryRelay } from '@nostrwatch/memory-relay';
import { noteCommentsCount$, noteReactionsCount$, noteZaps$ } from '$stores/helpers/helpers-notes';
import { activeMonitorChecksCount } from '$stores/monitors';
import FeedNoteComments from './FeedNoteComments.svelte';
import FeedNoteZaps from './FeedNoteZaps.svelte';
import FeedNoteReactions from './FeedNoteReactions.svelte';
export let note: NostrEvent;
export let memoryRelay: SvelteMemoryRelay<IEvent, NostrEvent>;
const comments: Readable<number> = noteCommentsCount$<NostrEvent>(note.id, memoryRelay);
const zaps: Readable<NostrEvent[]> = noteZaps$<NostrEvent>(note.id, memoryRelay);
const reactions: Readable<number> = noteReactionsCount$<NostrEvent>(note.id, memoryRelay);
let content: Writable<string>;
const mount = () => {
Expand All @@ -46,44 +44,24 @@
$: isComment = note.isComment
$: user = pubkeyUserInstance(note.pubkey)
$: name = user?.name || user?.pubkey
// $: animationClass = $relativesFetched? 'animate' : ''
$: bolt11s = $zaps.map(zap => {
const b11 = zap.tags.find(tag => tag[0] === 'bolt11')?.[1]
if(!b11) return null
return Bolt11.decode(b11)
}).filter( b11 => b11 !== null )
$: zapSum = isVisible? abbrNum(
Math
.round(
bolt11s
.reduce((acc, b11) => acc += parseInt(
b11.sections.find(
section => section?.name === 'amount')?.value || "0"
)
, 0)
/1000
)
): '';
let isVisible: boolean = true;
$: actionsClass = isVisible? '' : 'opacity-0';
function abbrNum(num: number): string {
if(num === 0) return '';
if (num < 1000) return num.toString();
const units = ["", "K", "M", "B", "T", "P", "E"];
const magnitude = Math.floor(Math.log10(num) / 3);
const precision = magnitude - 1;
const scaled = num / Math.pow(1000, magnitude);
return `${scaled.toFixed(precision + 1)}${units[magnitude]}`;
}
let commentsCountCache: number | undefined;
let reactionsCountCache: number | undefined;
let zapSumCache: string = '';
</script>

<section
tabindex="-1"
id="note-{note.id}"
class="note px-8 py-5 rounded-lg bg-black/5 dark:bg-white/5 text-md block mb-3"
use:observeViewport
on:viewportchange={(event: any) => {
isVisible = event.detail.isIntersecting;
}}
>
<div class="text-xs text-gray-400">
<span class="text-xs text-gray-400">
Expand All @@ -106,22 +84,31 @@
{@html $content}
</div>
<div class="actions flex mt-2 hover:opacity-100 {actionsClass} min-h-6">
{#if isVisible}
<div class="flex-grow">
<a href="">♡</a>
{$reactions? $reactions : ''}
{#if isVisible}
<FeedNoteReactions {note} {memoryRelay} bind:reactionsCountCache={reactionsCountCache} />
{:else}
{reactionsCountCache? reactionsCountCache : ''}
{/if}
</div>
<div class="flex-grow">
<a href="">⚡</a>
{zapSum}
{#if isVisible}
<FeedNoteZaps {note} {memoryRelay} bind:zapSumCache={zapSumCache} />
{:else}
{zapSumCache? zapSumCache : ''}
{/if}
</div>
<div class="flex-grow">
<a href="">🗨</a>
{$comments? $comments : ''}
{#if isVisible}
<FeedNoteComments {note} {memoryRelay} bind:commentsCountCache={commentsCountCache} />
{:else}
{commentsCountCache? commentsCountCache : ''}
{/if}
</div>
{/if}
</div>

</section>

<style global>
Expand Down
14 changes: 14 additions & 0 deletions apps/gui/src/lib/components/partials/FeedNoteComments.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { type Readable } from 'svelte/store';
import { noteCommentsCount$ } from '$stores/helpers/helpers-notes';
import type { NostrEvent } from '@nostrwatch/route66/models';
import type { SvelteMemoryRelay } from '@nostrwatch/memory-relay';
export let note: NostrEvent;
export let memoryRelay: SvelteMemoryRelay<NostrEvent, NostrEvent>;
export let commentsCountCache: number;
const comments: Readable<number> = noteCommentsCount$<NostrEvent>(note.id, memoryRelay);
comments.subscribe( count => commentsCountCache = count )
</script>

{commentsCountCache? commentsCountCache : ''}
14 changes: 14 additions & 0 deletions apps/gui/src/lib/components/partials/FeedNoteReactions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { type Readable } from 'svelte/store';
import { noteReactionsCount$ } from '$stores/helpers/helpers-notes';
import type { NostrEvent } from '@nostrwatch/route66/models';
import type { SvelteMemoryRelay } from '@nostrwatch/memory-relay';
export let note: NostrEvent;
export let memoryRelay: SvelteMemoryRelay<NostrEvent, NostrEvent>;
export let reactionsCountCache: number;
const reactions: Readable<number> = noteReactionsCount$<NostrEvent>(note.id, memoryRelay);
reactions.subscribe( count => reactionsCountCache = count )
</script>

{$reactions? $reactions : ''}
47 changes: 47 additions & 0 deletions apps/gui/src/lib/components/partials/FeedNoteZaps.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="ts">
import Bolt11 from 'light-bolt11-decoder';
import { type Readable } from 'svelte/store';
import { noteCommentsCount$, noteZaps$ } from '$stores/helpers/helpers-notes';
import type { NostrEvent } from '@nostrwatch/route66/models';
import type { SvelteMemoryRelay } from '@nostrwatch/memory-relay';
export let note: NostrEvent;
export let memoryRelay: SvelteMemoryRelay<NostrEvent, NostrEvent>;
export let zapSumCache: string;
const zaps: Readable<NostrEvent[]> = noteZaps$<NostrEvent>(note.id, memoryRelay);
$: bolt11s = $zaps.map(zap => {
const b11 = zap.tags.find(tag => tag[0] === 'bolt11')?.[1]
if(!b11) return null
return Bolt11.decode(b11)
}).filter( b11 => b11 !== null )
$: zapSum = abbrNum(
Math
.round(
bolt11s
.reduce((acc, b11) => acc += parseInt(
b11.sections.find(
section => section?.name === 'amount')?.value || "0"
)
, 0)
/1000
)
);
zaps.subscribe( sum => zapSumCache = zapSum )
function abbrNum(num: number): string {
if(num === 0) return '';
if (num < 1000) return num.toString();
const units = ["", "K", "M", "B", "T", "P", "E"];
const magnitude = Math.floor(Math.log10(num) / 3);
const precision = magnitude - 1;
const scaled = num / Math.pow(1000, magnitude);
return `${scaled.toFixed(precision + 1)}${units[magnitude]}`;
}
</script>

{zapSum? zapSum : ''}
6 changes: 2 additions & 4 deletions apps/gui/src/lib/components/partials/MonitorActions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
if(!$monitor) return;
if($monitor?.enabled) {
$monitor.disable();
([...$eventsArray] as IEvent[]).filter( event => event.pubkey === monitor.pubkey).forEach( event => {
([...$eventsArray] as IEvent[]).filter( event => event.pubkey === $monitor.pubkey).forEach( event => {
const key = eventKey(event);
$events.delete(key)
});
Expand All @@ -56,9 +56,7 @@
relays: [ ...($route66?.services?.monitors?.nip66Relays || []), ...$monitor.relays ],
priority: 20
}
const onevents = (events: IEvent[]) => {
publishEventsToMemoryRelay(events)
}
const onevents = publishEventsToMemoryRelay
await $route66?.services?.monitors?.subscribe(options, { onevents })
await resumer();
disabled.set(false);
Expand Down
21 changes: 14 additions & 7 deletions apps/gui/src/lib/components/partials/OperatorRelays.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { derived, writable, type Writable } from 'svelte/store';
import { eventsArray, route66 } from '$lib/stores';
import { eventsArray, route66, type StoreEventType } from '$lib/stores';
import { type IEvent, Monitor, Nip66CheckEvent } from '@nostrwatch/route66/models';
import OperatorRelay from './OperatorRelay.svelte';
Expand All @@ -15,6 +15,13 @@
const deadRelays: Writable<Nip66CheckEvent[]> = writable([])
const deduplicate = (events: Nip66CheckEvent[]): Nip66CheckEvent[] => {
return events.reduce( (acc: Nip66CheckEvent[], event: Nip66CheckEvent) => {
if(acc.find( (e: Nip66CheckEvent) => e.relay === event.relay)) return acc;
return [...acc, event]
}, [])
}
const fetchDeadRelays = async () => {
const dead = await $route66.services.monitors.fetchOperatorRelaysNotOnline(pubkey) || []
dead?.forEach( (event: IEvent) => {
Expand All @@ -28,17 +35,17 @@
}
const onlineRelays = derived(eventsArray, ($eventsArray) => {
return $eventsArray.filter((event: Nip66CheckEvent) => {
return event?.operatorPubkey
&& event.operatorPubkey === pubkey
&& event?.relay !== relayUrl;
})
return deduplicate($eventsArray.filter( (event: StoreEventType) => {
return (event as Nip66CheckEvent)?.operatorPubkey
&& (event as Nip66CheckEvent).operatorPubkey === pubkey
&& (event as Nip66CheckEvent)?.relay !== relayUrl;
}) as Nip66CheckEvent[])
});
const allOperatorRelays = derived([onlineRelays, deadRelays], ([$onlineRelays, $deadRelays]) => {
const all = [...$onlineRelays, ...$deadRelays]
otherRelaysCount = $onlineRelays.length
return all
return deduplicate(all)
});
const mount = async () => {
Expand Down
7 changes: 5 additions & 2 deletions apps/gui/src/lib/services/FeedService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,17 @@ export class FeedService extends Service {
keepAlive: false,
batch: 10
}
const hash = `${note.id}-${user.pubkey}`
// const hash = `${note.id}-${user.pubkey}`
const args: UserFetchArgs = {
filters,
relays,
options,
hash,
priority: 5
}
return this.subscribe(args, callbacks) as Promise<IEvent[]>
}

destroy(){
this.memoryRelay.destroy()
}
}
Loading

0 comments on commit 78d9b8d

Please sign in to comment.