mirror of
https://github.com/aljazceru/rabbit.git
synced 2025-12-18 14:34:25 +01:00
update
This commit is contained in:
@@ -1,36 +1,88 @@
|
||||
import { type Accessor } from 'solid-js';
|
||||
import { createSignal, createMemo, type Signal, type Accessor } from 'solid-js';
|
||||
import { type Event as NostrEvent } from 'nostr-tools/event';
|
||||
import { type CreateQueryResult } from '@tanstack/solid-query';
|
||||
import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query';
|
||||
|
||||
import useCachedEvents from '@/clients/useCachedEvents';
|
||||
import useConfig from '@/clients/useConfig';
|
||||
import useBatch, { type Task } from '@/clients/useBatch';
|
||||
import useSubscription from '@/clients/useSubscription';
|
||||
import timeout from '@/utils/timeout';
|
||||
|
||||
export type UseEventProps = {
|
||||
export type UseReactionsProps = {
|
||||
relayUrls: string[];
|
||||
eventId: string;
|
||||
};
|
||||
|
||||
export type UseEvent = {
|
||||
export type UseReactions = {
|
||||
reactions: Accessor<NostrEvent[]>;
|
||||
reactionsGroupedByContent: Accessor<Map<string, NostrEvent[]>>;
|
||||
isReactedBy(pubkey: string): boolean;
|
||||
query: CreateQueryResult<NostrEvent[]>;
|
||||
isReactedBy: (pubkey: string) => boolean;
|
||||
invalidateReactions: () => Promise<void>;
|
||||
query: CreateQueryResult<Accessor<NostrEvent[]>>;
|
||||
};
|
||||
|
||||
const useReactions = (propsProvider: () => UseEventProps): UseEvent => {
|
||||
const query = useCachedEvents(() => {
|
||||
const { relayUrls, eventId } = propsProvider();
|
||||
return {
|
||||
relayUrls,
|
||||
filters: [
|
||||
{
|
||||
'#e': [eventId],
|
||||
kinds: [7],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
const { exec } = useBatch<UseReactionsProps, Accessor<NostrEvent[]>>(() => {
|
||||
return {
|
||||
interval: 2500,
|
||||
executor: (tasks) => {
|
||||
// TODO relayUrlsを考慮する
|
||||
const [config] = useConfig();
|
||||
|
||||
const reactions = () => query.data ?? [];
|
||||
const eventIdTaskMap = new Map<string, Task<UseReactionsProps, Accessor<NostrEvent[]>>>(
|
||||
tasks.map((task) => [task.args.eventId, task]),
|
||||
);
|
||||
const eventIds = Array.from(eventIdTaskMap.keys());
|
||||
const eventIdReactionsMap = new Map<string, Signal<NostrEvent[]>>();
|
||||
|
||||
useSubscription(() => ({
|
||||
relayUrls: config().relayUrls,
|
||||
filters: [{ kinds: [7], '#e': eventIds }],
|
||||
continuous: false,
|
||||
onEvent(event: NostrEvent) {
|
||||
const reactTo = event.tags.find((e) => e[0] === 'e')?.[1];
|
||||
if (reactTo == null) return;
|
||||
const task = eventIdTaskMap.get(reactTo);
|
||||
// possibly, the new event received
|
||||
if (task == null) return;
|
||||
|
||||
const reactionsSignal =
|
||||
eventIdReactionsMap.get(reactTo) ?? createSignal<NostrEvent[]>([]);
|
||||
eventIdReactionsMap.set(reactTo, reactionsSignal);
|
||||
|
||||
const [reactions, setReactions] = reactionsSignal;
|
||||
|
||||
setReactions((currentReactions) => [...currentReactions, event]);
|
||||
|
||||
// 初回のresolveのみが有効
|
||||
task.resolve(reactions);
|
||||
},
|
||||
onEOSE() {
|
||||
tasks.forEach((task) => {
|
||||
task.resolve(() => []);
|
||||
});
|
||||
},
|
||||
}));
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const useReactions = (propsProvider: () => UseReactionsProps): UseReactions => {
|
||||
const props = createMemo(propsProvider);
|
||||
const queryKey = createMemo(() => ['useReactions', props()] as const);
|
||||
|
||||
const query = createQuery(
|
||||
() => queryKey(),
|
||||
({ queryKey, signal }) => {
|
||||
const [, currentProps] = queryKey;
|
||||
return timeout(15000, `useReactions: ${currentProps.eventId}`)(exec(currentProps, signal));
|
||||
},
|
||||
{
|
||||
// 1 minutes
|
||||
staleTime: 1 * 60 * 1000,
|
||||
cacheTime: 1 * 60 * 1000,
|
||||
},
|
||||
);
|
||||
|
||||
const reactions = () => query.data?.() ?? [];
|
||||
|
||||
const reactionsGroupedByContent = () => {
|
||||
const result = new Map<string, NostrEvent[]>();
|
||||
@@ -45,7 +97,12 @@ const useReactions = (propsProvider: () => UseEventProps): UseEvent => {
|
||||
const isReactedBy = (pubkey: string): boolean =>
|
||||
reactions().findIndex((event) => event.pubkey === pubkey) !== -1;
|
||||
|
||||
return { reactions, reactionsGroupedByContent, isReactedBy, query };
|
||||
const invalidateReactions = (): Promise<void> => {
|
||||
const queryClient = useQueryClient();
|
||||
return queryClient.invalidateQueries(queryKey());
|
||||
};
|
||||
|
||||
return { reactions, reactionsGroupedByContent, isReactedBy, invalidateReactions, query };
|
||||
};
|
||||
|
||||
export default useReactions;
|
||||
|
||||
Reference in New Issue
Block a user