slight changes to timeline loader

This commit is contained in:
hzrd149 2023-03-11 08:52:12 -06:00
parent 9cb2e8a5d8
commit a4194c1a73
7 changed files with 28 additions and 31 deletions

View File

@ -72,6 +72,7 @@ I would recomend you use a browser extension like [Alby](https://getalby.com/) o
## TODO
- Update TimelineLoader to connect to each relay individually so it better track the latest events
- Create notifications service that keeps track of read notifications. (show unread count in sidenav)
- Rebuild relays view to show relay info and settings NIP-11
- filter list of followers by users the user has blocked/reported (stops bots/spammers from showing up at followers)
@ -81,8 +82,6 @@ I would recomend you use a browser extension like [Alby](https://getalby.com/) o
- make app a valid web share target https://developer.chrome.com/articles/web-share-target/
- handle image share
- implement NIP-56 and blocking
- allow user to select relay or following list when fetching replies (default to my relays + following?)
- massive thread note1dapvuu8fl09yjtg2gyr2h6nypaffl2sq0aj5raz86463qk5kpyzqlxvtc3
- Improve link previews https://github.com/pengx17/logseq-plugin-link-preview/blob/master/src/use-link-preview-metadata.tsx
- Support `magnet:` links
- in-browser video player? https://webtorrent.io/

View File

@ -3,44 +3,40 @@ import { NostrEvent } from "../types/nostr-event";
import { NostrQuery } from "../types/nostr-query";
import { NostrRequest } from "./nostr-request";
import { NostrMultiSubscription } from "./nostr-multi-subscription";
import Subject, { PersistentSubject } from "./subject";
export type NostrQueryWithStart = NostrQuery & { since: number };
import { PersistentSubject } from "./subject";
import { utils } from "nostr-tools";
type Options = {
name?: string;
pageSize: number;
startLimit: number;
};
export type TimelineLoaderOptions = Partial<Options>;
export class TimelineLoader {
relays: string[];
query: NostrQueryWithStart;
query: NostrQuery;
events = new PersistentSubject<NostrEvent[]>([]);
loading = new PersistentSubject(false);
page = new PersistentSubject(0);
private eventDir = new Map<string, NostrEvent>();
private seenEvents = new Set<string>();
private subscription: NostrMultiSubscription;
private opts: Options = { pageSize: moment.duration(1, "hour").asSeconds() };
constructor(relays: string[], query: NostrQueryWithStart, opts?: TimelineLoaderOptions) {
if (!query.since) throw new Error('Timeline requires "since" to be set in query');
private opts: Options = { pageSize: moment.duration(1, "hour").asSeconds(), startLimit: 10 };
constructor(relays: string[], query: NostrQuery, opts?: TimelineLoaderOptions) {
this.relays = relays;
this.query = query;
Object.assign(this.opts, opts);
this.query = { ...query, limit: this.opts.startLimit };
this.subscription = new NostrMultiSubscription(relays, query, opts?.name);
this.subscription.onEvent.subscribe(this.handleEvent.bind(this));
this.subscription.onEvent.subscribe(this.handleEvent, this);
}
setQuery(query: NostrQueryWithStart) {
if (!query.since) throw new Error('Timeline requires "since" to be set in query');
this.query = query;
this.subscription.setQuery(query);
setQuery(query: NostrQuery) {
this.query = { ...query, limit: this.opts.startLimit };
this.subscription.setQuery(this.query);
}
setRelays(relays: string[]) {
@ -49,15 +45,15 @@ export class TimelineLoader {
}
private handleEvent(event: NostrEvent) {
if (!this.eventDir.has(event.id)) {
this.eventDir.set(event.id, event);
this.events.next(Array.from(this.eventDir.values()).sort((a, b) => b.created_at - a.created_at));
if (!this.seenEvents.has(event.id)) {
this.seenEvents.add(event.id);
this.events.next(utils.insertEventIntoDescendingList(Array.from(this.events.value), event));
if (this.loading.value) this.loading.next(false);
}
}
private getPageDates(page: number) {
const start = this.query.since;
const start = this.events.value[0]?.created_at ?? moment().unix();
const until = start - page * this.opts.pageSize;
const since = until - this.opts.pageSize;
@ -84,7 +80,7 @@ export class TimelineLoader {
forgetEvents() {
this.events.next([]);
this.eventDir.clear();
this.seenEvents.clear();
this.subscription.forgetEvents();
}
open() {

View File

@ -2,9 +2,11 @@ import { RelayConfig } from "../classes/relay";
import { safeRelayUrl } from "./url";
export function normalizeRelayConfigs(relays: RelayConfig[]) {
const seen: string[] = [];
return relays.reduce((newArr, r) => {
const safeUrl = safeRelayUrl(r.url);
if (safeUrl) {
if (safeUrl && !seen.includes(safeUrl)) {
seen.push(safeUrl);
newArr.push({ ...r, url: safeUrl });
}
return newArr;

View File

@ -1,13 +1,14 @@
import { useCallback, useEffect, useRef } from "react";
import { useUnmount } from "react-use";
import { NostrQueryWithStart, TimelineLoader, TimelineLoaderOptions } from "../classes/timeline-loader";
import { TimelineLoader, TimelineLoaderOptions } from "../classes/timeline-loader";
import { NostrQuery } from "../types/nostr-query";
import useSubject from "./use-subject";
type Options = TimelineLoaderOptions & {
enabled?: boolean;
};
export function useTimelineLoader(key: string, relays: string[], query: NostrQueryWithStart, opts?: Options) {
export function useTimelineLoader(key: string, relays: string[], query: NostrQuery, opts?: Options) {
if (opts && !opts.name) opts.name = key;
const ref = useRef<TimelineLoader | null>(null);

View File

@ -25,7 +25,7 @@ export default function GlobalTab() {
const { events, loading, loadMore, loader } = useTimelineLoader(
`global`,
selectedRelay ? [selectedRelay] : availableRelays,
{ kinds: [1], since: moment().unix() },
{ kinds: [1] },
{ pageSize: moment.duration(5, "minutes").asSeconds() }
);

View File

@ -45,7 +45,6 @@ const NotificationsView = () => {
{
"#p": [account.pubkey],
kinds: [1],
since: moment().subtract(1, "day").unix(),
},
{ pageSize: moment.duration(1, "day").asSeconds() }
);

View File

@ -34,16 +34,16 @@ const UserNotesTab = () => {
.filter((r) => r.mode & RelayMode.WRITE)
.map((r) => r.url);
// merge the users relays with client relays
const mergedRelays = useReadRelayUrls(userRelays);
const readRelays = useReadRelayUrls();
// find the top 4
const relays = relayScoreboardService.getRankedRelays(mergedRelays).slice(0, 4);
const relays = relayScoreboardService.getRankedRelays(userRelays.length === 0 ? readRelays : userRelays).slice(0, 4);
const { isOpen: showReplies, onToggle: toggleReplies } = useDisclosure();
const { events, loading, loadMore } = useTimelineLoader(
`${pubkey}-notes`,
relays,
{ authors: [pubkey], kinds: [1], since: moment().subtract(1, "day").unix() },
{ authors: [pubkey], kinds: [1] },
{ pageSize: moment.duration(1, "day").asSeconds() }
);
const timeline = showReplies ? events : events.filter(isNote);