2023-10-15 22:15:49 -04:00
|
|
|
"use client";
|
|
|
|
|
2023-10-15 10:58:44 -04:00
|
|
|
import { useState, useEffect } from "react";
|
|
|
|
import { useNDK } from "@/app/_providers/ndk";
|
|
|
|
import {
|
|
|
|
NDKEvent,
|
|
|
|
type NDKFilter,
|
|
|
|
type NDKSubscription,
|
|
|
|
} from "@nostr-dev-kit/ndk";
|
|
|
|
import { log } from "@/lib/utils";
|
|
|
|
import { uniqBy } from "ramda";
|
|
|
|
import { Event as NostrEvent } from "nostr-tools";
|
|
|
|
|
|
|
|
const debug = true;
|
|
|
|
type OnEventFunc = (event: NostrEvent) => void;
|
|
|
|
type OnDoneFunc = () => void;
|
|
|
|
type OnSubscribeFunc = (sub: NDKSubscription) => void;
|
|
|
|
type UseEventsProps = {
|
|
|
|
filter: NDKFilter;
|
|
|
|
enabled?: boolean;
|
|
|
|
eventFilter?: (e: NDKEvent) => boolean;
|
|
|
|
};
|
|
|
|
|
|
|
|
export default function useEvents({
|
|
|
|
filter,
|
|
|
|
enabled = true,
|
|
|
|
eventFilter = () => true,
|
|
|
|
}: UseEventsProps) {
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const [sub, setSub] = useState<NDKSubscription | undefined>(undefined);
|
|
|
|
const [events, setEvents] = useState<NDKEvent[]>([]);
|
|
|
|
const [eventIds, setEventIds] = useState<Set<string>>(new Set());
|
|
|
|
let onEventCallback: null | OnEventFunc = null;
|
|
|
|
let onSubscribeCallback: null | OnSubscribeFunc = null;
|
|
|
|
let onDoneCallback: null | OnDoneFunc = null;
|
|
|
|
const { ndk } = useNDK();
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!enabled || !ndk) return;
|
|
|
|
void init();
|
|
|
|
return () => {
|
|
|
|
console.log("STOPPING", sub);
|
|
|
|
if (sub) {
|
|
|
|
sub.stop();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, [enabled, ndk]);
|
|
|
|
|
|
|
|
async function init() {
|
|
|
|
console.log("Running init");
|
|
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
|
|
const sub = ndk!.subscribe(
|
|
|
|
{ limit: 50, ...filter },
|
|
|
|
{ closeOnEose: false },
|
|
|
|
);
|
|
|
|
setSub(sub);
|
|
|
|
onSubscribeCallback?.(sub);
|
|
|
|
sub.on("event", (e, r) => {
|
|
|
|
if (eventIds.has(e.id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (eventFilter(e)) {
|
|
|
|
setEvents((prevEvents) => {
|
|
|
|
const events = uniqBy((a) => a.id, [...prevEvents, e]);
|
|
|
|
return events.sort((a, b) => b.created_at - a.created_at);
|
|
|
|
});
|
|
|
|
setEventIds((prev) => prev.add(e.id));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (err) {
|
2023-10-18 21:55:45 -04:00
|
|
|
log("error", `❌ nostr (${err})`);
|
2023-10-15 10:58:44 -04:00
|
|
|
} finally {
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
isLoading,
|
|
|
|
events,
|
|
|
|
onEvent: (_onEventCallback: OnEventFunc) => {
|
|
|
|
if (_onEventCallback) {
|
|
|
|
onEventCallback = _onEventCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onDone: (_onDoneCallback: OnDoneFunc) => {
|
|
|
|
if (_onDoneCallback) {
|
|
|
|
onDoneCallback = _onDoneCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onSubscribe: (_onSubscribeCallback: OnSubscribeFunc) => {
|
|
|
|
if (_onSubscribeCallback) {
|
|
|
|
onSubscribeCallback = _onSubscribeCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2023-10-28 11:07:50 -04:00
|
|
|
export function useEvent({
|
|
|
|
filter,
|
|
|
|
enabled = true,
|
|
|
|
eventFilter = () => true,
|
|
|
|
}: UseEventsProps) {
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const [sub, setSub] = useState<NDKSubscription | undefined>(undefined);
|
|
|
|
const [event, setEvent] = useState<NDKEvent>();
|
|
|
|
const [eventId, setEventId] = useState<string>();
|
|
|
|
let onEventCallback: null | OnEventFunc = null;
|
|
|
|
let onSubscribeCallback: null | OnSubscribeFunc = null;
|
|
|
|
let onDoneCallback: null | OnDoneFunc = null;
|
|
|
|
const { ndk } = useNDK();
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!enabled || !ndk) return;
|
|
|
|
void init();
|
|
|
|
return () => {
|
|
|
|
console.log("STOPPING", sub);
|
|
|
|
if (sub) {
|
|
|
|
sub.stop();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}, [enabled, ndk]);
|
|
|
|
|
|
|
|
async function init() {
|
|
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
|
|
const sub = ndk!.subscribe(
|
|
|
|
{ limit: 1, ...filter },
|
|
|
|
{ closeOnEose: false },
|
|
|
|
);
|
|
|
|
setSub(sub);
|
|
|
|
onSubscribeCallback?.(sub);
|
|
|
|
sub.on("event", (e, r) => {
|
|
|
|
if (eventId === e.id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (eventFilter(e)) {
|
|
|
|
setEvent(e);
|
|
|
|
setEventId(e.id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (err) {
|
|
|
|
log("error", `❌ nostr (${err})`);
|
|
|
|
} finally {
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
isLoading,
|
|
|
|
event,
|
|
|
|
onEvent: (_onEventCallback: OnEventFunc) => {
|
|
|
|
if (_onEventCallback) {
|
|
|
|
onEventCallback = _onEventCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onDone: (_onDoneCallback: OnDoneFunc) => {
|
|
|
|
if (_onDoneCallback) {
|
|
|
|
onDoneCallback = _onDoneCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onSubscribe: (_onSubscribeCallback: OnSubscribeFunc) => {
|
|
|
|
if (_onSubscribeCallback) {
|
|
|
|
onSubscribeCallback = _onSubscribeCallback;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|