mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-05 12:22:28 +00:00
Optimize channel profile event lookup with author index
- Replaced `NostrClient.rawEvents` standard Map with `EventsMap` - Implemented `EventsMap` to maintain an author-based index - Updated `js/channelProfile.js` to use `getEventsByAuthor` for efficient lookup - Added unit tests for `EventsMap` - Added benchmark script verifying ~15x performance improvement (637ms -> 41ms for 1M events) Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
566c2dbf89
commit
67aa8ad2aa
5 files changed
+282
-5
No files matched your search
+17
-4
@@ -4366,10 +4366,23 @@ function getCachedChannelVideoEvents(pubkey) {
|
||||
};
|
||||
|
||||
const rawMatches = collectMatches(nostrClient?.rawEvents, (callback) => {
|
||||
if (
|
||||
nostrClient?.rawEvents &&
|
||||
typeof nostrClient.rawEvents.forEach === "function"
|
||||
) {
|
||||
if (!nostrClient?.rawEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof nostrClient.rawEvents.getEventsByAuthor === "function") {
|
||||
const candidates = nostrClient.rawEvents.getEventsByAuthor(normalized);
|
||||
if (Array.isArray(candidates)) {
|
||||
candidates.forEach((event) => {
|
||||
if (event?.kind === 30078) {
|
||||
callback(event);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof nostrClient.rawEvents.forEach === "function") {
|
||||
nostrClient.rawEvents.forEach((event) => {
|
||||
if (event?.kind === 30078) {
|
||||
callback(event);
|
||||
|
||||
+2
-1
@@ -203,6 +203,7 @@ import { createNip07Adapter } from "./adapters/nip07Adapter.js";
|
||||
import { createNsecAdapter } from "./adapters/nsecAdapter.js";
|
||||
import { createNip46Adapter } from "./adapters/nip46Adapter.js";
|
||||
import { queueSignEvent } from "./signRequestQueue.js";
|
||||
import { EventsMap } from "./eventsMap.js";
|
||||
|
||||
function normalizeProfileFromEvent(event) {
|
||||
if (!event || !event.content) return null;
|
||||
@@ -1271,7 +1272,7 @@ export class NostrClient {
|
||||
* Kept for signature verification and republishing (e.g. NIP-94 mirror).
|
||||
* @public
|
||||
*/
|
||||
this.rawEvents = new Map();
|
||||
this.rawEvents = new EventsMap();
|
||||
|
||||
/**
|
||||
* @type {Map<string, object>}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* A Map extension that maintains an author-based index for fast lookups.
|
||||
* Used for `rawEvents` in NostrClient.
|
||||
*/
|
||||
export class EventsMap extends Map {
|
||||
constructor(entries) {
|
||||
super(entries);
|
||||
this.authorIndex = new Map(); // pubkey -> Set<Event>
|
||||
|
||||
// If entries provided, index them
|
||||
if (entries) {
|
||||
for (const [key, value] of this.entries()) {
|
||||
this._addToIndex(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_normalizePubkey(pubkey) {
|
||||
if (typeof pubkey !== "string") return "";
|
||||
return pubkey.trim().toLowerCase();
|
||||
}
|
||||
|
||||
_addToIndex(event) {
|
||||
if (!event || typeof event !== "object") return;
|
||||
const pubkey = this._normalizePubkey(event.pubkey);
|
||||
if (!pubkey) return;
|
||||
|
||||
let set = this.authorIndex.get(pubkey);
|
||||
if (!set) {
|
||||
set = new Set();
|
||||
this.authorIndex.set(pubkey, set);
|
||||
}
|
||||
set.add(event);
|
||||
}
|
||||
|
||||
_removeFromIndex(event) {
|
||||
if (!event || typeof event !== "object") return;
|
||||
const pubkey = this._normalizePubkey(event.pubkey);
|
||||
if (!pubkey) return;
|
||||
|
||||
const set = this.authorIndex.get(pubkey);
|
||||
if (set) {
|
||||
set.delete(event);
|
||||
if (set.size === 0) {
|
||||
this.authorIndex.delete(pubkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
const existing = this.get(key);
|
||||
// If the value is identical, we still set it in the map,
|
||||
// but the index doesn't strictly need updating.
|
||||
// However, if the key was mapped to a DIFFERENT object with the SAME pubkey,
|
||||
// we must update the Set (remove old object, add new object).
|
||||
if (existing) {
|
||||
if (existing === value) {
|
||||
// No index change needed
|
||||
return super.set(key, value);
|
||||
}
|
||||
this._removeFromIndex(existing);
|
||||
}
|
||||
|
||||
super.set(key, value);
|
||||
this._addToIndex(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const value = this.get(key);
|
||||
const result = super.delete(key);
|
||||
if (result && value) {
|
||||
this._removeFromIndex(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
clear() {
|
||||
super.clear();
|
||||
this.authorIndex.clear();
|
||||
}
|
||||
|
||||
getEventsByAuthor(pubkey) {
|
||||
const normalized = this._normalizePubkey(pubkey);
|
||||
if (!normalized) return [];
|
||||
const set = this.authorIndex.get(normalized);
|
||||
// Return array to allow iteration
|
||||
return set ? Array.from(set) : [];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user