Skip to content

Commit 4adc133

Browse files
perf(solid): cache Pod URL in session to avoid repeated profile requests
1 parent 2dd61dd commit 4adc133

1 file changed

Lines changed: 42 additions & 24 deletions

File tree

api/server/services/SolidStorage.js

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,36 @@ async function getPodUrl(webId, fetch) {
394394
}
395395
}
396396

397+
/**
398+
* Get authenticated fetch and Pod URL for the current Solid user, with session cache.
399+
* Pod URL is fetched once per session (e.g. at first use after login) to avoid repeated profile requests.
400+
*
401+
* @param {Object} req - Express request (must have req.user.openidId and session)
402+
* @returns {Promise<{ authenticatedFetch: Function, podUrl: string }>}
403+
*/
404+
async function getSolidFetchAndPodUrl(req) {
405+
const openidId = req?.user?.openidId;
406+
if (!openidId) {
407+
throw new Error('User not authenticated with Solid/OpenID');
408+
}
409+
410+
const cached =
411+
req.session?.solidCachedPodUrlWebId === openidId && req.session?.solidCachedPodUrl;
412+
if (cached) {
413+
const authenticatedFetch = await getSolidFetch(req);
414+
logger.debug('[SolidStorage] Using cached Pod URL from session', { openidId });
415+
return { authenticatedFetch, podUrl: req.session.solidCachedPodUrl };
416+
}
417+
418+
const authenticatedFetch = await getSolidFetch(req);
419+
const podUrl = await getPodUrl(openidId, authenticatedFetch);
420+
if (req.session) {
421+
req.session.solidCachedPodUrl = podUrl;
422+
req.session.solidCachedPodUrlWebId = openidId;
423+
}
424+
return { authenticatedFetch, podUrl };
425+
}
426+
397427
/**
398428
* Get base storage path for LibreChat data in Pod
399429
*
@@ -574,8 +604,7 @@ async function ensureBaseStructureReady(req) {
574604
}
575605
let promise = baseStructureBatonMap.get(openidId);
576606
if (!promise) {
577-
const authenticatedFetch = await getSolidFetch(req);
578-
const podUrl = await getPodUrl(openidId, authenticatedFetch);
607+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
579608
promise = ensureBaseStructure(podUrl, authenticatedFetch).catch((err) => {
580609
baseStructureBatonMap.delete(openidId);
581610
throw err;
@@ -600,8 +629,7 @@ function startBaseStructureAfterLogin(req) {
600629

601630
const promise = (async () => {
602631
try {
603-
const authenticatedFetch = await getSolidFetch(req);
604-
const podUrl = await getPodUrl(openidId, authenticatedFetch);
632+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
605633
await ensureBaseStructure(podUrl, authenticatedFetch);
606634
logger.debug('[SolidStorage] Base structure ready after login', { openidId });
607635
} catch (err) {
@@ -645,8 +673,7 @@ async function saveMessageToSolid(req, messageDocument, metadata) {
645673
}
646674

647675
await ensureBaseStructureReady(req);
648-
const authenticatedFetch = await getSolidFetch(req);
649-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
676+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
650677

651678
const messagesContainerPath = getMessagesContainerPath(podUrl, messageDocument.conversationId);
652679
await ensureContainerExists(messagesContainerPath, authenticatedFetch);
@@ -743,8 +770,7 @@ async function getMessagesFromSolid(req, conversationId) {
743770
}
744771

745772
// Get authenticated fetch and Pod URL
746-
const authenticatedFetch = await getSolidFetch(req);
747-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
773+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
748774

749775
// Get messages container path
750776
const messagesContainerPath = getMessagesContainerPath(podUrl, conversationId);
@@ -919,8 +945,7 @@ async function updateMessageInSolid(req, messageData, metadata) {
919945
}
920946

921947
// Get authenticated fetch and Pod URL
922-
const authenticatedFetch = await getSolidFetch(req);
923-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
948+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
924949

925950
// First, try to get the existing message to merge updates
926951
let existingMessage = null;
@@ -1124,8 +1149,7 @@ async function deleteMessagesFromSolid(req, params) {
11241149
}
11251150

11261151
// Get authenticated fetch and Pod URL
1127-
const authenticatedFetch = await getSolidFetch(req);
1128-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
1152+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
11291153

11301154
// Get messages container path
11311155
const _messagesContainerPath = getMessagesContainerPath(podUrl, params.conversationId);
@@ -1271,8 +1295,7 @@ async function saveConvoToSolid(req, convoDocument, metadata) {
12711295
}
12721296

12731297
await ensureBaseStructureReady(req);
1274-
const authenticatedFetch = await getSolidFetch(req);
1275-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
1298+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
12761299

12771300
const conversationPath = getConversationPath(podUrl, finalConversationId);
12781301

@@ -1421,8 +1444,7 @@ async function getConvoFromSolid(req, conversationId) {
14211444
}
14221445

14231446
// Get authenticated fetch and Pod URL
1424-
const authenticatedFetch = await getSolidFetch(req);
1425-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
1447+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
14261448

14271449
// Get conversation file path
14281450
const conversationPath = getConversationPath(podUrl, conversationId);
@@ -1640,9 +1662,8 @@ async function getConvosByCursorFromSolid(req, options = {}) {
16401662
const finalSortDirection = sortDirection === 'asc' ? 'asc' : 'desc';
16411663

16421664
// Get authenticated fetch and Pod URL
1643-
const authenticatedFetch = await getSolidFetch(req);
1665+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
16441666
// TODO: Allow user to select their storage (can happen after the initial PR).
1645-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
16461667

16471668
// Get conversations container path
16481669
const conversationsContainerPath = `${getBaseStoragePath(podUrl)}conversations/`;
@@ -1967,8 +1988,7 @@ async function deleteConvosFromSolid(req, conversationIds) {
19671988
}
19681989

19691990
// Get authenticated fetch and Pod URL
1970-
const authenticatedFetch = await getSolidFetch(req);
1971-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
1991+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
19721992

19731993
let deletedCount = 0;
19741994

@@ -2548,8 +2568,7 @@ async function setPublicAccessForShare(req, conversationId) {
25482568
}
25492569

25502570
// Get authenticated fetch and Pod URL
2551-
const authenticatedFetch = await getSolidFetch(req);
2552-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
2571+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
25532572

25542573
// Get conversation file path
25552574
const conversationPath = getConversationPath(podUrl, conversationId);
@@ -2717,8 +2736,7 @@ async function removePublicAccessForShare(req, conversationId) {
27172736
}
27182737

27192738
// Get authenticated fetch and Pod URL
2720-
const authenticatedFetch = await getSolidFetch(req);
2721-
const podUrl = await getPodUrl(req.user.openidId, authenticatedFetch);
2739+
const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req);
27222740

27232741
// Get conversation file path
27242742
const conversationPath = getConversationPath(podUrl, conversationId);

0 commit comments

Comments
 (0)