Skip to content

Commit

Permalink
add local relay cache option
Browse files Browse the repository at this point in the history
cleanup event relay hint methods
  • Loading branch information
hzrd149 committed Dec 2, 2023
1 parent 9069932 commit 199f208
Show file tree
Hide file tree
Showing 29 changed files with 294 additions and 107 deletions.
5 changes: 5 additions & 0 deletions .changeset/quick-garlics-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostrudel": minor
---

Add local relay cache option
12 changes: 8 additions & 4 deletions src/classes/nostr-multi-subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ export default class NostrMultiSubscription {
this.id = nanoid();
this.name = name;
}
private handleEvent(event: IncomingEvent) {
if (this.state === NostrMultiSubscription.OPEN && event.subId === this.id && !this.seenEvents.has(event.body.id)) {
this.onEvent.next(event.body);
this.seenEvents.add(event.body.id);
private handleEvent(incomingEvent: IncomingEvent) {
if (
this.state === NostrMultiSubscription.OPEN &&
incomingEvent.subId === this.id &&
!this.seenEvents.has(incomingEvent.body.id)
) {
this.onEvent.next(incomingEvent.body);
this.seenEvents.add(incomingEvent.body.id);
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/classes/nostr-subscription.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { nanoid } from "nanoid";

import { NostrEvent } from "../types/nostr-event";
import { NostrOutgoingMessage, NostrRequestFilter } from "../types/nostr-query";
import Relay, { IncomingEOSE } from "./relay";
import relayPoolService from "../services/relay-pool";
import { Subject } from "./subject";
import { nanoid } from "nanoid";

export default class NostrSubscription {
static INIT = "initial";
Expand All @@ -26,7 +27,9 @@ export default class NostrSubscription {
this.relay = relayPoolService.requestRelay(relayUrl);

this.onEvent.connectWithHandler(this.relay.onEvent, (event, next) => {
if (this.state === NostrSubscription.OPEN) next(event.body);
if (this.state === NostrSubscription.OPEN) {
next(event.body);
}
});
this.onEOSE.connectWithHandler(this.relay.onEOSE, (eose, next) => {
if (this.state === NostrSubscription.OPEN) next(eose);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import appSettings from "../../../services/settings/app-settings";
import EventVerificationIcon from "../../event-verification-icon";
import { TrustProvider } from "../../../providers/trust";
import Timestamp from "../../timestamp";
import { getNeventCodeWithRelays } from "../../../helpers/nip19";
import { getNeventForEventId } from "../../../helpers/nip19";
import { CompactNoteContent } from "../../compact-note-content";
import HoverLinkOverlay from "../../hover-link-overlay";
import { getReferences } from "../../../helpers/nostr/events";
Expand All @@ -26,7 +26,7 @@ export default function EmbeddedTorrentComment({
const { showSignatureVerification } = useSubject(appSettings);
const refs = getReferences(comment);
const torrent = useSingleEvent(refs.rootId, refs.rootRelay ? [refs.rootRelay] : []);
const linkToTorrent = refs.rootId && `/torrents/${getNeventCodeWithRelays(refs.rootId)}`;
const linkToTorrent = refs.rootId && `/torrents/${getNeventForEventId(refs.rootId)}`;

const handleClick = useCallback<MouseEventHandler>(
(e) => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/embed-event/event-types/embedded-torrent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";

import { getNeventCodeWithRelays } from "../../../helpers/nip19";
import { getSharableEventAddress } from "../../../helpers/nip19";
import UserAvatarLink from "../../user-avatar-link";
import { UserLink } from "../../user-link";
import { NostrEvent } from "../../../types/nostr-event";
Expand All @@ -29,7 +29,7 @@ import HoverLinkOverlay from "../../hover-link-overlay";

export default function EmbeddedTorrent({ torrent, ...props }: Omit<CardProps, "children"> & { torrent: NostrEvent }) {
const navigate = useNavigateInDrawer();
const link = `/torrents/${getNeventCodeWithRelays(torrent.id)}`;
const link = `/torrents/${getSharableEventAddress(torrent)}`;

const handleClick = useCallback<MouseEventHandler>(
(e) => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/event-zap-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import accountService from "../../services/account";
import PayStep from "./pay-step";
import { getInvoiceFromCallbackUrl } from "../../helpers/lnurl";
import { UserLink } from "../user-link";
import relayHintService from "../../services/event-relay-hint";

export type PayRequest = { invoice?: string; pubkey: string; error?: any };

Expand Down Expand Up @@ -69,7 +70,7 @@ async function getPayRequestForPubkey(
.map((r) => r.url) ?? [],
)
.slice(0, 4);
const eventRelays = event ? relayScoreboardService.getRankedRelays(getEventRelays(event.id).value).slice(0, 4) : [];
const eventRelays = event ? relayHintService.getEventRelayHints(event, 4) : [];
const outbox = relayScoreboardService.getRankedRelays(clientRelaysService.getWriteUrls()).slice(0, 4);
const additional = relayScoreboardService.getRankedRelays(additionalRelays);

Expand Down
4 changes: 2 additions & 2 deletions src/components/note-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Link, LinkProps } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";

import { truncatedId } from "../helpers/nostr/events";
import { getNeventCodeWithRelays } from "../helpers/nip19";
import { getNeventForEventId } from "../helpers/nip19";

export type NoteLinkProps = LinkProps & {
noteId: string;
};

export const NoteLink = ({ children, noteId, color = "blue.500", ...props }: NoteLinkProps) => {
const nevent = useMemo(() => getNeventCodeWithRelays(noteId), [noteId]);
const nevent = useMemo(() => getNeventForEventId(noteId), [noteId]);

return (
<Link as={RouterLink} to={`/n/${nevent}`} color={color} {...props}>
Expand Down
16 changes: 7 additions & 9 deletions src/components/note/components/repost-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,25 @@ import {
useDisclosure,
useToast,
} from "@chakra-ui/react";
import { Kind } from "nostr-tools";
import dayjs from "dayjs";
import type { AddressPointer } from "nostr-tools/lib/types/nip19";

import { DraftNostrEvent, NostrEvent } from "../../../types/nostr-event";
import { EmbedEvent } from "../../embed-event";
import { getEventRelays } from "../../../services/event-relays";
import relayScoreboardService from "../../../services/relay-scoreboard";
import { Kind } from "nostr-tools";
import dayjs from "dayjs";
import NostrPublishAction from "../../../classes/nostr-publish-action";
import clientRelaysService from "../../../services/client-relays";
import { useSigningContext } from "../../../providers/signing-provider";
import { ChevronDownIcon, ChevronUpIcon, ExternalLinkIcon } from "../../icons";
import useUserCommunitiesList from "../../../hooks/use-user-communities-list";
import useCurrentAccount from "../../../hooks/use-current-account";
import { AddressPointer } from "nostr-tools/lib/types/nip19";
import { createCoordinate } from "../../../services/replaceable-event-requester";
import relayHintService from "../../../services/event-relay-hint";

function buildRepost(event: NostrEvent): DraftNostrEvent {
const relays = getEventRelays(event.id).value;
const topRelay = relayScoreboardService.getRankedRelays(relays)[0] ?? "";

const hint = relayHintService.getEventRelayHint(event);
const tags: NostrEvent["tags"] = [];
tags.push(["e", event.id, topRelay]);
tags.push(["e", event.id, hint ?? ""]);

return {
kind: Kind.Repost,
Expand Down Expand Up @@ -65,6 +62,7 @@ export default function RepostModal({
draftRepost.tags.push([
"a",
createCoordinate(communityPointer.kind, communityPointer.pubkey, communityPointer.identifier),
relayHintService.getAddressPointerRelayHint(communityPointer) ?? "",
]);
}
const signed = await requestSignature(draftRepost);
Expand Down
26 changes: 10 additions & 16 deletions src/helpers/nip19.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { bech32 } from "bech32";
import { getPublicKey, nip19 } from "nostr-tools";
import { getEventRelays } from "../services/event-relays";
import relayScoreboardService from "../services/relay-scoreboard";
import { NostrEvent, Tag, isATag, isDTag, isETag, isPTag } from "../types/nostr-event";
import { getEventUID, isReplaceable } from "./nostr/events";
import { isReplaceable } from "./nostr/events";
import { DecodeResult } from "nostr-tools/lib/types/nip19";
import relayHintService from "../services/event-relay-hint";

export function isHexKey(key?: string) {
if (key?.toLowerCase()?.match(/^[0-9a-f]{64}$/)) return true;
Expand Down Expand Up @@ -47,7 +46,7 @@ export function safeDecode(str: string) {
} catch (e) {}
}

export function getPubkey(result?: nip19.DecodeResult) {
export function getPubkeyFromDecodeResult(result?: nip19.DecodeResult) {
if (!result) return;
switch (result.type) {
case "naddr":
Expand All @@ -68,26 +67,21 @@ export function normalizeToHex(hex: string) {
}

export function getSharableEventAddress(event: NostrEvent) {
const relays = getEventRelays(getEventUID(event)).value;
const ranked = relayScoreboardService.getRankedRelays(relays);
const maxTwo = ranked.slice(0, 2);
const relays = relayHintService.getEventRelayHints(event, 2);

if (isReplaceable(event.kind)) {
const d = event.tags.find(isDTag)?.[1];
if (!d) return null;
return nip19.naddrEncode({ kind: event.kind, identifier: d, pubkey: event.pubkey, relays: maxTwo });
return nip19.naddrEncode({ kind: event.kind, identifier: d, pubkey: event.pubkey, relays });
} else {
if (maxTwo.length == 2) {
return nip19.neventEncode({ id: event.id, kind: event.kind, relays: maxTwo });
} else return nip19.neventEncode({ id: event.id, kind: event.kind, relays: maxTwo, author: event.pubkey });
return nip19.neventEncode({ id: event.id, kind: event.kind, relays, author: event.pubkey });
}
}

export function getNeventCodeWithRelays(eventId: string) {
const relays = getEventRelays(eventId).value;
const ranked = relayScoreboardService.getRankedRelays(relays);
const maxTwo = ranked.slice(0, 2);
return nip19.neventEncode({ id: eventId, relays: maxTwo });
/** @deprecated use getSharableEventAddress unless required */
export function getNeventForEventId(eventId: string, maxRelays = 2) {
const relays = relayHintService.getEventPointerRelayHints(eventId).slice(0, maxRelays);
return nip19.neventEncode({ id: eventId, relays });
}

export function encodePointer(pointer: DecodeResult) {
Expand Down
24 changes: 0 additions & 24 deletions src/helpers/nostr/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,30 +193,6 @@ export function parseCoordinate(a: string, requireD = false): CustomEventPointer
};
}

export function draftAddCoordinate(list: NostrEvent | DraftNostrEvent, coordinate: string, relay?: string) {
if (list.tags.some((t) => t[0] === "a" && t[1] === coordinate)) throw new Error("event already in list");

const draft: DraftNostrEvent = {
created_at: dayjs().unix(),
kind: list.kind,
content: list.content,
tags: [...list.tags, relay ? ["a", coordinate, relay] : ["a", coordinate]],
};

return draft;
}

export function draftRemoveCoordinate(list: NostrEvent | DraftNostrEvent, coordinate: string) {
const draft: DraftNostrEvent = {
created_at: dayjs().unix(),
kind: list.kind,
content: list.content,
tags: list.tags.filter((t) => !(t[0] === "a" && t[1] === coordinate)),
};

return draft;
}

export function parseHardcodedNoteContent(event: NostrEvent) {
const json = safeJson(event.content, null);
if (!json) return null;
Expand Down
8 changes: 8 additions & 0 deletions src/helpers/nostr/filter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import stringify from "json-stringify-deterministic";
import { NostrQuery, NostrRequestFilter, RelayQueryMap } from "../../types/nostr-query";
import localCacheRelayService, { LOCAL_CACHE_RELAY } from "../../services/local-cache-relay";

export function addQueryToFilter(filter: NostrRequestFilter, query: NostrQuery) {
if (Array.isArray(filter)) {
Expand All @@ -20,6 +21,13 @@ export function mapQueryMap(queryMap: RelayQueryMap, fn: (filter: NostrRequestFi

export function createSimpleQueryMap(relays: string[], filter: NostrRequestFilter) {
const map: RelayQueryMap = {};

// if the local cache relay is enabled, also ask it
if (localCacheRelayService.enabled) {
map[LOCAL_CACHE_RELAY] = filter;
}

for (const relay of relays) map[relay] = filter;

return map;
}
3 changes: 2 additions & 1 deletion src/helpers/nostr/lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ export function listAddCoordinate(
coordinate: string,
relay?: string,
): DraftNostrEvent {
if (list.tags.some((t) => t[0] === "a" && t[1] === coordinate)) throw new Error("coordinate already in list");
if (list.tags.some((t) => t[0] === "a" && t[1] === coordinate)) throw new Error("Event already in list");

return {
created_at: dayjs().unix(),
kind: list.kind,
Expand Down
12 changes: 5 additions & 7 deletions src/helpers/nostr/post.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { DraftNostrEvent, NostrEvent, Tag } from "../../types/nostr-event";
import { getMatchEmoji, getMatchHashtag } from "../regexp";
import { getReferences } from "./events";
import { getEventRelays } from "../../services/event-relays";
import relayScoreboardService from "../../services/relay-scoreboard";
import { getPubkey, safeDecode } from "../nip19";
import { getPubkeyFromDecodeResult, safeDecode } from "../nip19";
import { Emoji } from "../../providers/emoji-provider";
import { EventSplit } from "./zaps";
import { unique } from "../array";
import relayHintService from "../../services/event-relay-hint";

function addTag(tags: Tag[], tag: Tag, overwrite = false) {
if (tags.some((t) => t[0] === tag[0] && t[1] === tag[1])) {
Expand All @@ -21,10 +20,9 @@ function addTag(tags: Tag[], tag: Tag, overwrite = false) {
return [...tags, tag];
}
function AddEtag(tags: Tag[], eventId: string, type?: string, overwrite = false) {
const relays = getEventRelays(eventId).value ?? [];
const top = relayScoreboardService.getRankedRelays(relays)[0] ?? "";
const hint = relayHintService.getEventPointerRelayHint(eventId) ?? "";

const tag = type ? ["e", eventId, top, type] : ["e", eventId, top];
const tag = type ? ["e", eventId, hint, type] : ["e", eventId, hint];

if (tags.some((t) => t[0] === tag[0] && t[1] === tag[1] && t[3] === tag[3])) {
if (overwrite) {
Expand Down Expand Up @@ -73,7 +71,7 @@ export function getContentMentions(content: string) {
Array.from(matched)
.map((m) => {
const parsed = safeDecode(m[1]);
return parsed && getPubkey(parsed);
return parsed && getPubkeyFromDecodeResult(parsed);
})
.filter(Boolean) as string[],
);
Expand Down
10 changes: 0 additions & 10 deletions src/hooks/use-ranked-relay-configs.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/hooks/use-shareable-profile-id.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useMemo } from "react";
import relayScoreboardService from "../services/relay-scoreboard";
import { RelayMode } from "../classes/relay";
import { nip19 } from "nostr-tools";

import { RelayMode } from "../classes/relay";
import relayScoreboardService from "../services/relay-scoreboard";
import { useUserRelays } from "./use-user-relays";

export function useSharableProfileId(pubkey: string, relayCount = 2) {
Expand Down
3 changes: 1 addition & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import "./polyfill";
import { createRoot } from "react-dom/client";
import { App } from "./app";
import { GlobalProviders } from "./providers";

import "./services/serial-port";
import "./services/local-cache-relay";

// setup dayjs
import dayjs from "dayjs";
Expand Down
Loading

0 comments on commit 199f208

Please sign in to comment.