nostr-idb 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # nostr-idb
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 55e853c: Add in memory eventMap to relay core
8
+
3
9
  ## 2.0.1
4
10
 
5
11
  ### Patch Changes
@@ -2,6 +2,7 @@ import { type Filter, type NostrEvent } from "nostr-tools";
2
2
  import { NostrIDB } from "../database/schema.js";
3
3
  export declare class WriteQueue {
4
4
  db: NostrIDB;
5
+ private queuedIds;
5
6
  private eventQueue;
6
7
  private lastUsedQueue;
7
8
  constructor(db: NostrIDB);
@@ -1,21 +1,28 @@
1
1
  import { matchFilters } from "nostr-tools";
2
2
  import { addEvents, getEventUID, updateUsed } from "../database/ingest.js";
3
3
  import { logger } from "../debug.js";
4
- const log = logger.extend("cache:write");
4
+ const log = logger.extend("writeQueue");
5
5
  export class WriteQueue {
6
6
  db;
7
+ queuedIds = new Set();
7
8
  eventQueue = [];
8
9
  lastUsedQueue = new Set();
9
10
  constructor(db) {
10
11
  this.db = db;
11
12
  }
12
13
  addEvent(event) {
14
+ if (this.queuedIds.has(event.id))
15
+ return;
13
16
  this.eventQueue.push(event);
17
+ this.queuedIds.add(event.id);
14
18
  this.useEvent(event);
15
19
  }
16
20
  addEvents(events) {
17
- this.eventQueue.push(...events);
18
- this.useEvents(events);
21
+ const arr = events.filter((e) => !this.queuedIds.has(e.id));
22
+ if (arr.length === 0)
23
+ return;
24
+ this.eventQueue.push(...arr);
25
+ this.useEvents(arr);
19
26
  }
20
27
  useEvent(event) {
21
28
  this.lastUsedQueue.add(getEventUID(event));
@@ -35,9 +42,10 @@ export class WriteQueue {
35
42
  if (!event)
36
43
  break;
37
44
  events.push(event);
45
+ this.queuedIds.delete(event.id);
38
46
  }
39
47
  await addEvents(this.db, events);
40
- log(`Wrote ${events.length} to database,${this.eventQueue.length} left`);
48
+ log(`Wrote ${events.length} to database ${this.eventQueue.length} events left`);
41
49
  }
42
50
  if (this.lastUsedQueue.size > 0) {
43
51
  await updateUsed(this.db, this.lastUsedQueue);
@@ -1,4 +1,4 @@
1
- import type { Event, Filter } from "nostr-tools";
1
+ import type { Event, Filter, NostrEvent } from "nostr-tools";
2
2
  import type { NostrIDB } from "./schema.js";
3
3
  import { IndexCache } from "../cache/index-cache.js";
4
4
  export declare function queryForPubkeys(db: NostrIDB, authors?: Filter["authors"], indexCache?: IndexCache): Set<string> | Promise<Set<string>>;
@@ -7,7 +7,7 @@ export declare function queryForKinds(db: NostrIDB, kinds?: Filter["kinds"], ind
7
7
  export declare function queryForTime(db: NostrIDB, since: number | undefined, until: number | undefined): Promise<string[]>;
8
8
  export declare function getIdsForFilter(db: NostrIDB, filter: Filter, indexCache?: IndexCache): Promise<Set<string>>;
9
9
  export declare function getIdsForFilters(db: NostrIDB, filters: Filter[], indexCache?: IndexCache): Promise<Set<string>>;
10
- export declare function getEventsForFilter(db: NostrIDB, filter: Filter, indexCache?: IndexCache): Promise<Event[]>;
11
- export declare function getEventsForFilters(db: NostrIDB, filters: Filter[], indexCache?: IndexCache): Promise<Event[]>;
10
+ export declare function getEventsForFilter(db: NostrIDB, filter: Filter, indexCache?: IndexCache, eventMap?: Map<string, NostrEvent>): Promise<Event[]>;
11
+ export declare function getEventsForFilters(db: NostrIDB, filters: Filter[], indexCache?: IndexCache, eventMap?: Map<string, NostrEvent>): Promise<Event[]>;
12
12
  export declare function countEventsForFilter(db: NostrIDB, filter: Filter, indexCache?: IndexCache): Promise<number>;
13
13
  export declare function countEventsForFilters(db: NostrIDB, filters: Filter[], indexCache?: IndexCache): Promise<number>;
@@ -174,12 +174,25 @@ export async function getIdsForFilters(db, filters, indexCache) {
174
174
  }
175
175
  return ids;
176
176
  }
177
- async function loadEventsByUID(db, uids, filters) {
177
+ async function loadEventsByUID(db, uids, filters, eventMap) {
178
178
  const eventBuffer = [];
179
+ // load from in-memory event map
180
+ let remainingIds = [];
181
+ if (eventMap) {
182
+ for (const uid of uids) {
183
+ const event = eventMap.get(uid);
184
+ if (event)
185
+ eventBuffer.push(event);
186
+ else
187
+ remainingIds.push(uid);
188
+ }
189
+ }
190
+ else
191
+ remainingIds = uids;
179
192
  const trans = db.transaction("events", "readonly");
180
193
  const objectStore = trans.objectStore("events");
181
194
  const handleEntry = (e) => e && eventBuffer.push(e.event);
182
- const promises = Array.from(uids).map((uid) => objectStore.get(uid).then(handleEntry));
195
+ const promises = Array.from(remainingIds).map((uid) => objectStore.get(uid).then(handleEntry));
183
196
  trans.commit();
184
197
  const sorted = await Promise.all(promises).then(() => eventBuffer.sort(sortByDate));
185
198
  let minLimit = Infinity;
@@ -191,13 +204,13 @@ async function loadEventsByUID(db, uids, filters) {
191
204
  sorted.length = minLimit;
192
205
  return sorted;
193
206
  }
194
- export async function getEventsForFilter(db, filter, indexCache) {
207
+ export async function getEventsForFilter(db, filter, indexCache, eventMap) {
195
208
  const ids = await getIdsForFilter(db, filter, indexCache);
196
- return await loadEventsByUID(db, Array.from(ids), [filter]);
209
+ return await loadEventsByUID(db, Array.from(ids), [filter], eventMap);
197
210
  }
198
- export async function getEventsForFilters(db, filters, indexCache) {
211
+ export async function getEventsForFilters(db, filters, indexCache, eventMap) {
199
212
  const ids = await getIdsForFilters(db, filters, indexCache);
200
- return await loadEventsByUID(db, Array.from(ids), filters);
213
+ return await loadEventsByUID(db, Array.from(ids), filters, eventMap);
201
214
  }
202
215
  export async function countEventsForFilter(db, filter, indexCache) {
203
216
  const ids = await getIdsForFilter(db, filter, indexCache);
@@ -29,6 +29,7 @@ export declare class RelayCore {
29
29
  private writeInterval?;
30
30
  private pruneInterval?;
31
31
  get running(): boolean;
32
+ private eventMap;
32
33
  private writeQueue;
33
34
  private indexCache;
34
35
  db: NostrIDB;
@@ -38,6 +39,7 @@ export declare class RelayCore {
38
39
  stop(): Promise<void>;
39
40
  publish(event: Event): Promise<string>;
40
41
  count(filters: Filter[]): Promise<number>;
42
+ private addToEventMaps;
41
43
  private executeSubscription;
42
44
  subscribe(filters: Filter[], options: Partial<SubscriptionOptions>): Subscription;
43
45
  unsubscribe(id: string): void;
@@ -5,7 +5,7 @@ import { getEventsForFilters, countEventsForFilters, } from "../database/query-f
5
5
  import { sortByDate } from "../utils.js";
6
6
  import { nanoid } from "../lib/nanoid.js";
7
7
  import { logger } from "../debug.js";
8
- import { pruneLastUsed } from "../index.js";
8
+ import { getEventUID, pruneLastUsed } from "../index.js";
9
9
  const defaultOptions = {
10
10
  batchWrite: 1000,
11
11
  writeInterval: 100,
@@ -22,6 +22,7 @@ export class RelayCore {
22
22
  get running() {
23
23
  return !!this.writeInterval;
24
24
  }
25
+ eventMap = new Map();
25
26
  writeQueue;
26
27
  indexCache;
27
28
  db;
@@ -57,6 +58,7 @@ export class RelayCore {
57
58
  if (!kinds.isEphemeralKind(event.kind)) {
58
59
  this.writeQueue.addEvent(event);
59
60
  this.indexCache.addEventToIndexes(event);
61
+ this.eventMap.set(getEventUID(event), event);
60
62
  }
61
63
  let subs = 0;
62
64
  for (const [id, sub] of this.subscriptions) {
@@ -70,13 +72,18 @@ export class RelayCore {
70
72
  async count(filters) {
71
73
  return await countEventsForFilters(this.db, filters);
72
74
  }
75
+ addToEventMaps(events) {
76
+ for (const event of events)
77
+ this.eventMap.set(getEventUID(event), event);
78
+ }
73
79
  async executeSubscription(sub) {
74
80
  const start = new Date().valueOf();
75
81
  log(`Running ${sub.id}`, sub.filters);
76
82
  // load any events from the write queue
77
83
  const eventsFromQueue = this.writeQueue.matchPending(sub.filters);
78
84
  // get events
79
- await getEventsForFilters(this.db, sub.filters, this.indexCache).then((filterEvents) => {
85
+ await getEventsForFilters(this.db, sub.filters, this.indexCache, this.eventMap).then((filterEvents) => {
86
+ this.addToEventMaps(filterEvents);
80
87
  if (sub.onevent) {
81
88
  const idsFromQueue = new Set(eventsFromQueue.map((e) => e.id));
82
89
  const events = eventsFromQueue.length > 0