fix performance issue

This commit is contained in:
hzrd149 2024-02-03 11:02:32 +00:00
parent 6ccd9ea736
commit 4258a10d36
8 changed files with 79 additions and 47 deletions

View File

@ -56,7 +56,7 @@
"match-sorter": "^6.3.1",
"nanoid": "^5.0.4",
"ngeohash": "^0.6.3",
"nostr-idb": "^2.1.0",
"nostr-idb": "^2.1.1",
"nostr-tools": "^2.1.3",
"react": "^18.2.0",
"react-chartjs-2": "^5.2.0",

View File

@ -114,15 +114,20 @@ export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButt
const isFollowing = isPubkeyInList(contacts, pubkey);
const isDisabled = account?.readonly ?? true;
const [loading, setLoading] = useState(false);
const handleFollow = useAsyncErrorHandler(async () => {
setLoading(true);
const draft = listAddPerson(contacts || createEmptyContactList(), pubkey);
const signed = await requestSignature(draft);
await publish("Follow", signed);
setLoading(false);
}, [contacts, requestSignature]);
const handleUnfollow = useAsyncErrorHandler(async () => {
setLoading(true);
const draft = listRemovePerson(contacts || createEmptyContactList(), pubkey);
const signed = await requestSignature(draft);
await publish("Unfollow", signed);
setLoading(false);
}, [contacts, requestSignature]);
if (showLists) {
@ -139,11 +144,11 @@ export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButt
</MenuButton>
<MenuList>
{isFollowing ? (
<MenuItem onClick={handleUnfollow} icon={<UnfollowIcon />} isDisabled={isDisabled}>
<MenuItem onClick={handleUnfollow} icon={<UnfollowIcon />} isDisabled={isDisabled || loading}>
Unfollow
</MenuItem>
) : (
<MenuItem onClick={handleFollow} icon={<FollowIcon />} isDisabled={isDisabled}>
<MenuItem onClick={handleFollow} icon={<FollowIcon />} isDisabled={isDisabled || loading}>
Follow
</MenuItem>
)}
@ -168,13 +173,27 @@ export function UserFollowButton({ pubkey, showLists, ...props }: UserFollowButt
);
} else if (isFollowing) {
return (
<Button onClick={handleUnfollow} colorScheme="primary" icon={<UnfollowIcon />} isDisabled={isDisabled} {...props}>
<Button
onClick={handleUnfollow}
colorScheme="primary"
icon={<UnfollowIcon />}
isDisabled={isDisabled}
isLoading={loading}
{...props}
>
Unfollow
</Button>
);
} else {
return (
<Button onClick={handleFollow} colorScheme="primary" icon={<FollowIcon />} isDisabled={isDisabled} {...props}>
<Button
onClick={handleFollow}
colorScheme="primary"
icon={<FollowIcon />}
isDisabled={isDisabled}
isLoading={loading}
{...props}
>
Follow
</Button>
);

View File

@ -1,4 +1,5 @@
import { Filter, kinds, nip25 } from "nostr-tools";
import _throttle from "lodash.throttle";
import NostrRequest from "../classes/nostr-request";
import Subject from "../classes/subject";
@ -22,6 +23,7 @@ class EventReactionsService {
this.pending.get(eventId).add(relay);
}
}
this.throttleBatchRequest();
return subject;
}
@ -41,9 +43,20 @@ class EventReactionsService {
if (cache) localRelay.publish(event);
}
throttleBatchRequest = _throttle(this.batchRequests, 2000);
batchRequests() {
if (this.pending.size === 0) return;
// load events from cache
const uids = Array.from(this.pending.keys());
const ids = uids.filter((id) => !id.includes(":"));
const cords = uids.filter((id) => id.includes(":"));
const filters: Filter[] = [];
if (ids.length > 0) filters.push({ "#e": ids, kinds: [kinds.Reaction] });
if (cords.length > 0) filters.push({ "#a": cords, kinds: [kinds.Reaction] });
if (filters.length > 0)
relayRequest(localRelay, filters).then((events) => events.forEach((e) => this.handleEvent(e, false)));
const idsFromRelays: Record<relay, eventId[]> = {};
for (const [id, relays] of this.pending) {
for (const relay of relays) {
@ -53,14 +66,17 @@ class EventReactionsService {
}
for (const [relay, ids] of Object.entries(idsFromRelays)) {
const filter: Filter = { "#e": ids, kinds: [kinds.Reaction] };
const eventIds = ids.filter((id) => !id.includes(":"));
const coordinates = ids.filter((id) => id.includes(":"));
const filters: Filter[] = [];
if (eventIds.length > 0) filters.push({ "#e": eventIds, kinds: [kinds.Reaction] });
if (coordinates.length > 0) filters.push({ "#a": coordinates, kinds: [kinds.Reaction] });
// load from local relay
relayRequest(localRelay, [filter]).then((events) => events.forEach((e) => this.handleEvent(e, true)));
const request = new NostrRequest([relay]);
request.onEvent.subscribe(this.handleEvent, this);
request.start(filter);
if (filters.length > 0) {
const request = new NostrRequest([relay]);
request.onEvent.subscribe(this.handleEvent, this);
request.start(filters);
}
}
this.pending.clear();
}
@ -68,8 +84,9 @@ class EventReactionsService {
const eventReactionsService = new EventReactionsService();
setInterval(() => {
eventReactionsService.batchRequests();
}, 1000 * 2);
if (import.meta.env.DEV) {
//@ts-expect-error
window.eventReactionsService = eventReactionsService;
}
export default eventReactionsService;

View File

@ -1,10 +1,10 @@
import { Filter, kinds } from "nostr-tools";
import _throttle from "lodash.throttle";
import NostrRequest from "../classes/nostr-request";
import Subject from "../classes/subject";
import SuperMap from "../classes/super-map";
import { NostrEvent, isATag, isETag } from "../types/nostr-event";
import { isHexKey } from "../helpers/nip19";
import { relayRequest } from "../helpers/relay";
import { localRelay } from "./local-relay";
@ -23,6 +23,7 @@ class EventZapsService {
this.pending.get(eventUID).add(relay);
}
}
this.throttleBatchRequest();
return subject;
}
@ -42,9 +43,20 @@ class EventZapsService {
if (cache) localRelay.publish(event);
}
throttleBatchRequest = _throttle(this.batchRequests, 2000);
batchRequests() {
if (this.pending.size === 0) return;
// load events from cache
const uids = Array.from(this.pending.keys());
const ids = uids.filter((id) => !id.includes(":"));
const cords = uids.filter((id) => id.includes(":"));
const filters: Filter[] = [];
if (ids.length > 0) filters.push({ "#e": ids, kinds: [kinds.Zap] });
if (cords.length > 0) filters.push({ "#a": cords, kinds: [kinds.Zap] });
if (filters.length > 0)
relayRequest(localRelay, filters).then((events) => events.forEach((e) => this.handleEvent(e, false)));
const idsFromRelays: Record<relay, eventUID[]> = {};
for (const [id, relays] of this.pending) {
for (const relay of relays) {
@ -54,19 +66,17 @@ class EventZapsService {
}
for (const [relay, ids] of Object.entries(idsFromRelays)) {
const request = new NostrRequest([relay]);
request.onEvent.subscribe(this.handleEvent, this);
const eventIds = ids.filter(isHexKey);
const eventIds = ids.filter((id) => !id.includes(":"));
const coordinates = ids.filter((id) => id.includes(":"));
const filter: Filter[] = [];
if (eventIds.length > 0) filter.push({ "#e": eventIds, kinds: [kinds.Zap] });
if (coordinates.length > 0) filter.push({ "#a": coordinates, kinds: [kinds.Zap] });
const queries: Filter[] = [];
if (eventIds.length > 0) queries.push({ "#e": eventIds, kinds: [kinds.Zap] });
if (coordinates.length > 0) queries.push({ "#a": coordinates, kinds: [kinds.Zap] });
// load from local relay
relayRequest(localRelay, queries).then((events) => events.forEach((e) => this.handleEvent(e, false)));
request.start(queries);
if (filter.length > 0) {
const request = new NostrRequest([relay]);
request.onEvent.subscribe(this.handleEvent, this);
request.start(filter);
}
}
this.pending.clear();
}
@ -79,8 +89,4 @@ if (import.meta.env.DEV) {
window.eventZapsService = eventZapsService;
}
setInterval(() => {
eventZapsService.batchRequests();
}, 1000 * 2);
export default eventZapsService;

View File

@ -65,21 +65,11 @@ async function connectRelay() {
export const localRelay = await connectRelay();
function pruneLocalDatabase() {
if (localRelay instanceof CacheRelay) {
pruneLastUsed(localRelay.db, 20_000);
}
}
// keep the relay connection alive
setInterval(() => {
if (!localRelay.connected) localRelay.connect().then(() => log("Reconnected"));
}, 1000 * 5);
setInterval(() => {
pruneLocalDatabase();
}, 1000 * 60);
if (import.meta.env.DEV) {
//@ts-ignore
window.localDatabase = localDatabase;

View File

@ -201,7 +201,7 @@ class ReplaceableEventLoaderService {
loading.set(cord, p);
}
const filters = Array.from(Object.values(kindFilters));
const filters = Object.values(kindFilters);
for (const [cord] of loading) this.readFromCachePromises.delete(cord);

View File

@ -164,7 +164,7 @@ function CommunitiesHomePage() {
</Flex>
</Flex>
) : (
<Center aspectRatio={3 / 4} flexDirection="column" gap="4">
<Center py="20" flexDirection="column" gap="4">
<Heading size="md">No communities :(</Heading>
<Text>
go find a cool one to join.{" "}

View File

@ -5244,10 +5244,10 @@ normalize-package-data@^2.5.0:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
nostr-idb@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/nostr-idb/-/nostr-idb-2.1.0.tgz#81ba6381086e7e10a2e916a026101caa8d77218e"
integrity sha512-hAdLn3b3S5JJ77CuMo7tD25BsKnJ1XXuuGBLad8pjdhVEG9RIJhLvUYmgfx0Ylwj4Xuar57csaepSDJzKj/sYw==
nostr-idb@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/nostr-idb/-/nostr-idb-2.1.1.tgz#5aaf4ebb793266c87ab7c9d72ed4be3bcae79fc2"
integrity sha512-vUdRPOJkWtEovsL0CqnniiuwIqastHby7nf2NKyhvO5MV5Dyl9CBxs9nIcAHB5GJHDV7nt+t6SF193Odorp/1g==
dependencies:
debug "^4.3.4"
idb "^8.0.0"