Load zap receipts for loaded photo events
This commit is contained in:
+119
-1
@@ -38,6 +38,7 @@ export default class NostrDataService extends Service {
|
|||||||
@tracked placePhotos = [];
|
@tracked placePhotos = [];
|
||||||
@tracked myContributionEvents = [];
|
@tracked myContributionEvents = [];
|
||||||
@tracked profiles = {};
|
@tracked profiles = {};
|
||||||
|
@tracked zapReceipts = {};
|
||||||
|
|
||||||
_profileSub = null;
|
_profileSub = null;
|
||||||
_mailboxesSub = null;
|
_mailboxesSub = null;
|
||||||
@@ -46,6 +47,11 @@ export default class NostrDataService extends Service {
|
|||||||
_contributionsSub = null;
|
_contributionsSub = null;
|
||||||
_profileModelSubs = new Map();
|
_profileModelSubs = new Map();
|
||||||
|
|
||||||
|
_zapReceiptsSub = null;
|
||||||
|
_zapReceiptsNetworkSub = null;
|
||||||
|
_zapRefreshTimer = null;
|
||||||
|
_lastPhotoIds = new Set();
|
||||||
|
|
||||||
_requestSub = null;
|
_requestSub = null;
|
||||||
_cachePromise = null;
|
_cachePromise = null;
|
||||||
_currentPlaceEntityId = null;
|
_currentPlaceEntityId = null;
|
||||||
@@ -87,7 +93,8 @@ export default class NostrDataService extends Service {
|
|||||||
e.kind === 5 ||
|
e.kind === 5 ||
|
||||||
e.kind === 10002 ||
|
e.kind === 10002 ||
|
||||||
e.kind === 10063 ||
|
e.kind === 10063 ||
|
||||||
e.kind === 360
|
e.kind === 360 ||
|
||||||
|
e.kind === 9735
|
||||||
);
|
);
|
||||||
|
|
||||||
if (toCache.length > 0) {
|
if (toCache.length > 0) {
|
||||||
@@ -247,7 +254,12 @@ export default class NostrDataService extends Service {
|
|||||||
this._photosSub = null;
|
this._photosSub = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._cleanupZapReceiptSubs();
|
||||||
|
this._clearZapRefreshTimer();
|
||||||
|
|
||||||
this.placePhotos = [];
|
this.placePhotos = [];
|
||||||
|
this.zapReceipts = {};
|
||||||
|
this._lastPhotoIds = new Set();
|
||||||
this._clearProfileSubs();
|
this._clearProfileSubs();
|
||||||
this._currentPlaceEntityId = entityId;
|
this._currentPlaceEntityId = entityId;
|
||||||
|
|
||||||
@@ -267,6 +279,7 @@ export default class NostrDataService extends Service {
|
|||||||
this.placePhotos = events;
|
this.placePhotos = events;
|
||||||
const pubkeys = [...new Set(events.map((e) => e.pubkey))];
|
const pubkeys = [...new Set(events.map((e) => e.pubkey))];
|
||||||
this.loadProfiles(pubkeys);
|
this.loadProfiles(pubkeys);
|
||||||
|
this._scheduleZapReceiptRefresh(events);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -500,6 +513,109 @@ export default class NostrDataService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scheduleZapReceiptRefresh(events) {
|
||||||
|
const newIds = new Set(events.map((e) => e.id));
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
if (newIds.size !== this._lastPhotoIds.size) {
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
for (const id of newIds) {
|
||||||
|
if (!this._lastPhotoIds.has(id)) {
|
||||||
|
changed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) return;
|
||||||
|
this._lastPhotoIds = newIds;
|
||||||
|
|
||||||
|
this._clearZapRefreshTimer();
|
||||||
|
this._zapRefreshTimer = setTimeout(() => {
|
||||||
|
this._zapRefreshTimer = null;
|
||||||
|
this._refreshZapReceiptSubscription([...newIds]);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearZapRefreshTimer() {
|
||||||
|
if (this._zapRefreshTimer) {
|
||||||
|
clearTimeout(this._zapRefreshTimer);
|
||||||
|
this._zapRefreshTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_refreshZapReceiptSubscription(photoIds) {
|
||||||
|
this._cleanupZapReceiptSubs();
|
||||||
|
|
||||||
|
if (!photoIds || photoIds.length === 0) return;
|
||||||
|
|
||||||
|
// Batch IDs into filters of <=100 to stay under relay REQ limits
|
||||||
|
const BATCH_SIZE = 100;
|
||||||
|
const filters = [];
|
||||||
|
for (let i = 0; i < photoIds.length; i += BATCH_SIZE) {
|
||||||
|
filters.push({
|
||||||
|
kinds: [9735],
|
||||||
|
'#e': photoIds.slice(i, i + BATCH_SIZE),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reactive local query — emits whenever matching events are in the store
|
||||||
|
this._zapReceiptsSub = this.store.timeline(filters).subscribe((events) => {
|
||||||
|
this._updateZapReceipts(events);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load from IDB cache (fire-and-forget — store.add triggers timeline)
|
||||||
|
this._cachePromise
|
||||||
|
.then(() => this.cache.query(filters))
|
||||||
|
.then((cachedEvents) => {
|
||||||
|
if (cachedEvents && cachedEvents.length > 0) {
|
||||||
|
for (const event of cachedEvents) {
|
||||||
|
this.store.add(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.warn('[nostr-data] Failed to read zap receipts from cache', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Network request (fire-and-forget)
|
||||||
|
this._zapReceiptsNetworkSub = this.nostrRelay.pool
|
||||||
|
.request(this.activeReadRelays, filters)
|
||||||
|
.subscribe({
|
||||||
|
next: (event) => {
|
||||||
|
this.store.add(event);
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('[nostr-data] Error fetching zap receipts:', err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateZapReceipts(events) {
|
||||||
|
const grouped = {};
|
||||||
|
for (const receipt of events) {
|
||||||
|
for (const tag of receipt.tags) {
|
||||||
|
if (tag[0] === 'e' && tag[1]) {
|
||||||
|
if (!grouped[tag[1]]) grouped[tag[1]] = [];
|
||||||
|
grouped[tag[1]].push(receipt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.zapReceipts = { ...this.zapReceipts, ...grouped };
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanupZapReceiptSubs() {
|
||||||
|
if (this._zapReceiptsSub) {
|
||||||
|
this._zapReceiptsSub.unsubscribe();
|
||||||
|
this._zapReceiptsSub = null;
|
||||||
|
}
|
||||||
|
if (this._zapReceiptsNetworkSub) {
|
||||||
|
this._zapReceiptsNetworkSub.unsubscribe();
|
||||||
|
this._zapReceiptsNetworkSub = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_cleanupSubscriptions() {
|
_cleanupSubscriptions() {
|
||||||
if (this._requestSub) {
|
if (this._requestSub) {
|
||||||
this._requestSub.unsubscribe();
|
this._requestSub.unsubscribe();
|
||||||
@@ -525,6 +641,8 @@ export default class NostrDataService extends Service {
|
|||||||
this._contributionsSub.unsubscribe();
|
this._contributionsSub.unsubscribe();
|
||||||
this._contributionsSub = null;
|
this._contributionsSub = null;
|
||||||
}
|
}
|
||||||
|
this._cleanupZapReceiptSubs();
|
||||||
|
this._clearZapRefreshTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
willDestroy() {
|
willDestroy() {
|
||||||
|
|||||||
Reference in New Issue
Block a user