chore: random fixes
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Kieran 2023-11-22 15:34:46 +00:00
parent a67263e5e1
commit 2884a35b5c
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
9 changed files with 75 additions and 66 deletions

View File

@ -16,7 +16,7 @@ enum Provider {
} }
export default function SuggestedProfiles() { export default function SuggestedProfiles() {
const login = useLogin(); const login = useLogin(s => ({ publicKey: s.publicKey, follows: s.follows.item }));
const [userList, setUserList] = useState<HexKey[]>(); const [userList, setUserList] = useState<HexKey[]>();
const [provider, setProvider] = useState(Provider.NostrBand); const [provider, setProvider] = useState(Provider.NostrBand);
const [error, setError] = useState<Error>(); const [error, setError] = useState<Error>();
@ -37,7 +37,7 @@ export default function SuggestedProfiles() {
} }
case Provider.SemisolDev: { case Provider.SemisolDev: {
const api = new SemisolDevApi(); const api = new SemisolDevApi();
const users = await api.sugguestedFollows(login.publicKey, login.follows.item); const users = await api.sugguestedFollows(login.publicKey, login.follows);
const keys = users.recommendations.sort(a => a[1]).map(a => a[0]); const keys = users.recommendations.sort(a => a[1]).map(a => a[0]);
setUserList(keys); setUserList(keys);
break; break;
@ -52,7 +52,7 @@ export default function SuggestedProfiles() {
useEffect(() => { useEffect(() => {
loadSuggestedProfiles(); loadSuggestedProfiles();
}, [login, provider]); }, [login.publicKey, login.follows, provider]);
return ( return (
<> <>

View File

@ -1,11 +1,9 @@
import { useEffect, useMemo } from "react"; import { useEffect, useMemo } from "react";
import { TaggedNostrEvent, EventKind, RequestBuilder, NoteCollection, NostrLink } from "@snort/system"; import { TaggedNostrEvent, EventKind, RequestBuilder, NoteCollection, NostrLink, parseRelayTags } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react"; import { useRequestBuilder } from "@snort/system-react";
import { bech32ToHex, debounce, findTag, getNewest, getNewestEventTagsByKey, unwrap } from "@/SnortUtils"; import { bech32ToHex, debounce, getNewest, getNewestEventTagsByKey, unwrap } from "@/SnortUtils";
import { makeNotification, sendNotification } from "@/Notifications";
import useEventPublisher from "@/Hooks/useEventPublisher"; import useEventPublisher from "@/Hooks/useEventPublisher";
import useModeration from "@/Hooks/useModeration";
import useLogin from "@/Hooks/useLogin"; import useLogin from "@/Hooks/useLogin";
import { import {
SnortAppData, SnortAppData,
@ -24,14 +22,14 @@ import { SubscriptionEvent } from "@/Subscription";
import { FollowLists, FollowsFeed, GiftsCache, Notifications, UserRelays } from "@/Cache"; import { FollowLists, FollowsFeed, GiftsCache, Notifications, UserRelays } from "@/Cache";
import { Nip28Chats, Nip4Chats } from "@/chat"; import { Nip28Chats, Nip4Chats } from "@/chat";
import { useRefreshFeedCache } from "@/Hooks/useRefreshFeedcache"; import { useRefreshFeedCache } from "@/Hooks/useRefreshFeedcache";
import { usePrevious } from "@uidotdev/usehooks";
/** /**
* Managed loading data for the current logged in user * Managed loading data for the current logged in user
*/ */
export default function useLoginFeed() { export default function useLoginFeed() {
const login = useLogin(); const login = useLogin();
const { publicKey: pubKey, readNotifications, follows } = login; const { publicKey: pubKey, follows } = login;
const { isMuted } = useModeration();
const { publisher, system } = useEventPublisher(); const { publisher, system } = useEventPublisher();
useRefreshFeedCache(Notifications, true); useRefreshFeedCache(Notifications, true);
@ -43,15 +41,19 @@ export default function useLoginFeed() {
system.checkSigs = login.appData.item.preferences.checkSigs; system.checkSigs = login.appData.item.preferences.checkSigs;
}, [login]); }, [login]);
const previous = usePrevious(login.appData.item);
// write appdata after 10s of no changes // write appdata after 10s of no changes
useEffect(() => { useEffect(() => {
if (!previous || JSON.stringify(previous) === JSON.stringify(login.appData.item)) {
return;
}
return debounce(10_000, async () => { return debounce(10_000, async () => {
if (publisher && login.appData.item) { if (publisher && login.appData.item) {
const ev = await publisher.appData(login.appData.item, "snort"); const ev = await publisher.appData(login.appData.item, "snort");
await system.BroadcastEvent(ev); await system.BroadcastEvent(ev);
} }
}); });
}, [login.appData.timestamp]); }, [previous]);
const subLogin = useMemo(() => { const subLogin = useMemo(() => {
if (!login || !pubKey) return null; if (!login || !pubKey) return null;
@ -62,8 +64,16 @@ export default function useLoginFeed() {
}); });
b.withFilter() b.withFilter()
.authors([pubKey]) .authors([pubKey])
.kinds([EventKind.ContactList, EventKind.Relays, EventKind.MuteList, EventKind.PinList]); .kinds([
b.withFilter().authors([pubKey]).kinds([EventKind.CategorizedBookmarks]).tag("d", ["follow", "bookmark"]); EventKind.ContactList,
EventKind.Relays,
EventKind.MuteList,
EventKind.PinList,
EventKind.BookmarksList,
EventKind.InterestsList,
EventKind.PublicChatsList,
]);
b.withFilter().authors([pubKey]).kinds([]);
if (CONFIG.features.subscriptions && !login.readonly) { if (CONFIG.features.subscriptions && !login.readonly) {
b.withFilter().authors([pubKey]).kinds([EventKind.AppData]).tag("d", ["snort"]); b.withFilter().authors([pubKey]).kinds([EventKind.AppData]).tag("d", ["snort"]);
b.withFilter() b.withFilter()
@ -100,17 +110,7 @@ export default function useLoginFeed() {
const relays = getNewest(loginFeed.data.filter(a => a.kind === EventKind.Relays)); const relays = getNewest(loginFeed.data.filter(a => a.kind === EventKind.Relays));
if (relays) { if (relays) {
const parsedRelays = relays.tags const parsedRelays = parseRelayTags(relays.tags.filter(a => a[0] === "r")).map(a => [a.url, a.settings]);
.filter(a => a[0] === "r")
.map(a => {
return [
a[1],
{
read: a[2] === "read" || a[2] === undefined,
write: a[2] === "write" || a[2] === undefined,
},
];
});
setRelays(login, Object.fromEntries(parsedRelays), relays.created_at * 1000); setRelays(login, Object.fromEntries(parsedRelays), relays.created_at * 1000);
} }
@ -144,21 +144,6 @@ export default function useLoginFeed() {
} }
}, [loginFeed, publisher]); }, [loginFeed, publisher]);
// send out notifications
useEffect(() => {
if (loginFeed.data) {
const replies = loginFeed.data.filter(
a => a.kind === EventKind.TextNote && !isMuted(a.pubkey) && a.created_at > readNotifications,
);
replies.forEach(async nx => {
const n = await makeNotification(nx);
if (n) {
sendNotification(login, n);
}
});
}
}, [loginFeed, readNotifications]);
async function handleMutedFeed(mutedFeed: TaggedNostrEvent[]) { async function handleMutedFeed(mutedFeed: TaggedNostrEvent[]) {
const latest = getNewest(mutedFeed); const latest = getNewest(mutedFeed);
if (!latest) return; if (!latest) return;
@ -211,14 +196,10 @@ export default function useLoginFeed() {
const pinnedFeed = loginFeed.data.filter(a => a.kind === EventKind.PinList); const pinnedFeed = loginFeed.data.filter(a => a.kind === EventKind.PinList);
handlePinnedFeed(pinnedFeed); handlePinnedFeed(pinnedFeed);
const tagsFeed = loginFeed.data.filter( const tagsFeed = loginFeed.data.filter(a => a.kind === EventKind.InterestsList);
a => a.kind === EventKind.CategorizedBookmarks && findTag(a, "d") === "follow",
);
handleTagFeed(tagsFeed); handleTagFeed(tagsFeed);
const bookmarkFeed = loginFeed.data.filter( const bookmarkFeed = loginFeed.data.filter(a => a.kind === EventKind.BookmarksList);
a => a.kind === EventKind.CategorizedBookmarks && findTag(a, "d") === "bookmark",
);
handleBookmarkFeed(bookmarkFeed); handleBookmarkFeed(bookmarkFeed);
} }
}, [loginFeed]); }, [loginFeed]);

View File

@ -27,7 +27,7 @@ export function useLinkListEvents(id: string, fn: (rb: RequestBuilder) => void)
} }
export function usePinList(pubkey: string | undefined) { export function usePinList(pubkey: string | undefined) {
return useLinkListEvents(`pins:${pubkey?.slice(0, 12)}`, rb => { return useLinkListEvents(`list:pins:${pubkey?.slice(0, 12)}`, rb => {
if (pubkey) { if (pubkey) {
rb.withFilter().kinds([EventKind.PinList]).authors([pubkey]); rb.withFilter().kinds([EventKind.PinList]).authors([pubkey]);
} }
@ -35,17 +35,25 @@ export function usePinList(pubkey: string | undefined) {
} }
export function useMuteList(pubkey: string | undefined) { export function useMuteList(pubkey: string | undefined) {
return useLinkList(`pins:${pubkey?.slice(0, 12)}`, rb => { return useLinkList(`list:mute:${pubkey?.slice(0, 12)}`, rb => {
if (pubkey) { if (pubkey) {
rb.withFilter().kinds([EventKind.MuteList]).authors([pubkey]); rb.withFilter().kinds([EventKind.MuteList]).authors([pubkey]);
} }
}); });
} }
export default function useCategorizedBookmarks(pubkey: string | undefined, list: string) { export function useBookmarkList(pubkey: string | undefined) {
return useLinkListEvents(`categorized-bookmarks:${list}:${pubkey?.slice(0, 12)}`, rb => { return useLinkListEvents(`list:bookmark:${pubkey?.slice(0, 12)}`, rb => {
if (pubkey) { if (pubkey) {
rb.withFilter().kinds([EventKind.CategorizedBookmarks]).authors([pubkey]).tag("d", [list]); rb.withFilter().kinds([EventKind.BookmarksList]).authors([pubkey]);
}
});
}
export function useInterestsList(pubkey: string | undefined) {
return useLinkList(`list:interest:${pubkey?.slice(0, 12)}`, rb => {
if (pubkey) {
rb.withFilter().kinds([EventKind.InterestsList]).authors([pubkey]);
} }
}); });
} }

View File

@ -1,7 +1,7 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { FormattedMessage, FormattedNumber } from "react-intl"; import { FormattedMessage, FormattedNumber } from "react-intl";
import { EventKind, NostrHashtagLink, NoteCollection, RequestBuilder } from "@snort/system"; import { EventKind, NoteCollection, RequestBuilder } from "@snort/system";
import { dedupe } from "@snort/shared"; import { dedupe } from "@snort/shared";
import { useRequestBuilder } from "@snort/system-react"; import { useRequestBuilder } from "@snort/system-react";
@ -44,10 +44,11 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events?
async function followTags(ts: string[]) { async function followTags(ts: string[]) {
if (publisher) { if (publisher) {
const ev = await publisher.bookmarks( const ev = await publisher.generic(eb => {
ts.map(a => new NostrHashtagLink(a)), eb.kind(EventKind.InterestsList);
"follow", ts.forEach(a => eb.tag(["t", a]));
); return eb;
});
setTags(login, ts, ev.created_at * 1000); setTags(login, ts, ev.created_at * 1000);
await system.BroadcastEvent(ev); await system.BroadcastEvent(ev);
} }
@ -55,7 +56,7 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events?
const sub = useMemo(() => { const sub = useMemo(() => {
const rb = new RequestBuilder(`hashtag-counts:${tag}`); const rb = new RequestBuilder(`hashtag-counts:${tag}`);
rb.withFilter().kinds([EventKind.CategorizedBookmarks]).tag("d", ["follow"]).tag("t", [tag.toLowerCase()]); rb.withFilter().kinds([EventKind.InterestsList]).tag("t", [tag.toLowerCase()]);
return rb; return rb;
}, [tag]); }, [tag]);
const followsTag = useRequestBuilder(NoteCollection, sub); const followsTag = useRequestBuilder(NoteCollection, sub);

View File

@ -13,7 +13,7 @@ import Bookmarks from "@/Element/User/Bookmarks";
import Icon from "@/Icons/Icon"; import Icon from "@/Icons/Icon";
import { Tab } from "@/Element/Tabs"; import { Tab } from "@/Element/Tabs";
import { default as ZapElement } from "@/Element/Event/Zap"; import { default as ZapElement } from "@/Element/Event/Zap";
import useCategorizedBookmarks from "@/Hooks/useLists"; import { useBookmarkList } from "@/Hooks/useLists";
import messages from "../messages"; import messages from "../messages";
@ -60,7 +60,7 @@ export function RelaysTab({ id }: { id: HexKey }) {
} }
export function BookMarksTab({ id }: { id: HexKey }) { export function BookMarksTab({ id }: { id: HexKey }) {
const bookmarks = useCategorizedBookmarks(id, "bookmark"); const bookmarks = useBookmarkList(id);
const reactions = useReactions(`bookmark:reactions:{id}`, bookmarks.map(NostrLink.fromEvent)); const reactions = useReactions(`bookmark:reactions:{id}`, bookmarks.map(NostrLink.fromEvent));
return <Bookmarks pubkey={id} bookmarks={bookmarks} related={reactions.data ?? []} />; return <Bookmarks pubkey={id} bookmarks={bookmarks} related={reactions.data ?? []} />;
} }

View File

@ -27,9 +27,20 @@ enum EventKind {
MuteList = 10_000, // NIP-51 MuteList = 10_000, // NIP-51
PinList = 10_001, // NIP-51 PinList = 10_001, // NIP-51
BookmarksList = 10_003, // NIP-51
CommunitiesList = 10_004, // NIP-51
PublicChatsList = 10_005, // NIP-51
BlockedRelaysList = 10_006, // NIP-51
SearchRelaysList = 10_007, // NIP-51
InterestsList = 10_015, // NIP-51
EmojisList = 10_030, // NIP-51
CategorizedPeople = 30000, // NIP-51a FollowSet = 30_000, // NIP-51
CategorizedBookmarks = 30001, // NIP-51b RelaySet = 30_002, // NIP-51
BookmarkSet = 30_003, // NIP-51
CurationSet = 30_004, // NIP-51
InterestSet = 30_015, // NIP-15
EmojiSet = 30_030, // NIP-51
Badge = 30009, // NIP-58 Badge = 30009, // NIP-58
ProfileBadges = 30008, // NIP-58 ProfileBadges = 30008, // NIP-58

View File

@ -137,9 +137,8 @@ export class EventPublisher {
* Build a categorized bookmarks event with a given label * Build a categorized bookmarks event with a given label
* @param notes List of bookmarked links * @param notes List of bookmarked links
*/ */
async bookmarks(notes: Array<ToNostrEventTag>, list: "bookmark" | "follow") { async bookmarks(notes: Array<ToNostrEventTag>) {
const eb = this.#eb(EventKind.CategorizedBookmarks); const eb = this.#eb(EventKind.BookmarksList);
eb.tag(["d", list]);
notes.forEach(n => { notes.forEach(n => {
eb.tag(unwrap(n.toEventTag())); eb.tag(unwrap(n.toEventTag()));
}); });

View File

@ -400,7 +400,7 @@ export class NostrSystem extends EventEmitter<NostrSystemEvents> implements Syst
} }
return; return;
}), }),
...replyRelays.filter(a => !socks.some(b => b.Address === a)).map(a => this.WriteOnceToRelay(a, ev)), ...replyRelays.filter(a => !this.#sockets.has(a)).map(a => this.WriteOnceToRelay(a, ev)),
]); ]);
return removeUndefined(oks); return removeUndefined(oks);
} }

