fixed memory leak and high cpu pike

This commit is contained in:
Ren Amamiya
2023-03-27 20:28:26 +07:00
parent eb440eda1b
commit 38033fcd57
24 changed files with 168 additions and 361 deletions

View File

@@ -2,39 +2,44 @@ import { RelayContext } from '@components/relaysProvider';
import { relaysAtom } from '@stores/relays';
import { dateToUnix } from '@utils/getDate';
import { createFollows } from '@utils/storage';
import { tagsToArray } from '@utils/transform';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { AvatarIcon, ExitIcon, GearIcon } from '@radix-ui/react-icons';
import destr from 'destr';
import { useAtomValue } from 'jotai';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { memo, useContext, useEffect } from 'react';
import { memo, useContext, useEffect, useRef } from 'react';
export const ActiveAccount = memo(function ActiveAccount({ user }: { user: any }) {
const pool: any = useContext(RelayContext);
const relays = useAtomValue(relaysAtom);
const router = useRouter();
const userData = JSON.parse(user.metadata);
const userData = destr(user.metadata);
const now = useRef(new Date());
const openProfile = () => {
router.push(`/users/${user.pubkey}`);
router.push(`/users/${user.id}`);
};
useEffect(() => {
pool.subscribe(
const unsubscribe = pool.subscribe(
[
{
kinds: [3],
authors: [user.pubkey],
authors: [user.id],
since: dateToUnix(now.current),
},
],
relays,
(event: any) => {
if (event.tags.length > 0) {
createFollows(tagsToArray(event.tags), user.pubkey, 0);
createFollows(tagsToArray(event.tags), user.id, 0);
}
},
undefined,
@@ -43,7 +48,11 @@ export const ActiveAccount = memo(function ActiveAccount({ user }: { user: any }
unsubscribeOnEose: true,
}
);
}, [pool, relays, user.pubkey]);
return () => {
unsubscribe;
};
}, [pool, relays, user.id]);
return (
<DropdownMenu.Root>

View File

@@ -1,8 +1,9 @@
import destr from 'destr';
import Image from 'next/image';
import { memo } from 'react';
export const InactiveAccount = memo(function InactiveAccount({ user }: { user: any }) {
const userData = JSON.parse(user.metadata);
const userData = destr(user.metadata);
const setCurrentUser = () => {
console.log('clicked');

View File

@@ -1,24 +1,9 @@
import { MessageList } from '@components/columns/navigator/messages/list';
import { activeAccountAtom } from '@stores/account';
import { getAllFollowsByID } from '@utils/storage';
import * as Collapsible from '@radix-ui/react-collapsible';
import { TriangleUpIcon } from '@radix-ui/react-icons';
import { useAtom } from 'jotai';
import { useEffect, useState } from 'react';
import { useState } from 'react';
export default function Messages() {
const [open, setOpen] = useState(true);
const [follows, setFollows] = useState([]);
const [activeAccount] = useAtom(activeAccountAtom);
useEffect(() => {
getAllFollowsByID(activeAccount.id)
.then((res: any) => setFollows(res))
.catch(console.error);
}, [activeAccount.id]);
return (
<Collapsible.Root open={open} onOpenChange={setOpen}>
@@ -35,9 +20,7 @@ export default function Messages() {
Messages
</h3>
</Collapsible.Trigger>
<Collapsible.Content className="flex flex-col">
<MessageList data={follows} />
</Collapsible.Content>
<Collapsible.Content className="flex flex-col"></Collapsible.Content>
</div>
</Collapsible.Root>
);

View File

@@ -8,7 +8,6 @@ import { relaysAtom } from '@stores/relays';
import { dateToUnix } from '@utils/getDate';
import { ImageIcon, ResetIcon } from '@radix-ui/react-icons';
import { sendNotification } from '@tauri-apps/api/notification';
import { useAtom, useAtomValue } from 'jotai';
import { useResetAtom } from 'jotai/utils';
import { getEventHash, signEvent } from 'nostr-tools';
@@ -41,7 +40,7 @@ export default function FormBase() {
// reset form
resetValue();
// send notification
sendNotification('Note has been published successfully');
// sendNotification('Note has been published successfully');
};
return (

View File

@@ -6,7 +6,6 @@ import { relaysAtom } from '@stores/relays';
import { dateToUnix } from '@utils/getDate';
import { sendNotification } from '@tauri-apps/api/notification';
import destr from 'destr';
import { useAtom, useAtomValue } from 'jotai';
import { getEventHash, signEvent } from 'nostr-tools';
@@ -35,7 +34,7 @@ export default function FormComment({ eventID }: { eventID: any }) {
// publish note
pool.publish(event, relays);
// send notification
sendNotification('Comment has been published successfully');
// sendNotification('Comment has been published successfully');
};
return (

View File

@@ -11,6 +11,7 @@ import CommentIcon from '@assets/icons/comment';
import * as Dialog from '@radix-ui/react-dialog';
import { SizeIcon } from '@radix-ui/react-icons';
import destr from 'destr';
import { useAtom, useAtomValue } from 'jotai';
import { useRouter } from 'next/router';
import { getEventHash, signEvent } from 'nostr-tools';
@@ -38,7 +39,7 @@ export const NoteComment = memo(function NoteComment({
const [open, setOpen] = useState(false);
const [value, setValue] = useState('');
const profile = JSON.parse(activeAccount.metadata);
const profile = destr(activeAccount.metadata);
const openThread = () => {
router.push(`/newsfeed/${eventID}`);

View File

@@ -4,6 +4,7 @@ import { RelayContext } from '@components/relaysProvider';
import { relaysAtom } from '@stores/relays';
import { dateToUnix } from '@utils/getDate';
import { createCacheCommentNote } from '@utils/storage';
import { useAtomValue } from 'jotai';
@@ -17,7 +18,7 @@ export default function NoteMetadata({
}: {
eventID: string;
eventPubkey: string;
eventTime: string;
eventTime: any;
eventContent: any;
}) {
const pool: any = useContext(RelayContext);
@@ -26,13 +27,15 @@ export default function NoteMetadata({
const [likes, setLikes] = useState(0);
const [comments, setComments] = useState(0);
/*
useEffect(() => {
const unsubscribe = pool.subscribe(
[
{
'#e': [eventID],
since: 0,
since: parseInt(eventTime),
kinds: [1, 7],
limit: 50,
},
],
relays,
@@ -53,7 +56,7 @@ export default function NoteMetadata({
break;
}
},
undefined,
1000,
undefined,
{
unsubscribeOnEose: true,
@@ -61,9 +64,10 @@ export default function NoteMetadata({
);
return () => {
unsubscribe();
unsubscribe;
};
}, [eventID, pool, relays]);
}, [eventID, eventTime, pool, relays]);
*/
return (
<div className="relative z-10 -ml-1 flex items-center gap-8">

View File

@@ -12,7 +12,7 @@ import { createCacheNote, getNoteByID } from '@utils/storage';
import destr from 'destr';
import { useAtomValue } from 'jotai';
import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import ReactPlayer from 'react-player';
import reactStringReplace from 'react-string-replace';
@@ -21,9 +21,10 @@ export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
const relays = useAtomValue(relaysAtom);
const [event, setEvent] = useState(null);
const unsubscribe = useRef(null);
const fetchEvent = useCallback(() => {
pool.subscribe(
unsubscribe.current = pool.subscribe(
[
{
ids: [id],
@@ -53,6 +54,10 @@ export const NoteParent = memo(function NoteParent({ id }: { id: string }) {
fetchEvent();
}
});
return () => {
unsubscribe.current;
};
}, [fetchEvent, id]);
const content = useMemo(() => {

View File

@@ -8,7 +8,7 @@ import { createCacheNote, getNoteByID } from '@utils/storage';
import destr from 'destr';
import { useAtomValue } from 'jotai';
import { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import reactStringReplace from 'react-string-replace';
export const NoteRepost = memo(function NoteRepost({ id }: { id: string }) {
@@ -16,9 +16,10 @@ export const NoteRepost = memo(function NoteRepost({ id }: { id: string }) {
const relays = useAtomValue(relaysAtom);
const [event, setEvent] = useState(null);
const unsubscribe = useRef(null);
const fetchEvent = useCallback(() => {
pool.subscribe(
unsubscribe.current = pool.subscribe(
[
{
ids: [id],
@@ -48,6 +49,10 @@ export const NoteRepost = memo(function NoteRepost({ id }: { id: string }) {
fetchEvent();
}
});
return () => {
unsubscribe.current;
};
}, [fetchEvent, id]);
const content = useMemo(() => {
@@ -100,22 +105,6 @@ export const NoteRepost = memo(function NoteRepost({ id }: { id: string }) {
</div>
);
} else {
return (
<div className="relative z-10 flex h-min animate-pulse select-text flex-col pb-5">
<div className="flex items-start gap-2">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-md bg-zinc-700" />
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex w-full items-center justify-between">
<div className="flex items-center gap-2 text-sm">
<div className="h-4 w-16 rounded bg-zinc-700" />
<span className="text-zinc-500">·</span>
<div className="h-4 w-12 rounded bg-zinc-700" />
</div>
<div className="h-3 w-3 rounded-full bg-zinc-700" />
</div>
</div>
</div>
</div>
);
return <div className="mt-2 h-6 animate-pulse select-text flex-col rounded bg-zinc-700 pb-5"></div>;
}
});

View File

@@ -8,6 +8,7 @@ import { fetch } from '@tauri-apps/api/http';
import Avatar from 'boring-avatars';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import destr from 'destr';
import { useRouter } from 'next/router';
import { memo, useCallback, useEffect, useState } from 'react';
@@ -33,11 +34,11 @@ export const UserExtend = memo(function UserExtend({ pubkey, time }: { pubkey: s
useEffect(() => {
getCacheProfile(pubkey).then((res) => {
if (res) {
setProfile(JSON.parse(res.metadata));
setProfile(destr(res.metadata));
} else {
fetchProfile(pubkey)
.then((res: any) => {
setProfile(JSON.parse(res.content));
setProfile(destr(res.content));
createCacheProfile(pubkey, res.content);
})
.catch(console.error);

View File

@@ -8,6 +8,7 @@ import { fetch } from '@tauri-apps/api/http';
import Avatar from 'boring-avatars';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import destr from 'destr';
import { memo, useCallback, useEffect, useState } from 'react';
dayjs.extend(relativeTime);
@@ -26,11 +27,11 @@ export const UserLarge = memo(function UserLarge({ pubkey, time }: { pubkey: str
useEffect(() => {
getCacheProfile(pubkey).then((res) => {
if (res) {
setProfile(JSON.parse(res.metadata));
setProfile(destr(res.metadata));
} else {
fetchProfile(pubkey)
.then((res: any) => {
setProfile(JSON.parse(res.content));
setProfile(destr(res.content));
createCacheProfile(pubkey, res.content);
})
.catch(console.error);

View File

@@ -2,6 +2,7 @@ import { createCacheProfile, getCacheProfile } from '@utils/storage';
import { truncate } from '@utils/truncate';
import { fetch } from '@tauri-apps/api/http';
import destr from 'destr';
import { memo, useCallback, useEffect, useState } from 'react';
export const UserMention = memo(function UserMention({ pubkey }: { pubkey: string }) {
@@ -18,11 +19,11 @@ export const UserMention = memo(function UserMention({ pubkey }: { pubkey: strin
useEffect(() => {
getCacheProfile(pubkey).then((res) => {
if (res) {
setProfile(JSON.parse(res.metadata));
setProfile(destr(res.metadata));
} else {
fetchProfile(pubkey)
.then((res: any) => {
setProfile(JSON.parse(res.content));
setProfile(destr(res.content));
createCacheProfile(pubkey, res.content);
})
.catch(console.error);

View File

@@ -5,6 +5,7 @@ import { truncate } from '@utils/truncate';
import { fetch } from '@tauri-apps/api/http';
import Avatar from 'boring-avatars';
import destr from 'destr';
import { memo, useCallback, useEffect, useState } from 'react';
export const UserMini = memo(function UserMini({ pubkey }: { pubkey: string }) {
@@ -21,11 +22,11 @@ export const UserMini = memo(function UserMini({ pubkey }: { pubkey: string }) {
useEffect(() => {
getCacheProfile(pubkey).then((res) => {
if (res) {
setProfile(JSON.parse(res.metadata));
setProfile(destr(res.metadata));
} else {
fetchProfile(pubkey)
.then((res: any) => {
setProfile(JSON.parse(res.content));
setProfile(destr(res.content));
createCacheProfile(pubkey, res.content);
})
.catch(console.error);

View File

@@ -13,7 +13,17 @@ import LumeSymbol from '@assets/icons/Lume';
import { useAtom, useAtomValue } from 'jotai';
import { useRouter } from 'next/router';
import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useContext, useEffect, useRef } from 'react';
import {
JSXElementConstructor,
ReactElement,
ReactFragment,
ReactPortal,
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
export default function Page() {
const router = useRouter();
@@ -22,72 +32,60 @@ export default function Page() {
const relays = useAtomValue(relaysAtom);
const [activeAccount] = useAtom(activeAccountAtom);
const [done, setDone] = useState(false);
const now = useRef(new Date());
const timer = useRef(null);
const unsubscribe = useRef(null);
const fetchData = useCallback(
(since) => {
getAllFollowsByID(activeAccount.id).then((follows) => {
unsubscribe.current = pool.subscribe(
[
{
kinds: [1],
authors: pubkeyArray(follows),
since: dateToUnix(since),
until: dateToUnix(now.current),
},
],
relays,
(event) => {
// insert event to local database
createCacheNote(event);
},
undefined,
() => {
setDone(true);
},
{
unsubscribeOnEose: true,
}
);
});
},
[activeAccount.id, pool, relays]
);
useEffect(() => {
countTotalNotes().then((count) => {
if (count.total === 0) {
getAllFollowsByID(activeAccount.id).then((follows) => {
pool.subscribe(
[
{
kinds: [1],
authors: pubkeyArray(follows),
since: dateToUnix(hoursAgo(24, now.current)),
until: dateToUnix(now.current),
},
],
relays,
(event) => {
// insert event to local database
createCacheNote(event);
},
undefined,
() => {
timer.current = setTimeout(() => router.push('/newsfeed/following'), 3000);
},
{
unsubscribeOnEose: true,
}
);
});
} else {
getLastLoginTime().then((time) => {
const parseDate = new Date(time);
getAllFollowsByID(activeAccount.id).then((follows) => {
pool.subscribe(
[
{
kinds: [1],
authors: pubkeyArray(follows),
since: dateToUnix(parseDate),
until: dateToUnix(now.current),
},
],
relays,
(event) => {
// insert event to local database
createCacheNote(event);
},
undefined,
() => {
timer.current = setTimeout(() => router.push('/newsfeed/following'), 3000);
},
{
unsubscribeOnEose: true,
}
);
if (!done) {
countTotalNotes().then((count) => {
if (count.total === 0) {
fetchData(hoursAgo(24, now.current));
} else {
getLastLoginTime().then((time) => {
const parseDate = new Date(time.setting_value);
fetchData(parseDate);
});
});
}
});
}
});
} else {
router.push('/newsfeed/following');
}
return () => {
clearTimeout(timer.current);
unsubscribe.current;
};
}, [activeAccount.id, pool, relays, router]);
}, [activeAccount.id, done, pool, relays, router, fetchData]);
return (
<div className="relative h-full overflow-hidden">

View File

@@ -17,8 +17,7 @@ export default function Page() {
const virtualizer = useVirtualizer({
count: data.length,
overscan: 5,
estimateSize: () => 600,
estimateSize: () => 500,
getScrollElement: () => parentRef.current,
getItemKey: (index) => data[index].id,
});

View File

@@ -34,7 +34,6 @@ export default function Page() {
const relays = useAtomValue(relaysAtom);
const [profile, setProfile] = useState(null);
const [done, setDone] = useState(false);
const timer = useRef(null);
useEffect(() => {
const unsubscribe = pool.subscribe(
@@ -65,7 +64,7 @@ export default function Page() {
},
undefined,
() => {
timer.current = setTimeout(() => setDone(true), 3000);
setDone(true);
},
{
unsubscribeOnEose: true,
@@ -73,8 +72,7 @@ export default function Page() {
);
return () => {
unsubscribe();
clearTimeout(timer.current);
unsubscribe;
};
}, [pool, privkey, pubkey, relays]);

View File

@@ -91,7 +91,7 @@ export async function getCacheProfile(id) {
// get all notes
export async function getAllNotes() {
const db = await connect();
return await db.select(`SELECT * FROM cache_notes GROUP BY parent_id ORDER BY created_at DESC LIMIT 1000`);
return await db.select(`SELECT * FROM cache_notes GROUP BY parent_id ORDER BY created_at DESC LIMIT 500`);
}
// get note by id
@@ -122,7 +122,7 @@ export async function createCacheNote(data) {
export async function getAllCommentNotes(eid) {
const db = await connect();
return await db.select(
`SELECT * FROM cache_notes WHERE parent_comment_id = "${eid}" ORDER BY created_at DESC LIMIT 1000`
`SELECT * FROM cache_notes WHERE parent_comment_id = "${eid}" ORDER BY created_at DESC LIMIT 500`
);
}