mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-17 21:31:43 +01:00
fix metadata and contracts service pruning
This commit is contained in:
parent
0c25242c18
commit
976734b81a
@ -1,9 +1,9 @@
|
||||
import { useState } from "react";
|
||||
import { Button, Text, useDisclosure } from "@chakra-ui/react";
|
||||
import { useInterval } from "react-use";
|
||||
import { Button, useDisclosure } from "@chakra-ui/react";
|
||||
import { Relay } from "../services/relays";
|
||||
import relayPool from "../services/relays/relay-pool";
|
||||
import { DevModel } from "./dev-modal";
|
||||
import { useInterval } from "react-use";
|
||||
|
||||
export const ConnectedRelays = () => {
|
||||
const [relays, setRelays] = useState<Relay[]>(relayPool.getRelays());
|
||||
|
@ -54,3 +54,8 @@ export const TrashIcon = createIcon({
|
||||
displayName: "delete-bin-line",
|
||||
d: "M17 6h5v2h-2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V8H2V6h5V3a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v3zm1 2H6v12h12V8zm-9 3h2v6H9v-6zm4 0h2v6h-2v-6zM9 4v2h6V4H9z",
|
||||
});
|
||||
|
||||
export const AddIcon = createIcon({
|
||||
displayName: "delete-bin-line",
|
||||
d: "M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z",
|
||||
});
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { useMemo } from "react";
|
||||
import settings from "../services/settings";
|
||||
import userContactsService from "../services/user-contacts";
|
||||
import useSubject from "./use-subject";
|
||||
|
||||
export function useUserContacts(pubkey: string) {
|
||||
const relays = useSubject(settings.relays);
|
||||
const observable = useMemo(() => userContactsService.requestContacts(pubkey, relays), [pubkey, relays]);
|
||||
export function useUserContacts(pubkey: string, relays: string[] = [], alwaysRequest = false) {
|
||||
const observable = useMemo(() => userContactsService.requestContacts(pubkey, relays, alwaysRequest), [pubkey]);
|
||||
const contacts = useSubject(observable) ?? undefined;
|
||||
|
||||
return {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useMemo } from "react";
|
||||
import { useObservable } from "react-use";
|
||||
import userMetadataService from "../services/user-metadata";
|
||||
import useSubject from "./use-subject";
|
||||
|
||||
export function useUserMetadata(pubkey: string, relays?: string[], alwaysRequest = false) {
|
||||
export function useUserMetadata(pubkey: string, relays: string[] = [], alwaysRequest = false) {
|
||||
const observable = useMemo(() => userMetadataService.requestMetadata(pubkey, relays, alwaysRequest), [pubkey]);
|
||||
const metadata = useObservable(observable) ?? undefined;
|
||||
const metadata = useSubject(observable) ?? undefined;
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ function flushRequests() {
|
||||
|
||||
function pruneMemoryCache() {
|
||||
const keys = userSubjects.prune();
|
||||
for (const [key] of keys) {
|
||||
for (const key of keys) {
|
||||
pendingRequests.removePubkey(key);
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ setInterval(() => {
|
||||
pruneMemoryCache();
|
||||
}, 1000);
|
||||
|
||||
const userContactsService = { requestContacts, flushRequests };
|
||||
const userContactsService = { requestContacts, flushRequests, pendingRequests };
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// @ts-ignore
|
||||
|
@ -8,19 +8,20 @@ import { Kind0ParsedContent, NostrEvent } from "../types/nostr-event";
|
||||
import { NostrQuery } from "../types/nostr-query";
|
||||
import { unique } from "../helpers/array";
|
||||
|
||||
type Metadata = Kind0ParsedContent & { created_at: number };
|
||||
|
||||
const subscription = new NostrSubscription([], undefined, "user-metadata");
|
||||
const userMetadataSubjects = new PubkeySubjectCache<NostrEvent>();
|
||||
const userMetadataSubjects = new PubkeySubjectCache<Metadata>();
|
||||
const pendingRequests = new PubkeyRequestList();
|
||||
|
||||
function requestMetadataEvent(
|
||||
pubkey: string,
|
||||
relays: string[],
|
||||
alwaysRequest = false
|
||||
): BehaviorSubject<NostrEvent | null> {
|
||||
function requestMetadata(pubkey: string, relays: string[], alwaysRequest = false) {
|
||||
let subject = userMetadataSubjects.getSubject(pubkey);
|
||||
|
||||
db.get("user-metadata", pubkey).then((cached) => {
|
||||
if (cached) subject.next(cached);
|
||||
if (cached) {
|
||||
const parsed = parseMetadata(cached);
|
||||
if (parsed) subject.next(parsed);
|
||||
}
|
||||
|
||||
if (alwaysRequest || !cached) {
|
||||
pendingRequests.addPubkey(pubkey, relays);
|
||||
@ -30,17 +31,11 @@ function requestMetadataEvent(
|
||||
return subject;
|
||||
}
|
||||
|
||||
function isEvent(e: NostrEvent | null): e is NostrEvent {
|
||||
return !!e;
|
||||
}
|
||||
function parseMetadata(event: NostrEvent): Kind0ParsedContent | undefined {
|
||||
function parseMetadata(event: NostrEvent): Metadata | undefined {
|
||||
try {
|
||||
return JSON.parse(event.content);
|
||||
return { ...JSON.parse(event.content), created_at: event.created_at };
|
||||
} catch (e) {}
|
||||
}
|
||||
function requestMetadata(pubkey: string, relays: string[] = [], alwaysRequest = false) {
|
||||
return requestMetadataEvent(pubkey, relays, alwaysRequest).pipe(filter(isEvent), map(parseMetadata));
|
||||
}
|
||||
|
||||
function flushRequests() {
|
||||
if (!pendingRequests.needsFlush) return;
|
||||
@ -59,7 +54,7 @@ function flushRequests() {
|
||||
|
||||
function pruneMemoryCache() {
|
||||
const keys = userMetadataSubjects.prune();
|
||||
for (const [key] of keys) {
|
||||
for (const key of keys) {
|
||||
pendingRequests.removePubkey(key);
|
||||
}
|
||||
}
|
||||
@ -86,7 +81,7 @@ setInterval(() => {
|
||||
pruneMemoryCache();
|
||||
}, 1000);
|
||||
|
||||
const userMetadataService = { requestMetadata, requestMetadataEvent, flushRequests };
|
||||
const userMetadataService = { requestMetadata, flushRequests, pendingRequests };
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
// @ts-ignore
|
||||
|
@ -1,10 +1,31 @@
|
||||
import { useMemo } from "react";
|
||||
import { Flex, SkeletonText, Text } from "@chakra-ui/react";
|
||||
import settings from "../../services/settings";
|
||||
import moment from "moment";
|
||||
import { Box, Flex, Grid, Heading, IconButton, SkeletonText, Text, Link } from "@chakra-ui/react";
|
||||
import { Link as ReactRouterLink } from "react-router-dom";
|
||||
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import userContactsService from "../../services/user-contacts";
|
||||
import { UserAvatarLink } from "../../components/user-avatar-link";
|
||||
import moment from "moment";
|
||||
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
||||
import { getUserDisplayName } from "../../helpers/user-metadata";
|
||||
import { AddIcon } from "../../components/icons";
|
||||
import { UserAvatar } from "../../components/user-avatar";
|
||||
import { Bech32Prefix, normalizeToBech32 } from "../../helpers/nip-19";
|
||||
|
||||
const UserCard = ({ pubkey }: { pubkey: string }) => {
|
||||
const metadata = useUserMetadata(pubkey);
|
||||
|
||||
return (
|
||||
<Box borderWidth="1px" borderRadius="lg" pl="3" pr="3" pt="2" pb="2" overflow="hidden">
|
||||
<Flex gap="4" alignItems="center">
|
||||
<UserAvatar pubkey={pubkey} />
|
||||
<Link as={ReactRouterLink} to={`/u/${normalizeToBech32(pubkey, Bech32Prefix.Pubkey)}`}>
|
||||
<Heading size="sm">{getUserDisplayName(metadata, pubkey)}</Heading>
|
||||
</Link>
|
||||
<IconButton size="sm" icon={<AddIcon />} aria-label="Follow user" title="Follow" ml="auto" />
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const UserFollowingTab = ({ pubkey }: { pubkey: string }) => {
|
||||
const observable = useMemo(() => userContactsService.requestContacts(pubkey, [], true), [pubkey]);
|
||||
@ -14,12 +35,12 @@ export const UserFollowingTab = ({ pubkey }: { pubkey: string }) => {
|
||||
<Flex gap="2" direction="column">
|
||||
{contacts ? (
|
||||
<>
|
||||
<Flex flexWrap="wrap" gap="2">
|
||||
<Grid templateColumns={{ base: "1fr", xl: "repeat(2, 1fr)", "2xl": "repeat(3, 1fr)" }} gap="2">
|
||||
{contacts.contacts.map((contact, i) => (
|
||||
<UserAvatarLink key={contact.pubkey + i} pubkey={contact.pubkey} />
|
||||
<UserCard key={contact.pubkey} pubkey={contact.pubkey} />
|
||||
))}
|
||||
</Flex>
|
||||
<Text>{`Updated ${moment(contacts?.created_at).fromNow()}`}</Text>
|
||||
</Grid>
|
||||
<Text>{`Updated ${moment(contacts?.created_at * 1000).fromNow()}`}</Text>
|
||||
</>
|
||||
) : (
|
||||
<SkeletonText />
|
||||
|
Loading…
x
Reference in New Issue
Block a user