mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Tier login hydration and trim DM fetch
This commit is contained in:
1 parent
83efdfcec7
commit
aad2fe465a
4 files changed
+174
-86
No files matched your search
@@ -2698,7 +2698,7 @@ class Application {
|
||||
}
|
||||
|
||||
const messageContext =
|
||||
reason === "login" && postLoginResult?.blocksLoaded !== false
|
||||
reason === "login" && postLoginResult?.blocksLoaded === true
|
||||
? "Applying your filters…"
|
||||
: "Refreshing videos…";
|
||||
|
||||
@@ -4285,56 +4285,96 @@ class Application {
|
||||
authLoadingState: this.authLoadingState,
|
||||
});
|
||||
|
||||
const dmTasks = [];
|
||||
if (activePubkey) {
|
||||
dmTasks.push(
|
||||
Promise.resolve()
|
||||
.then(() =>
|
||||
this.nostrService.loadDirectMessages({
|
||||
actorPubkey: activePubkey,
|
||||
limit: 50,
|
||||
initialLoad: true,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[Application] Failed to sync direct messages during login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}),
|
||||
);
|
||||
const accessControlReadyPromise =
|
||||
accessControl && typeof accessControl.ensureReady === "function"
|
||||
? Promise.resolve()
|
||||
.then(() => accessControl.ensureReady())
|
||||
.catch((error) => {
|
||||
userLogger.error(
|
||||
"[Application] Failed to refresh admin lists after login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
})
|
||||
: null;
|
||||
|
||||
if (typeof this.nostrService.ensureDirectMessageSubscription === "function") {
|
||||
const scheduleAfterFirstRender = () =>
|
||||
new Promise((resolve) => {
|
||||
if (typeof requestAnimationFrame === "function") {
|
||||
requestAnimationFrame(() => requestAnimationFrame(resolve));
|
||||
} else {
|
||||
setTimeout(resolve, 0);
|
||||
}
|
||||
});
|
||||
|
||||
const tier1ReadyPromise = Promise.allSettled(
|
||||
[postLoginPromise, accessControlReadyPromise].filter(Boolean),
|
||||
);
|
||||
|
||||
const startDmHydration = () => {
|
||||
const dmTasks = [];
|
||||
if (activePubkey) {
|
||||
dmTasks.push(
|
||||
Promise.resolve()
|
||||
.then(() =>
|
||||
this.nostrService.ensureDirectMessageSubscription({
|
||||
this.nostrService.loadDirectMessages({
|
||||
actorPubkey: activePubkey,
|
||||
limit: 50,
|
||||
decryptLimit: 50,
|
||||
initialLoad: true,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[Application] Failed to subscribe to direct messages during login:",
|
||||
"[Application] Failed to sync direct messages during login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const dmStatePromise = dmTasks.length
|
||||
? Promise.allSettled(dmTasks).then((results) => {
|
||||
const success = results.every(
|
||||
(result) => result.status === "fulfilled",
|
||||
if (
|
||||
typeof this.nostrService.ensureDirectMessageSubscription === "function"
|
||||
) {
|
||||
dmTasks.push(
|
||||
Promise.resolve()
|
||||
.then(() =>
|
||||
this.nostrService.ensureDirectMessageSubscription({
|
||||
actorPubkey: activePubkey,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[Application] Failed to subscribe to direct messages during login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}),
|
||||
);
|
||||
this.updateAuthLoadingState({
|
||||
dms: success ? "ready" : "error",
|
||||
});
|
||||
return success;
|
||||
})
|
||||
: Promise.resolve(this.updateAuthLoadingState({ dms: "idle" }));
|
||||
}
|
||||
}
|
||||
|
||||
return dmTasks.length
|
||||
? Promise.allSettled(dmTasks).then((results) => {
|
||||
const success = results.every(
|
||||
(result) => result.status === "fulfilled",
|
||||
);
|
||||
this.updateAuthLoadingState({
|
||||
dms: success ? "ready" : "error",
|
||||
});
|
||||
return success;
|
||||
})
|
||||
: Promise.resolve(this.updateAuthLoadingState({ dms: "idle" }));
|
||||
};
|
||||
|
||||
const dmStatePromise = tier1ReadyPromise
|
||||
.then(() => scheduleAfterFirstRender())
|
||||
.then(() => startDmHydration())
|
||||
.catch((error) => {
|
||||
devLogger.warn("[Application] Delayed DM hydration failed:", error);
|
||||
this.updateAuthLoadingState({ dms: "error" });
|
||||
return false;
|
||||
});
|
||||
|
||||
const nwcPromise = Promise.resolve()
|
||||
.then(() => this.nwcSettingsService.onLogin(loginContext))
|
||||
@@ -4382,46 +4422,32 @@ class Application {
|
||||
});
|
||||
|
||||
const listTasks = [];
|
||||
const accessControlReadyPromise =
|
||||
accessControl && typeof accessControl.ensureReady === "function"
|
||||
? Promise.resolve()
|
||||
.then(() => accessControl.ensureReady())
|
||||
.catch((error) => {
|
||||
userLogger.error(
|
||||
"[Application] Failed to refresh admin lists after login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
})
|
||||
: null;
|
||||
if (activePubkey) {
|
||||
if (activePubkey && typeof this.authService.loadBlocksForPubkey === "function") {
|
||||
listTasks.push(
|
||||
postLoginPromise.then((postLogin) => {
|
||||
const blocksLoaded = postLogin?.blocksLoaded !== false;
|
||||
const relaysLoaded = postLogin?.relaysLoaded !== false;
|
||||
if (!blocksLoaded || !relaysLoaded) {
|
||||
const listError = new Error("Post-login list hydration incomplete.");
|
||||
listError.blocksLoaded = blocksLoaded;
|
||||
listError.relaysLoaded = relaysLoaded;
|
||||
throw listError;
|
||||
}
|
||||
return { blocksLoaded, relaysLoaded };
|
||||
}),
|
||||
tier1ReadyPromise
|
||||
.then(() => this.authService.loadBlocksForPubkey(activePubkey))
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[Application] Failed to load blocks during login:",
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (accessControlReadyPromise) {
|
||||
listTasks.push(accessControlReadyPromise);
|
||||
}
|
||||
|
||||
if (
|
||||
activePubkey &&
|
||||
subscriptions &&
|
||||
typeof subscriptions.ensureLoaded === "function"
|
||||
) {
|
||||
listTasks.push(
|
||||
subscriptions
|
||||
.ensureLoaded(activePubkey, { allowPermissionPrompt: false })
|
||||
tier1ReadyPromise
|
||||
.then(() =>
|
||||
subscriptions.ensureLoaded(activePubkey, {
|
||||
allowPermissionPrompt: false,
|
||||
}),
|
||||
)
|
||||
.catch((error) => {
|
||||
devLogger.warn(
|
||||
"[Application] Failed to load subscriptions during login:",
|
||||
|
||||
+57
-20
@@ -623,7 +623,9 @@ export default class AuthService {
|
||||
postLoginError: null,
|
||||
};
|
||||
|
||||
const { detail: postLoginDetail, completionPromise } = this.applyPostLoginState();
|
||||
const { detail: postLoginDetail, completionPromise } = this.applyPostLoginState({
|
||||
deferBlocks: true,
|
||||
});
|
||||
detail.postLogin = postLoginDetail;
|
||||
|
||||
const postLoginPromise = Promise.resolve(completionPromise)
|
||||
@@ -680,13 +682,13 @@ export default class AuthService {
|
||||
return detail;
|
||||
}
|
||||
|
||||
applyPostLoginState() {
|
||||
applyPostLoginState({ deferBlocks = false } = {}) {
|
||||
const activePubkey = this.normalizeHexPubkey(getPubkey()) || getPubkey();
|
||||
const cachedEntry = activePubkey ? this.getProfileCacheEntry(activePubkey) : null;
|
||||
const cachedProfile = cachedEntry?.profile || FALLBACK_PROFILE;
|
||||
const detail = {
|
||||
pubkey: activePubkey || null,
|
||||
blocksLoaded: false,
|
||||
blocksLoaded: deferBlocks ? null : false,
|
||||
relaysLoaded: false,
|
||||
profile: cachedProfile,
|
||||
};
|
||||
@@ -699,23 +701,11 @@ export default class AuthService {
|
||||
|
||||
const operations = [];
|
||||
|
||||
if (this.userBlocks && typeof this.userBlocks.loadBlocks === "function") {
|
||||
operations.push({
|
||||
name: "blocksLoaded",
|
||||
promise: schedule(() => this.userBlocks.loadBlocks(activePubkey)),
|
||||
onFulfilled: () => true,
|
||||
onRejected: (error) => {
|
||||
this.log("[AuthService] Failed to load block list", error);
|
||||
return false;
|
||||
},
|
||||
emit: (value, error) => {
|
||||
this.emit("blocksLoaded", {
|
||||
pubkey: activePubkey,
|
||||
blocksLoaded: value,
|
||||
error: error ?? null,
|
||||
});
|
||||
},
|
||||
});
|
||||
if (!deferBlocks) {
|
||||
const blocksOperation = this.createBlocksLoadOperation(activePubkey, schedule);
|
||||
if (blocksOperation) {
|
||||
operations.push(blocksOperation);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.relayManager && typeof this.relayManager.loadRelayList === "function") {
|
||||
@@ -784,6 +774,53 @@ export default class AuthService {
|
||||
return { detail, completionPromise };
|
||||
}
|
||||
|
||||
createBlocksLoadOperation(activePubkey, schedule = (callback) => Promise.resolve().then(() => callback())) {
|
||||
if (!this.userBlocks || typeof this.userBlocks.loadBlocks !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
name: "blocksLoaded",
|
||||
promise: schedule(() => this.userBlocks.loadBlocks(activePubkey)),
|
||||
onFulfilled: () => true,
|
||||
onRejected: (error) => {
|
||||
this.log("[AuthService] Failed to load block list", error);
|
||||
return false;
|
||||
},
|
||||
emit: (value, error) => {
|
||||
this.emit("blocksLoaded", {
|
||||
pubkey: activePubkey,
|
||||
blocksLoaded: value,
|
||||
error: error ?? null,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async loadBlocksForPubkey(pubkey) {
|
||||
const normalized = this.normalizeHexPubkey(pubkey) ||
|
||||
(typeof pubkey === "string" ? pubkey.trim() : "");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const operation = this.createBlocksLoadOperation(normalized);
|
||||
if (!operation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const value = await operation.promise;
|
||||
const resolved = operation.onFulfilled(value);
|
||||
operation.emit?.(resolved, null);
|
||||
return resolved;
|
||||
} catch (error) {
|
||||
const resolved = operation.onRejected(error);
|
||||
operation.emit?.(resolved, error);
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
async logout() {
|
||||
if (this.nostrClient && typeof this.nostrClient.logout === "function") {
|
||||
try {
|
||||
|
||||
@@ -982,6 +982,8 @@ export class NostrService {
|
||||
: Number.isFinite(decryptLimitCandidate) && decryptLimitCandidate > 0
|
||||
? Math.floor(decryptLimitCandidate)
|
||||
: null;
|
||||
const sinceCandidate = Number(options.since);
|
||||
const untilCandidate = Number(options.until);
|
||||
|
||||
if (resolvedDecryptLimit && resolvedDecryptLimit > resolvedLimit) {
|
||||
resolvedDecryptLimit = resolvedLimit;
|
||||
@@ -1006,6 +1008,27 @@ export class NostrService {
|
||||
|
||||
this.dmActorPubkey = normalizedActor;
|
||||
|
||||
let resolvedSince =
|
||||
Number.isFinite(sinceCandidate) && sinceCandidate >= 0
|
||||
? Math.floor(sinceCandidate)
|
||||
: null;
|
||||
const resolvedUntil =
|
||||
Number.isFinite(untilCandidate) && untilCandidate >= 0
|
||||
? Math.floor(untilCandidate)
|
||||
: null;
|
||||
if (resolvedSince === null && initialLoad) {
|
||||
let latestTimestamp = 0;
|
||||
for (const message of Array.isArray(this.dmMessages) ? this.dmMessages : []) {
|
||||
const timestamp = Number(message?.timestamp);
|
||||
if (Number.isFinite(timestamp) && timestamp > latestTimestamp) {
|
||||
latestTimestamp = timestamp;
|
||||
}
|
||||
}
|
||||
if (latestTimestamp > 0) {
|
||||
resolvedSince = Math.max(latestTimestamp - 60, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let messages = [];
|
||||
try {
|
||||
messages = await this.nostrClient.listDirectMessages(normalizedActor, {
|
||||
@@ -1013,6 +1036,8 @@ export class NostrService {
|
||||
...options,
|
||||
limit: resolvedLimit,
|
||||
decryptLimit: resolvedDecryptLimit,
|
||||
...(resolvedSince !== null ? { since: resolvedSince } : {}),
|
||||
...(resolvedUntil !== null ? { until: resolvedUntil } : {}),
|
||||
onMessage: (message) => {
|
||||
this.applyDirectMessage(message, { reason: "load-incremental" });
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ export default class VideoListViewController {
|
||||
}
|
||||
|
||||
const messageContext =
|
||||
reason === "login" && postLoginResult?.blocksLoaded !== false
|
||||
reason === "login" && postLoginResult?.blocksLoaded === true
|
||||
? "Applying your filters…"
|
||||
: "Refreshing videos…";
|
||||
|
||||
|
||||
Reference in new issue
Block a user