From 5a3b4cfcb4e582e302526a3e18bcb476b584ccf8 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 5 Oct 2022 12:10:15 +0200 Subject: [PATCH] MOBILE-3817 core: Split ongoing requests in 2 types --- src/core/classes/site.ts | 91 +++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 16 deletions(-) diff --git a/src/core/classes/site.ts b/src/core/classes/site.ts index c8781f9f7..a252ec3af 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/site.ts @@ -125,7 +125,7 @@ export class CoreSite { protected lastAutoLogin = 0; protected offlineDisabled = false; // eslint-disable-next-line @typescript-eslint/no-explicit-any - protected ongoingRequests: { [cacheId: string]: WSObservable } = {}; + protected ongoingRequests: Record | undefined>> = {}; protected requestQueue: RequestQueueItem[] = []; protected requestQueueTimeout: number | null = null; protected tokenPluginFileWorks?: boolean; @@ -636,9 +636,10 @@ export class CoreSite { const cacheId = this.getCacheId(method, data); - // Check for an ongoing identical request if we're not ignoring cache. - if (preSets.getFromCache && this.ongoingRequests[cacheId] !== undefined) { - return this.ongoingRequests[cacheId]; + // Check for an ongoing identical request. + const ongoingRequest = this.getOngoingRequest(cacheId, preSets); + if (ongoingRequest) { + return ongoingRequest; } const observable = this.performRequest(method, data, preSets, wsPreSets).pipe( @@ -646,18 +647,68 @@ export class CoreSite { map((data) => CoreUtils.clone(data)), ); - this.ongoingRequests[cacheId] = observable; + this.setOngoingRequest(cacheId, preSets, observable); return observable.pipe( finalize(() => { - // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache). - if (this.ongoingRequests[cacheId] === observable) { - delete this.ongoingRequests[cacheId]; - } + this.clearOngoingRequest(cacheId, preSets, observable); }), ); } + /** + * Get an ongoing request if there's one already. + * + * @param cacheId Cache ID. + * @param preSets Presets. + * @return Ongoing request if it exists. + */ + protected getOngoingRequest(cacheId: string, preSets: CoreSiteWSPreSets): WSObservable | undefined { + if (preSets.updateInBackground) { + return this.ongoingRequests[cacheId]?.[OngoingRequestType.UPDATE_IN_BACKGROUND]; + } else if (preSets.getFromCache) { // Only reuse ongoing request when using cache. + return this.ongoingRequests[cacheId]?.[OngoingRequestType.STANDARD]; + } + } + + /** + * Store an ongoing request in memory. + * + * @param cacheId Cache ID. + * @param preSets Presets. + * @param request Request to store. + */ + protected setOngoingRequest(cacheId: string, preSets: CoreSiteWSPreSets, request: WSObservable): void { + this.ongoingRequests[cacheId] = this.ongoingRequests[cacheId] ?? {}; + + if (preSets.updateInBackground) { + this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND] = request; + } else { + this.ongoingRequests[cacheId][OngoingRequestType.STANDARD] = request; + } + } + + /** + * Clear the ongoing request unless it has changed (e.g. a new request that ignores cache). + * + * @param cacheId Cache ID. + * @param preSets Presets. + * @param request Current request. + */ + protected clearOngoingRequest(cacheId: string, preSets: CoreSiteWSPreSets, request: WSObservable): void { + this.ongoingRequests[cacheId] = this.ongoingRequests[cacheId] ?? {}; + + if (preSets.updateInBackground) { + if (this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND] === request) { + delete this.ongoingRequests[cacheId][OngoingRequestType.UPDATE_IN_BACKGROUND]; + } + } else { + if (this.ongoingRequests[cacheId][OngoingRequestType.STANDARD] === request) { + delete this.ongoingRequests[cacheId][OngoingRequestType.STANDARD]; + } + } + } + /** * Perform a request, getting the response either from cache or WebService. * @@ -1640,8 +1691,11 @@ export class CoreSite { } // Check for an ongoing identical request if we're not ignoring cache. - if (cachePreSets.getFromCache && this.ongoingRequests[cacheId] !== undefined) { - return await firstValueFrom(this.ongoingRequests[cacheId]); + + // Check for an ongoing identical request. + const ongoingRequest = this.getOngoingRequest(cacheId, cachePreSets); + if (ongoingRequest) { + return firstValueFrom(ongoingRequest); } const subject = new Subject(); @@ -1649,14 +1703,11 @@ export class CoreSite { // Return a clone of the original object, this may prevent errors if in the callback the object is modified. map((data) => CoreUtils.clone(data)), finalize(() => { - // Clear the ongoing request unless it has changed (e.g. a new request that ignores cache). - if (this.ongoingRequests[cacheId] === observable) { - delete this.ongoingRequests[cacheId]; - } + this.clearOngoingRequest(cacheId, cachePreSets, observable); }), ); - this.ongoingRequests[cacheId] = observable; + this.setOngoingRequest(cacheId, cachePreSets, observable); this.getFromCache(method, {}, cachePreSets, false) .then(cachedData => cachedData.response) @@ -2804,3 +2855,11 @@ type WSCachedError = { * Otherwise, it will only return 1 value, either coming from cache or from the server. After this, it will complete. */ export type WSObservable = Observable; + +/** + * Type of ongoing requests stored in memory to avoid duplicating them. + */ +enum OngoingRequestType { + STANDARD = 0, + UPDATE_IN_BACKGROUND = 1, +}