Skip to content

Commit

Permalink
improve how event deletion is handled in the cache
Browse files Browse the repository at this point in the history
  • Loading branch information
pablof7z committed Dec 5, 2024
1 parent 8926079 commit 8f25984
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 16 deletions.
7 changes: 4 additions & 3 deletions ndk-cache-dexie/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NDKEvent, NDKRelay, deserialize, profileFromEvent } from "@nostr-dev-kit/ndk";
import type {
Hexpubkey,
NDKEventId,
NDKCacheAdapter,
NDKFilter,
NDKSubscription,
Expand Down Expand Up @@ -335,9 +336,9 @@ export default class NDKCacheAdapterDexie implements NDKCacheAdapter {
}
}

public async deleteEvent(event: NDKEvent): Promise<void> {
this.events.delete(event.tagId());
await db.events.where({ id: event.tagId() }).delete();
public async deleteEventIds(eventIds: NDKEventId[]): Promise<void> {
eventIds.forEach((id) => this.events.delete(id));
await db.events.where({ id: eventIds }).delete();
}

public addUnpublishedEvent = addUnpublishedEvent.bind(this);
Expand Down
9 changes: 4 additions & 5 deletions ndk-mobile/src/cache-adapter/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,13 @@ export class NDKCacheAdapterSqlite implements NDKCacheAdapter {

// if this event is a delete event, see if the deleted events are in the cache and remove them
if (event.kind === NDKKind.EventDeletion) {
const deletedEventIds = event.tags.filter((tag) => tag[0] === 'e').map((tag) => tag[1]);
await this.db.runAsync(`DELETE FROM event_tags WHERE event_id IN (${deletedEventIds.map(() => '?').join(',')});`, deletedEventIds);
this.deleteEventIds(event.tags.filter((tag) => tag[0] === 'e').map((tag) => tag[1]));
}
}

async deleteEvent(event: NDKEvent): Promise<void> {
await this.db.runAsync(`DELETE FROM events WHERE id = ?;`, [event.id]);
await this.db.runAsync(`DELETE FROM event_tags WHERE event_id = ?;`, [event.id]);
async deleteEventIds(eventIds: NDKEventId[]): Promise<void> {
await this.db.runAsync(`DELETE FROM events WHERE id IN (${eventIds.map(() => '?').join(',')});`, eventIds);
await this.db.runAsync(`DELETE FROM event_tags WHERE event_id IN (${eventIds.map(() => '?').join(',')});`, eventIds);
}

fetchProfileSync(pubkey: Hexpubkey): NDKCacheEntry<NDKUserProfile> | null {
Expand Down
16 changes: 13 additions & 3 deletions ndk-mobile/src/hooks/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface SubscribeStore<T> {
eose: boolean;
isSubscribed: boolean;
addEvent: (event: T) => void;
removeEventId: (id: string) => void;
setEose: () => void;
clearEvents: () => void;
setSubscription: (sub: NDKSubscription | undefined) => void;
Expand Down Expand Up @@ -107,6 +108,14 @@ const createSubscribeStore = <T extends NDKEvent>(bufferMs: number | false = 16)
}
},

removeEventId: (id) => {
set((state) => {
state.eventMap.delete(id);
const events = Array.from(state.eventMap.values());
return { eventMap: state.eventMap, events };
});
},

setEose: () => {
if (timeout) {
clearTimeout(timeout);
Expand All @@ -129,8 +138,6 @@ const createSubscribeStore = <T extends NDKEvent>(bufferMs: number | false = 16)
* @returns {boolean} isSubscribed - Subscription status
*/
export const useSubscribe = <T extends NDKEvent>({ filters, opts = undefined, relays = undefined }: UseSubscribeParams) => {
const ref = useRef(0);

const { ndk } = useNDK();
const muteList = useSessionStore((state) => state.muteList);
const store = useMemo(() => createSubscribeStore<T>(opts?.bufferMs), [opts?.bufferMs]);
Expand Down Expand Up @@ -189,6 +196,10 @@ export const useSubscribe = <T extends NDKEvent>({ filters, opts = undefined, re
// If we need to convert the event, we do so
if (opts?.klass) event = opts.klass.from(event);

event.once("deleted", () => {
storeInstance.removeEventId(id);
});

// If conversion failed, we bail
if (!event) return;

Expand All @@ -208,7 +219,6 @@ export const useSubscribe = <T extends NDKEvent>({ filters, opts = undefined, re

useEffect(() => {
if (!filters || filters.length === 0 || !ndk) return;
ref.current += 1;

if (storeInstance.subscriptionRef) {
storeInstance.subscriptionRef.stop();
Expand Down
4 changes: 2 additions & 2 deletions ndk/src/cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export interface NDKCacheAdapter {
/**
* Called when an event is deleted by the client.
* Cache adapters should remove the event from their cache.
* @param event - The event that was deleted.
* @param eventIds - The ids of the events that were deleted.
*/
deleteEvent?(event: NDKEvent): Promise<void>;
deleteEventIds?(eventIds: NDKEventId[]): Promise<void>;

/**
* Fetches a profile from the cache synchronously.
Expand Down
15 changes: 12 additions & 3 deletions ndk/src/events/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,9 @@ export class NDKEvent extends EventEmitter {
}

// If the published event is a delete event, notify the cache if there is one
if (this.kind === NDKKind.EventDeletion && this.ndk.cacheAdapter?.deleteEvent) {
this.ndk.cacheAdapter.deleteEvent(this);
if (this.kind === NDKKind.EventDeletion && this.ndk.cacheAdapter?.deleteEventIds) {
const eTags = this.getMatchingTags('e').map((tag) => tag[1]);
this.ndk.cacheAdapter.deleteEventIds(eTags);
}

const rawEvent = this.rawEvent();
Expand All @@ -468,6 +469,11 @@ export class NDKEvent extends EventEmitter {
}
}

// if this is a delete event, send immediately to the cache
if (this.kind === NDKKind.EventDeletion && this.ndk.cacheAdapter?.deleteEventIds) {
this.ndk.cacheAdapter.deleteEventIds(this.getMatchingTags('e').map((tag) => tag[1]));
}

// send to active subscriptions that want this event
this.ndk.subManager.subscriptions.forEach((sub) => {
if (sub.filters.some((filter) => matchFilter(filter, rawEvent as any))) {
Expand Down Expand Up @@ -738,7 +744,10 @@ export class NDKEvent extends EventEmitter {
} as NostrEvent);
e.tag(this, undefined, true);
e.tags.push(["k", this.kind!.toString()]);
if (publish) await e.publish();
if (publish) {
this.emit("deleted");
await e.publish();
}

return e;
}
Expand Down

0 comments on commit 8f25984

Please sign in to comment.