Skip to content

Commit

Permalink
Merge pull request #698 from SnowCait/unify-metadata
Browse files Browse the repository at this point in the history
Unify metadata
  • Loading branch information
SnowCait authored Oct 10, 2023
2 parents 9efdaab + d6cacfd commit a79979a
Show file tree
Hide file tree
Showing 16 changed files with 93 additions and 291 deletions.
47 changes: 10 additions & 37 deletions web/src/lib/Api.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { nip19, type Event, type SimplePool, Kind, type Filter } from 'nostr-tools';
import { get } from 'svelte/store';
import type { Event as NostrEvent, UserEvent } from '../routes/types';
import { cachedEvents, events as timelineEvents } from '../stores/Events';
import type { UserEvent } from '../routes/types';
import { events as timelineEvents } from '../stores/Events';
import { saveMetadataEvent, userEvents } from '../stores/UserEvents';
import { EventItem } from './Items';
import { Content } from './Content';
import { Signer } from './Signer';
import { channelMetadataEvents } from './cache/Events';
import { cachedEvents as newCachedEvents } from './cache/Events';
import { chronological, reverseChronological } from './Constants';
import { metadataReqEmit } from './timelines/MainTimeline';

export class Api {
public static readonly replaceableKinds = [
Expand Down Expand Up @@ -178,16 +179,6 @@ export class Api {
return events.at(0);
}

// With metadata
async fetchEventItem(filter: Filter): Promise<EventItem | undefined> {
const event = await this.fetchEvent([filter]);
if (event === undefined) {
return undefined;
}
const metadataEventsMap = await this.fetchMetadataEventsMap([event.pubkey]);
return new EventItem(event, metadataEventsMap.get(event.pubkey));
}

async fetchEventItemById(id: string): Promise<EventItem | undefined> {
// If exsits in store
const $events = get(timelineEvents);
Expand All @@ -211,10 +202,7 @@ export class Api {
return undefined;
}

const userEvent = await this.fetchUserEvent(event.pubkey);
if (userEvent === undefined) {
return new EventItem(event);
}
metadataReqEmit(event);

// // Return
// const nostrEvent = event as NostrEvent;
Expand All @@ -223,7 +211,7 @@ export class Api {
// Cache
// $cachedEvents.set(nostrEvent.id, nostrEvent);

return new EventItem(event, userEvent);
return new EventItem(event);
}

async fetchContactsEvent(pubkey: string): Promise<Event | undefined> {
Expand Down Expand Up @@ -267,28 +255,13 @@ export class Api {
);
const referencedEvents = await this.fetchEventsByIds([...referencedEventIds]);

const referencedPubkeys = events
.map((x) => x.tags.filter(([tagName]) => tagName === 'p').map(([, pubkey]) => pubkey))
.flat();
const referencedPubkeysOfReferencedEvents = referencedEvents
.map((x) => x.tags.filter(([tagName]) => tagName === 'p').map(([, pubkey]) => pubkey))
.flat();

const metadataEventsMap = await this.fetchMetadataEventsMap([
...new Set([
...[...events, ...referencedEvents].map((x) => x.pubkey),
...referencedPubkeys,
...referencedPubkeysOfReferencedEvents
])
]);
for (const event of [...events, ...referencedEvents]) {
metadataReqEmit(event);
}

events.sort(reverseChronological);
const eventItems = events.map(
(event) => new EventItem(event, metadataEventsMap.get(event.pubkey))
);
const referencedEventItems = referencedEvents.map(
(event) => new EventItem(event, metadataEventsMap.get(event.pubkey))
);
const eventItems = events.map((event) => new EventItem(event));
const referencedEventItems = referencedEvents.map((event) => new EventItem(event));

// Cache events
for (const item of [...eventItems, ...referencedEventItems]) {
Expand Down
7 changes: 1 addition & 6 deletions web/src/lib/Items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ export interface Item {
}

export class EventItem implements Item {
public metadata: Metadata | undefined;
constructor(public readonly event: Event, metadataEvent: Event | undefined = undefined) {
if (metadataEvent !== undefined) {
this.metadata = new Metadata(metadataEvent);
}
}
constructor(public readonly event: Event) {}

public get replyToPubkeys(): pubkey[] {
return [...new Set(filterTags('p', this.event.tags))];
Expand Down
11 changes: 6 additions & 5 deletions web/src/lib/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EventItem } from './Items';
import { pool } from '../stores/Pool';
import { Api } from './Api';
import { readRelays } from '../stores/Author';
import { metadataReqEmit } from './timelines/MainTimeline';

export class Search {
parseQuery(query: string): Filter {
Expand Down Expand Up @@ -67,11 +68,11 @@ export class Search {
const $pool = get(pool);
const api = new Api($pool, filter.search !== undefined ? searchRelays : get(readRelays));
const events = await api.fetchEvents([filter]);
const metadataEventsMap = await api.fetchMetadataEventsMap([
...new Set(events.map((x) => x.pubkey))
]);
console.log('[search events]', events, metadataEventsMap);
console.log('[search events]', events);
for (const event of events) {
metadataReqEmit(event);
}
events.sort(reverseChronological);
return events.map((event) => new EventItem(event, metadataEventsMap.get(event.pubkey)));
return events.map((event) => new EventItem(event));
}
}
8 changes: 3 additions & 5 deletions web/src/lib/Timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { userTimelineEvents } from '../stores/Events';
import { chunk } from './Array';
import { filterLimitItems } from './Constants';
import { Content } from './Content';
import { metadataReqEmit } from './timelines/MainTimeline';

export class Timeline {
private readonly $pool: SimplePool;
Expand Down Expand Up @@ -95,10 +96,7 @@ export class Timeline {
return;
}

const userEvent = await this.api.fetchUserEvent(event.pubkey); // not chronological
if (userEvent !== undefined) {
event.user = userEvent.user;
}
metadataReqEmit(event);

// Cache note events
const eventIds = new Set([
Expand All @@ -117,7 +115,7 @@ export class Timeline {
// }

const events = get(userTimelineEvents);
events.unshift(new EventItem(event, userEvent));
events.unshift(new EventItem(event));
userTimelineEvents.set(events);

// // Cache
Expand Down
10 changes: 5 additions & 5 deletions web/src/lib/cache/Events.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { get } from 'svelte/store';
import { get, writable } from 'svelte/store';
import type { Event } from 'nostr-tools';
import type { id, pubkey } from '$lib/Types';
import { EventItem } from '$lib/Items';
import { EventItem, Metadata } from '$lib/Items';
import { events } from '../../stores/Events';

export const metadataStore = writable(new Map<pubkey, Metadata>());

// <event.id, event>
export const cachedEvents = new Map<id, Event>();
// <event.pubkey, event>
export const metadataEvents = new Map<pubkey, Event>();
// <root-id, event>
export const channelMetadataEvents = new Map<id, Event>();

Expand All @@ -16,7 +16,7 @@ export function getCachedEventItem(id: string): EventItem | undefined {
if (item === undefined) {
const event = cachedEvents.get(id);
if (event !== undefined) {
item = new EventItem(event, metadataEvents.get(event.pubkey));
item = new EventItem(event);
}
}
return item;
Expand Down
31 changes: 13 additions & 18 deletions web/src/lib/timelines/MainTimeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { batch, createRxBackwardReq, createRxNostr, latestEach } from 'rx-nostr'
import { bufferTime } from 'rxjs';
import { timeout } from '$lib/Constants';
import { filterTags } from '$lib/EventHelper';
import { Metadata } from '../Items';
import { metadataEvents } from '../cache/Events';
import { events } from '../../stores/Events';
import { Metadata } from '$lib/Items';
import { metadataStore } from '../cache/Events';

export const rxNostr = createRxNostr({ timeout }); // Based on NIP-65

const metadataReq = createRxBackwardReq();

export const rxNostr = createRxNostr({ timeout }); // for home & notification timeline
export const metadataReq = createRxBackwardReq();
export function metadataReqEmit(event: Event): void {
for (const pubkey of [event.pubkey, ...filterTags('p', event.tags)]) {
console.debug('[rx-nostr metadata REQ emit]', pubkey);
metadataReq.emit({
kinds: [0],
authors: [pubkey],
Expand All @@ -20,23 +22,16 @@ export function metadataReqEmit(event: Event): void {
}
}

const $events = get(events);
rxNostr
.use(metadataReq.pipe(bufferTime(1000, null, 10), batch()))
.pipe(latestEach(({ event }: { event: Event }) => event.pubkey))
.subscribe(async (packet) => {
const cache = metadataEvents.get(packet.event.pubkey);
if (cache === undefined || cache.created_at < packet.event.created_at) {
metadataEvents.set(packet.event.pubkey, packet.event);

const cache = get(metadataStore).get(packet.event.pubkey);
if (cache === undefined || cache.event.created_at < packet.event.created_at) {
const metadata = new Metadata(packet.event);
console.log('[rx-nostr metadata]', packet, metadata.content?.name, $events.length);
for (const item of $events) {
if (item.event.pubkey !== packet.event.pubkey) {
continue;
}
item.metadata = metadata;
}
events.set($events);
console.log('[rx-nostr metadata]', packet, metadata.content?.name);
const store = get(metadataStore);
store.set(metadata.event.pubkey, metadata);
metadataStore.set(store);
}
});
11 changes: 7 additions & 4 deletions web/src/routes/ZapDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
import { WebStorage } from '$lib/WebStorage';
import { Signer } from '$lib/Signer';
import type { EventItem } from '$lib/Items';
import { metadataStore } from '$lib/cache/Events';
import ModalDialog from '$lib/components/ModalDialog.svelte';
export let eventItem: EventItem;
$: metadata = $metadataStore.get(eventItem.event.pubkey);
export function openZapDialog() {
console.log('[zap open]');
open = true;
Expand Down Expand Up @@ -40,12 +43,12 @@
relays: $writeRelays
});
const zapRequestEvent = await Signer.signEvent(zapRequest);
console.log('[zap request]', zapRequestEvent, eventItem.metadata?.content);
console.log('[zap request]', zapRequestEvent, metadata?.content);
const encoded = encodeURI(JSON.stringify(zapRequestEvent));
const zapUrl = (await eventItem.metadata?.zapUrl()) ?? null;
const zapUrl = (await metadata?.zapUrl()) ?? null;
if (zapUrl === null) {
console.error('[zap url not found]', eventItem.metadata?.content?.lud16);
console.error('[zap url not found]', metadata?.content?.lud16);
return;
}
const url = `${zapUrl.href}?amount=${amount}&nostr=${encoded}`;
Expand All @@ -71,7 +74,7 @@
<article>
{#if invoice === ''}
<div>
@{eventItem.metadata?.content?.name ?? eventItem.metadata?.content?.display_name}
@{metadata?.content?.name ?? metadata?.content?.display_name}
</div>
<form on:submit|preventDefault={zap}>
<div>
Expand Down
46 changes: 4 additions & 42 deletions web/src/routes/[npub=npub]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,9 @@
import { error } from '@sveltejs/kit';
import { page } from '$app/stores';
import { nip05, nip19, SimplePool, type Event } from 'nostr-tools';
import {
batch,
createRxBackwardReq,
createRxOneshotReq,
latestEach,
now,
uniq
} from 'rx-nostr';
import { createRxOneshotReq, now, uniq } from 'rx-nostr';
import { tap, bufferTime } from 'rxjs';
import { rxNostr } from '$lib/timelines/MainTimeline';
import { metadataEvents } from '$lib/cache/Events';
import { metadataReqEmit, rxNostr } from '$lib/timelines/MainTimeline';
import type { User } from '../types';
import { pool } from '../../stores/Pool';
import TimelineView from '../TimelineView.svelte';
Expand Down Expand Up @@ -52,27 +44,6 @@
let slug = $page.params.npub;
const api = new Api($pool, relays);
const metadataReq = createRxBackwardReq();
rxNostr
.use(metadataReq.pipe(bufferTime(1000, null, 10), batch()))
.pipe(latestEach(({ event }: { event: Event }) => event.pubkey))
.subscribe(async (packet) => {
const cache = metadataEvents.get(packet.event.pubkey);
if (cache === undefined || cache.created_at < packet.event.created_at) {
metadataEvents.set(packet.event.pubkey, packet.event);
const metadata = new Metadata(packet.event);
console.log('[rx-nostr metadata]', packet, metadata.content?.name);
for (const item of events) {
if (item.event.pubkey !== packet.event.pubkey) {
continue;
}
item.metadata = metadata;
}
events = events;
}
});
afterNavigate(async () => {
slug = $page.params.npub;
console.log('[profile page]', slug);
Expand Down Expand Up @@ -165,13 +136,7 @@
.use(pastEventsReq)
.pipe(
uniq(),
tap(({ event }: { event: Event }) => {
metadataReq.emit({
kinds: [0],
authors: [event.pubkey],
limit: 1
});
}),
tap(({ event }: { event: Event }) => metadataReqEmit(event)),
bufferTime(timelineBufferMs)
)
.subscribe({
Expand All @@ -183,10 +148,7 @@
({ event }) =>
since <= event.created_at && event.created_at < until
)
.map(
({ event }) =>
new EventItem(event, metadataEvents.get(event.pubkey))
);
.map(({ event }) => new EventItem(event));
const duplicateEvents = newEventItems.filter((item) =>
events.some((x) => x.event.id === item.event.id)
);
Expand Down
17 changes: 6 additions & 11 deletions web/src/routes/[npub=npub]/bookmark/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import TimelineView from '../../TimelineView.svelte';
import { Signer } from '$lib/Signer';
import { EventItem } from '$lib/Items';
import { metadataReqEmit } from '$lib/timelines/MainTimeline';
let publicBookmarkEventItems: EventItem[] = [];
let privateBookmarkEventItems: EventItem[] = [];
Expand Down Expand Up @@ -54,21 +55,15 @@
}
console.log('[bookmarks]', originalPublicBookmarkEvents, originalPrivateBookmarkEvents);
const metadataEvents = await api.fetchMetadataEventsMap(
Array.from(
new Set([
...originalPublicBookmarkEvents.map((x) => x.pubkey),
...originalPrivateBookmarkEvents.map((x) => x.pubkey)
])
)
);
console.log('[bookmark metadata]', metadataEvents);
for (const event of [...originalPublicBookmarkEvents, ...originalPrivateBookmarkEvents]) {
metadataReqEmit(event);
}
publicBookmarkEventItems = originalPublicBookmarkEvents.map(
(event) => new EventItem(event, metadataEvents.get(event.pubkey))
(event) => new EventItem(event)
);
privateBookmarkEventItems = originalPrivateBookmarkEvents.map(
(event) => new EventItem(event, metadataEvents.get(event.pubkey))
(event) => new EventItem(event)
);
});
</script>
Expand Down
Loading

1 comment on commit a79979a

@vercel
Copy link

@vercel vercel bot commented on a79979a Oct 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nostter – ./

nostter-git-main-snowcait.vercel.app
nostter-snowcait.vercel.app
nostter.vercel.app

Please sign in to comment.