mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add fast relay fallback for list fetches
This commit is contained in:
1 parent
bcb9f13751
commit
e4ad07b2cf
3 files changed
+149
-61
No files matched your search
@@ -27,6 +27,9 @@ const HEX64_REGEX = /^[0-9a-f]{64}$/i;
|
||||
const DEFAULT_VERSION = 1;
|
||||
const DECRYPT_TIMEOUT_MS = 90000;
|
||||
const DECRYPT_RETRY_DELAY_MS = 10000;
|
||||
const FAST_RELAY_LIMIT = 3;
|
||||
const FAST_RELAY_TIMEOUT_MS = 4000;
|
||||
const FULL_RELAY_TIMEOUT_MS = 12000;
|
||||
|
||||
class TinyEventEmitter {
|
||||
constructor() {
|
||||
@@ -448,7 +451,8 @@ class HashtagPreferencesService {
|
||||
);
|
||||
}
|
||||
|
||||
async load(pubkey) {
|
||||
async load(pubkey, options = {}) {
|
||||
const { skipFastRelays = false, isBackground = false, skipCache = false } = options;
|
||||
const normalized = normalizeHexPubkey(pubkey);
|
||||
let wasLoadedForUser =
|
||||
this.activePubkey &&
|
||||
@@ -464,7 +468,7 @@ class HashtagPreferencesService {
|
||||
}
|
||||
|
||||
// Try cache first
|
||||
if (this.loadFromCache(normalized)) {
|
||||
if (!skipCache && this.loadFromCache(normalized)) {
|
||||
wasLoadedForUser = true;
|
||||
}
|
||||
|
||||
@@ -523,20 +527,43 @@ class HashtagPreferencesService {
|
||||
// If we have cached data, we ask for updates since that timestamp.
|
||||
// If we have no data, we force a full fetch (since=0).
|
||||
const since = wasLoadedForUser ? Number(this.eventCreatedAt) || 0 : 0;
|
||||
const fastRelays = relays.slice(0, FAST_RELAY_LIMIT);
|
||||
const shouldUseFastRelays =
|
||||
!skipFastRelays && fastRelays.length > 0 && fastRelays.length < relays.length;
|
||||
const initialRelays = shouldUseFastRelays ? fastRelays : relays;
|
||||
const initialTimeoutMs = shouldUseFastRelays
|
||||
? FAST_RELAY_TIMEOUT_MS
|
||||
: FULL_RELAY_TIMEOUT_MS;
|
||||
|
||||
const promises = kinds.map((kind) =>
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind,
|
||||
pubkey: normalized,
|
||||
dTag: HASHTAG_IDENTIFIER,
|
||||
relayUrls: relays,
|
||||
since,
|
||||
timeoutMs: 12000,
|
||||
}),
|
||||
);
|
||||
const fetchFromRelays = async (relayList, timeoutMs) => {
|
||||
const promises = kinds.map((kind) =>
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind,
|
||||
pubkey: normalized,
|
||||
dTag: HASHTAG_IDENTIFIER,
|
||||
relayUrls: relayList,
|
||||
since,
|
||||
timeoutMs,
|
||||
}),
|
||||
);
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
events = results.flat();
|
||||
const results = await Promise.all(promises);
|
||||
return results.flat();
|
||||
};
|
||||
|
||||
events = await fetchFromRelays(initialRelays, initialTimeoutMs);
|
||||
if (!events.length && shouldUseFastRelays && !isBackground) {
|
||||
devLogger.log(
|
||||
`${LOG_PREFIX} Fast relay fetch returned no events; continuing in background.`,
|
||||
);
|
||||
this.load(normalized, {
|
||||
skipFastRelays: true,
|
||||
isBackground: true,
|
||||
skipCache: true,
|
||||
}).catch((error) => {
|
||||
devLogger.warn(`${LOG_PREFIX} Background refresh failed`, error);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
fetchError = error;
|
||||
|
||||
+61
-26
@@ -38,6 +38,9 @@ const SUBSCRIPTION_SET_KIND =
|
||||
getNostrEventSchema(NOTE_TYPES.SUBSCRIPTION_LIST)?.kind ?? 30000;
|
||||
const DECRYPT_TIMEOUT_MS = 90000;
|
||||
const DECRYPT_RETRY_DELAY_MS = 10000;
|
||||
const FAST_RELAY_LIMIT = 3;
|
||||
const FAST_RELAY_TIMEOUT_MS = 4000;
|
||||
const FULL_RELAY_TIMEOUT_MS = 12000;
|
||||
|
||||
function normalizeHexPubkey(value) {
|
||||
if (typeof value !== "string") {
|
||||
@@ -448,14 +451,16 @@ class SubscriptionsManager {
|
||||
);
|
||||
}
|
||||
|
||||
async updateFromRelays(userPubkey) {
|
||||
async updateFromRelays(userPubkey, options = {}) {
|
||||
if (!userPubkey) return;
|
||||
|
||||
try {
|
||||
const normalizedUserPubkey = normalizeHexPubkey(userPubkey) || userPubkey;
|
||||
const { relayUrlsOverride, skipFastRelays = false, isBackground = false } = options;
|
||||
|
||||
const readRelays = relayManager.getReadRelayUrls();
|
||||
const relayUrls = readRelays.length > 0 ? readRelays : Array.from(DEFAULT_RELAY_URLS);
|
||||
const fallbackRelayUrls = readRelays.length > 0 ? readRelays : Array.from(DEFAULT_RELAY_URLS);
|
||||
const relayUrls = relayUrlsOverride?.length ? relayUrlsOverride : fallbackRelayUrls;
|
||||
if (!relayUrls.length) {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] No relay URLs available while loading subscriptions.",
|
||||
@@ -463,45 +468,75 @@ class SubscriptionsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const fastRelayUrls = relayUrls.slice(0, FAST_RELAY_LIMIT);
|
||||
const shouldUseFastRelays =
|
||||
!skipFastRelays && fastRelayUrls.length > 0 && fastRelayUrls.length < relayUrls.length;
|
||||
const initialRelayUrls = shouldUseFastRelays ? fastRelayUrls : relayUrls;
|
||||
const initialTimeoutMs = shouldUseFastRelays
|
||||
? FAST_RELAY_TIMEOUT_MS
|
||||
: FULL_RELAY_TIMEOUT_MS;
|
||||
|
||||
// Use incremental fetch helper
|
||||
const cachedSnapshot = parseCachedSubscriptionSnapshot(
|
||||
profileCache.getProfileData(normalizedUserPubkey, "subscriptions"),
|
||||
);
|
||||
const shouldForceFullFetch = !cachedSnapshot.hasSnapshot;
|
||||
let events = await nostrClient.fetchListIncrementally({
|
||||
kind: SUBSCRIPTION_SET_KIND,
|
||||
pubkey: normalizedUserPubkey,
|
||||
dTag: SUBSCRIPTION_LIST_IDENTIFIER,
|
||||
relayUrls,
|
||||
since: shouldForceFullFetch ? 0 : undefined,
|
||||
timeoutMs: 12000,
|
||||
});
|
||||
|
||||
const normalizedSessionActorPubkey = normalizeNostrPubkey(
|
||||
nostrClient?.sessionActor?.pubkey,
|
||||
);
|
||||
const shouldFetchSessionActor =
|
||||
normalizedSessionActorPubkey &&
|
||||
normalizedSessionActorPubkey !== normalizedUserPubkey;
|
||||
if (shouldFetchSessionActor) {
|
||||
const sessionCachedSnapshot = parseCachedSubscriptionSnapshot(
|
||||
profileCache.getProfileData(
|
||||
normalizedSessionActorPubkey,
|
||||
"subscriptions",
|
||||
),
|
||||
);
|
||||
const shouldForceSessionFetch = !sessionCachedSnapshot.hasSnapshot;
|
||||
const sessionEvents = await nostrClient.fetchListIncrementally({
|
||||
|
||||
const fetchFromRelays = async (relayList, timeoutMs) => {
|
||||
let events = await nostrClient.fetchListIncrementally({
|
||||
kind: SUBSCRIPTION_SET_KIND,
|
||||
pubkey: normalizedSessionActorPubkey,
|
||||
pubkey: normalizedUserPubkey,
|
||||
dTag: SUBSCRIPTION_LIST_IDENTIFIER,
|
||||
relayUrls,
|
||||
since: shouldForceSessionFetch ? 0 : undefined,
|
||||
timeoutMs: 12000,
|
||||
relayUrls: relayList,
|
||||
since: shouldForceFullFetch ? 0 : undefined,
|
||||
timeoutMs,
|
||||
});
|
||||
if (sessionEvents.length) {
|
||||
events = events.concat(sessionEvents);
|
||||
|
||||
if (shouldFetchSessionActor) {
|
||||
const sessionCachedSnapshot = parseCachedSubscriptionSnapshot(
|
||||
profileCache.getProfileData(
|
||||
normalizedSessionActorPubkey,
|
||||
"subscriptions",
|
||||
),
|
||||
);
|
||||
const shouldForceSessionFetch = !sessionCachedSnapshot.hasSnapshot;
|
||||
const sessionEvents = await nostrClient.fetchListIncrementally({
|
||||
kind: SUBSCRIPTION_SET_KIND,
|
||||
pubkey: normalizedSessionActorPubkey,
|
||||
dTag: SUBSCRIPTION_LIST_IDENTIFIER,
|
||||
relayUrls: relayList,
|
||||
since: shouldForceSessionFetch ? 0 : undefined,
|
||||
timeoutMs,
|
||||
});
|
||||
if (sessionEvents.length) {
|
||||
events = events.concat(sessionEvents);
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
};
|
||||
|
||||
let events = await fetchFromRelays(initialRelayUrls, initialTimeoutMs);
|
||||
if (!events.length && shouldUseFastRelays && !isBackground) {
|
||||
devLogger.log(
|
||||
"[SubscriptionsManager] Fast relay fetch returned no events; continuing in background.",
|
||||
);
|
||||
this.updateFromRelays(normalizedUserPubkey, {
|
||||
relayUrlsOverride: relayUrls,
|
||||
skipFastRelays: true,
|
||||
isBackground: true,
|
||||
}).catch((error) => {
|
||||
devLogger.warn(
|
||||
"[SubscriptionsManager] Background relay refresh failed:",
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const mergedEvents = [];
|
||||
|
||||
+47
-21
@@ -73,7 +73,7 @@ export const USER_BLOCK_EVENTS = Object.freeze({
|
||||
|
||||
const FAST_BLOCKLIST_RELAY_LIMIT = 3;
|
||||
const FAST_BLOCKLIST_TIMEOUT_MS = 2500;
|
||||
const BACKGROUND_BLOCKLIST_TIMEOUT_MS = 6000;
|
||||
const FULL_BLOCKLIST_TIMEOUT_MS = 12000;
|
||||
const DECRYPT_TIMEOUT_MS = 90000;
|
||||
const DECRYPT_RETRY_DELAY_MS = 10000;
|
||||
|
||||
@@ -751,28 +751,39 @@ class UserBlockListManager {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
statusCallback?.(detail);
|
||||
} catch (callbackError) {
|
||||
userLogger.warn(
|
||||
"[UserBlockList] statusCallback threw while emitting status",
|
||||
callbackError,
|
||||
);
|
||||
}
|
||||
if (!options.isBackground) {
|
||||
try {
|
||||
statusCallback?.(detail);
|
||||
} catch (callbackError) {
|
||||
userLogger.warn(
|
||||
"[UserBlockList] statusCallback threw while emitting status",
|
||||
callbackError,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
this.emitter.emit(USER_BLOCK_EVENTS.STATUS, detail);
|
||||
} catch (emitterError) {
|
||||
userLogger.warn(
|
||||
"[UserBlockList] Failed to dispatch status event",
|
||||
emitterError,
|
||||
);
|
||||
try {
|
||||
this.emitter.emit(USER_BLOCK_EVENTS.STATUS, detail);
|
||||
} catch (emitterError) {
|
||||
userLogger.warn(
|
||||
"[UserBlockList] Failed to dispatch status event",
|
||||
emitterError,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const readRelays = relayManager.getReadRelayUrls();
|
||||
const relays = readRelays.length > 0 ? readRelays : Array.from(DEFAULT_RELAY_URLS);
|
||||
emitStatus({ status: "loading", relays });
|
||||
const fastRelays = relays.slice(0, FAST_BLOCKLIST_RELAY_LIMIT);
|
||||
const shouldUseFastRelays =
|
||||
!options.skipFastRelays &&
|
||||
fastRelays.length > 0 &&
|
||||
fastRelays.length < relays.length;
|
||||
const initialRelays = shouldUseFastRelays ? fastRelays : relays;
|
||||
const initialTimeoutMs = shouldUseFastRelays
|
||||
? FAST_BLOCKLIST_TIMEOUT_MS
|
||||
: FULL_BLOCKLIST_TIMEOUT_MS;
|
||||
emitStatus({ status: "loading", relays: initialRelays });
|
||||
|
||||
const localBlocks = this._loadLocal(normalized);
|
||||
const hasLocalData = !!localBlocks;
|
||||
@@ -1206,17 +1217,17 @@ class UserBlockListManager {
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind: 10000,
|
||||
pubkey: normalized,
|
||||
relayUrls: relays,
|
||||
relayUrls: initialRelays,
|
||||
since: fetchSince,
|
||||
timeoutMs: 12000,
|
||||
timeoutMs: initialTimeoutMs,
|
||||
}),
|
||||
nostrClient.fetchListIncrementally({
|
||||
kind: 10000,
|
||||
pubkey: normalized,
|
||||
dTag: BLOCK_LIST_IDENTIFIER,
|
||||
relayUrls: relays,
|
||||
relayUrls: initialRelays,
|
||||
since: fetchSince,
|
||||
timeoutMs: 12000,
|
||||
timeoutMs: initialTimeoutMs,
|
||||
}),
|
||||
]);
|
||||
|
||||
@@ -1224,6 +1235,21 @@ class UserBlockListManager {
|
||||
|
||||
// If combined is empty, check if we have loaded state
|
||||
if (!combined.length) {
|
||||
if (shouldUseFastRelays && !options.isBackground) {
|
||||
devLogger.log(
|
||||
"[UserBlockList] Fast relay fetch returned no events; continuing in background.",
|
||||
);
|
||||
this.loadBlocks(normalized, {
|
||||
...options,
|
||||
skipFastRelays: true,
|
||||
isBackground: true,
|
||||
}).catch((error) => {
|
||||
devLogger.warn(
|
||||
"[UserBlockList] Background relay refresh failed:",
|
||||
error,
|
||||
);
|
||||
});
|
||||
}
|
||||
if (!this.loaded) {
|
||||
// Assuming empty if we have no prior state
|
||||
await applyEvents([], { source: "incremental" });
|
||||
|
||||
Reference in new issue
Block a user