mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-29 13:03:33 +02:00
ignore old user metadata events
This commit is contained in:
@@ -22,6 +22,8 @@ import {
|
|||||||
import { useInterval } from "react-use";
|
import { useInterval } from "react-use";
|
||||||
import { Relay } from "../services/relays";
|
import { Relay } from "../services/relays";
|
||||||
import relayPool from "../services/relays/relay-pool";
|
import relayPool from "../services/relays/relay-pool";
|
||||||
|
import useSubject from "../hooks/use-subject";
|
||||||
|
import settings from "../services/settings";
|
||||||
|
|
||||||
const getRelayStatusText = (relay: Relay) => {
|
const getRelayStatusText = (relay: Relay) => {
|
||||||
if (relay.connecting) return "Connecting...";
|
if (relay.connecting) return "Connecting...";
|
||||||
@@ -31,6 +33,7 @@ const getRelayStatusText = (relay: Relay) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ConnectedRelays = () => {
|
export const ConnectedRelays = () => {
|
||||||
|
const relayUrls = useSubject(settings.relays);
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const [relays, setRelays] = useState<Relay[]>([]);
|
const [relays, setRelays] = useState<Relay[]>([]);
|
||||||
|
|
||||||
@@ -38,6 +41,13 @@ export const ConnectedRelays = () => {
|
|||||||
setRelays(relayPool.getRelays());
|
setRelays(relayPool.getRelays());
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
for (const url of relayUrls) {
|
||||||
|
// ask the pool to reconnect if disconnected
|
||||||
|
relayPool.requestRelay(url);
|
||||||
|
}
|
||||||
|
}, 1000 * 30);
|
||||||
|
|
||||||
const connected = relays.filter((relay) => relay.okay);
|
const connected = relays.filter((relay) => relay.okay);
|
||||||
const disconnected = relays.filter((relay) => !relay.okay);
|
const disconnected = relays.filter((relay) => !relay.okay);
|
||||||
|
|
||||||
|
@@ -27,7 +27,6 @@ export type PostProps = {
|
|||||||
};
|
};
|
||||||
export const Post = React.memo(({ event }: PostProps) => {
|
export const Post = React.memo(({ event }: PostProps) => {
|
||||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||||
const corsProxy = useSubject(settings.corsProxy);
|
|
||||||
const userMetadata = useUserMetadata(event.pubkey);
|
const userMetadata = useUserMetadata(event.pubkey);
|
||||||
|
|
||||||
const isLong = event.content.length > 800;
|
const isLong = event.content.length > 800;
|
||||||
@@ -37,10 +36,7 @@ export const Post = React.memo(({ event }: PostProps) => {
|
|||||||
<CardHeader>
|
<CardHeader>
|
||||||
<HStack spacing="4">
|
<HStack spacing="4">
|
||||||
<Flex flex="1" gap="4" alignItems="center" flexWrap="wrap">
|
<Flex flex="1" gap="4" alignItems="center" flexWrap="wrap">
|
||||||
<Avatar
|
<Avatar src={userMetadata?.picture} />
|
||||||
name={userMetadata?.display_name ?? userMetadata?.name}
|
|
||||||
src={userMetadata?.picture}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size="sm">
|
<Heading size="sm">
|
||||||
|
@@ -72,13 +72,4 @@ if (import.meta.env.DEV) {
|
|||||||
window.relayPool = relayPool;
|
window.relayPool = relayPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this somewhere where it makes sense
|
|
||||||
setTimeout(async () => {
|
|
||||||
const urls = settings.relays.getValue();
|
|
||||||
|
|
||||||
for (const url of urls) {
|
|
||||||
relayPool.requestRelay(url);
|
|
||||||
}
|
|
||||||
}, 1000 * 10);
|
|
||||||
|
|
||||||
export default relayPool;
|
export default relayPool;
|
||||||
|
@@ -4,7 +4,7 @@ import db from "./db";
|
|||||||
import settings from "./settings";
|
import settings from "./settings";
|
||||||
import { Subscription } from "./subscriptions";
|
import { Subscription } from "./subscriptions";
|
||||||
|
|
||||||
class UserMetadata {
|
class UserMetadataService {
|
||||||
requests = new Set<string>();
|
requests = new Set<string>();
|
||||||
subjects = new Map<string, BehaviorSubject<Kind0ParsedContent | null>>();
|
subjects = new Map<string, BehaviorSubject<Kind0ParsedContent | null>>();
|
||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
@@ -12,11 +12,17 @@ class UserMetadata {
|
|||||||
constructor(relayUrls: string[] = []) {
|
constructor(relayUrls: string[] = []) {
|
||||||
this.subscription = new Subscription(relayUrls, undefined, "user-metadata");
|
this.subscription = new Subscription(relayUrls, undefined, "user-metadata");
|
||||||
|
|
||||||
this.subscription.onEvent.subscribe((event) => {
|
this.subscription.onEvent.subscribe(async (event) => {
|
||||||
try {
|
try {
|
||||||
|
const current = await db.get("user-metadata", event.pubkey);
|
||||||
|
if (current && current.created_at > event.created_at) {
|
||||||
|
// ignore this event because its older
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
db.put("user-metadata", event);
|
||||||
|
|
||||||
const metadata = JSON.parse(event.content);
|
const metadata = JSON.parse(event.content);
|
||||||
this.getUserSubject(event.pubkey).next(metadata);
|
this.getUserSubject(event.pubkey).next(metadata);
|
||||||
db.put("user-metadata", event);
|
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -89,7 +95,7 @@ class UserMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const userMetadata = new UserMetadata(settings.relays.getValue());
|
const userMetadata = new UserMetadataService(settings.relays.getValue());
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@@ -1,25 +1,30 @@
|
|||||||
import React from "react";
|
import { Avatar, HStack } from "@chakra-ui/react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useUserMetadata } from "../hooks/use-user-metadata";
|
||||||
|
|
||||||
|
const UserAvatar = ({ pubkey }: { pubkey: string }) => {
|
||||||
|
const metadata = useUserMetadata(pubkey);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to={`/user/${pubkey}`}>
|
||||||
|
<Avatar src={metadata?.picture} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const HomeView = () => {
|
export const HomeView = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>
|
<HStack spacing=".5rem">
|
||||||
There are many benefits to a joint design and development system. Not
|
<UserAvatar pubkey="32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245" />
|
||||||
only does it bring benefits to the design team, but it also brings
|
<UserAvatar pubkey="6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964" />
|
||||||
benefits to engineering teams. It makes sure that our experiences have a
|
<UserAvatar pubkey="00000000827ffaa94bfea288c3dfce4422c794fbb96625b6b31e9049f729d700" />
|
||||||
consistent look and feel, not just in our design specs, but in
|
<UserAvatar pubkey="82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2" />
|
||||||
production.
|
<UserAvatar pubkey="85080d3bad70ccdcd7f74c29a44f55bb85cbcd3dd0cbb957da1d215bdb931204" />
|
||||||
</span>
|
<UserAvatar pubkey="e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411" />
|
||||||
<Link to="/user/32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245">
|
<UserAvatar pubkey="8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168" />
|
||||||
jb55
|
<UserAvatar pubkey="266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5" />
|
||||||
</Link>
|
</HStack>
|
||||||
<Link to="/user/266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5">
|
|
||||||
self
|
|
||||||
</Link>
|
|
||||||
<Link to="/user/6b0d4c8d9dc59e110d380b0429a02891f1341a0fa2ba1b1cf83a3db4d47e3964">
|
|
||||||
gigi
|
|
||||||
</Link>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,15 +1,22 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
Heading,
|
Heading,
|
||||||
|
HStack,
|
||||||
|
SkeletonText,
|
||||||
Tab,
|
Tab,
|
||||||
TabList,
|
TabList,
|
||||||
TabPanel,
|
TabPanel,
|
||||||
TabPanels,
|
TabPanels,
|
||||||
Tabs,
|
Tabs,
|
||||||
|
Text,
|
||||||
|
VStack,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { UserPostsTab } from "./posts";
|
import { UserPostsTab } from "./posts";
|
||||||
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
||||||
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
export const UserView = () => {
|
export const UserView = () => {
|
||||||
const { pubkey } = useParams();
|
const { pubkey } = useParams();
|
||||||
@@ -21,8 +28,20 @@ export const UserView = () => {
|
|||||||
const metadata = useUserMetadata(pubkey);
|
const metadata = useUserMetadata(pubkey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<VStack alignItems="stretch" spacing={4}>
|
||||||
|
{" "}
|
||||||
|
<HStack spacing={4}>
|
||||||
|
<Avatar src={metadata?.picture} />
|
||||||
|
<Box>
|
||||||
<Heading>{metadata?.name ?? pubkey}</Heading>
|
<Heading>{metadata?.name ?? pubkey}</Heading>
|
||||||
|
<Text>{metadata?.display_name}</Text>
|
||||||
|
</Box>
|
||||||
|
</HStack>
|
||||||
|
{metadata?.about ? (
|
||||||
|
<ReactMarkdown>{metadata.about}</ReactMarkdown>
|
||||||
|
) : (
|
||||||
|
<SkeletonText />
|
||||||
|
)}
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabList>
|
<TabList>
|
||||||
<Tab>Posts</Tab>
|
<Tab>Posts</Tab>
|
||||||
@@ -42,6 +61,6 @@ export const UserView = () => {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabPanels>
|
</TabPanels>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</>
|
</VStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user