View File

@ -1,5 +1,14 @@
import { EventKind, FullRelaySettings, NostrEvent, ReqFilter, RequestBuilder, SystemInterface, UsersRelays } from "."; import {
import { dedupe, sanitizeRelayUrl, unixNowMs, unwrap } from "@snort/shared"; EventKind,
FullRelaySettings,
NostrEvent,
ReqFilter,
RequestBuilder,
SystemInterface,
TaggedNostrEvent,
UsersRelays,
} from ".";
import { dedupe, removeUndefined, sanitizeRelayUrl, unixNowMs, unwrap } from "@snort/shared";
import debug from "debug"; import debug from "debug";
import { FlatReqFilter } from "./query-optimizer"; import { FlatReqFilter } from "./query-optimizer";
import { RelayListCacheExpire } from "./const"; import { RelayListCacheExpire } from "./const";
@ -193,7 +202,7 @@ export async function pickRelaysForReply(ev: NostrEvent, system: SystemInterface
const recipients = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1])); const recipients = dedupe(ev.tags.filter(a => a[0] === "p").map(a => a[1]));
await updateRelayLists(recipients, system); await updateRelayLists(recipients, system);
const relays = pickTopRelays(system.RelayCache, recipients, 2, "read"); const relays = pickTopRelays(system.RelayCache, recipients, 2, "read");
const ret = dedupe(relays.map(a => a.relays).flat()); const ret = removeUndefined(dedupe(relays.map(a => a.relays).flat()));
logger("Picked %O from authors %O", ret, recipients); logger("Picked %O from authors %O", ret, recipients);
return ret; return ret;
} }