diff --git a/src/core/classes/site.ts b/src/core/classes/site.ts index 693830b19..3420106dc 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/site.ts @@ -41,7 +41,7 @@ import { CoreLogger } from '@singletons/logger'; import { Translate } from '@singletons'; import { CoreIonLoadingElement } from './ion-loading'; import { CoreLang } from '@services/lang'; -import { CoreSites } from '@services/sites'; +import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { asyncInstance, AsyncInstance } from '../utils/async-instance'; import { CoreDatabaseTable } from './database/database-table'; import { CoreDatabaseCachingStrategy } from './database/database-table-proxy'; @@ -1389,9 +1389,88 @@ export class CoreSite { /** * Get the public config of this site. * + * @param options Options. * @return Promise resolved with public config. Rejected with an object if error, see CoreWSProvider.callAjax. */ - async getPublicConfig(): Promise { + async getPublicConfig(options: { readingStrategy?: CoreSitesReadingStrategy } = {}): Promise { + if (!this.db) { + return this.requestPublicConfig(); + } + + const method = 'tool_mobile_get_public_config'; + const cacheId = this.getCacheId(method, {}); + const cachePreSets: CoreSiteWSPreSets = { + getFromCache: true, + saveToCache: true, + emergencyCache: true, + ...CoreSites.getReadingStrategyPreSets(options.readingStrategy), + }; + + if (this.offlineDisabled) { + // Offline is disabled, don't use cache. + cachePreSets.getFromCache = false; + cachePreSets.saveToCache = false; + cachePreSets.emergencyCache = false; + } + + // Check for an ongoing identical request if we're not ignoring cache. + if (cachePreSets.getFromCache && this.ongoingRequests[cacheId]) { + const response = await this.ongoingRequests[cacheId]; + + return response; + } + + const promise = this.getFromCache(method, {}, cachePreSets, false).catch(async () => { + if (cachePreSets.forceOffline) { + // Don't call the WS, just fail. + throw new CoreError( + Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }), + ); + } + + // Call the WS. + try { + const config = await this.requestPublicConfig(); + + if (cachePreSets.saveToCache) { + this.saveToCache(method, {}, config, cachePreSets); + } + + return config; + } catch (error) { + cachePreSets.omitExpires = true; + cachePreSets.getFromCache = true; + + try { + return await this.getFromCache(method, {}, cachePreSets, true); + } catch { + throw error; + } + } + }); + + this.ongoingRequests[cacheId] = promise; + + // Clear ongoing request after setting the promise (just in case it's already resolved). + try { + const response = await promise; + + // We pass back a clone of the original object, this may prevent errors if in the callback the object is modified. + return response; + } finally { + // Make sure we don't clear the promise of a newer request that ignores the cache. + if (this.ongoingRequests[cacheId] === promise) { + delete this.ongoingRequests[cacheId]; + } + } + } + + /** + * Perform a request to the server to get the public config of this site. + * + * @return Promise resolved with public config. + */ + protected async requestPublicConfig(): Promise { const preSets: CoreWSAjaxPreSets = { siteUrl: this.siteUrl, }; diff --git a/src/core/features/login/pages/reconnect/reconnect.ts b/src/core/features/login/pages/reconnect/reconnect.ts index f40c6fd05..c8a8acf37 100644 --- a/src/core/features/login/pages/reconnect/reconnect.ts +++ b/src/core/features/login/pages/reconnect/reconnect.ts @@ -16,7 +16,7 @@ import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/co import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { CoreApp } from '@services/app'; -import { CoreSites } from '@services/sites'; +import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CoreLoginHelper } from '@features/login/services/login-helper'; @@ -132,7 +132,9 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { * Get some data (like identity providers) from the site config. */ protected async checkSiteConfig(site: CoreSite): Promise { - this.siteConfig = await CoreUtils.ignoreErrors(site.getPublicConfig()); + this.siteConfig = await CoreUtils.ignoreErrors(site.getPublicConfig({ + readingStrategy: CoreSitesReadingStrategy.PREFER_NETWORK, + })); if (!this.siteConfig) { return; diff --git a/src/core/features/login/services/handlers/cron.ts b/src/core/features/login/services/handlers/cron.ts index 2add95869..3b6c53838 100644 --- a/src/core/features/login/services/handlers/cron.ts +++ b/src/core/features/login/services/handlers/cron.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreCronHandler } from '@services/cron'; -import { CoreSites } from '@services/sites'; +import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; import { makeSingleton } from '@singletons'; @@ -39,7 +39,9 @@ export class CoreLoginCronHandlerService implements CoreCronHandler { // Do not check twice in the same 10 minutes. const site = await CoreSites.getSite(siteId); - const config = await CoreUtils.ignoreErrors(site.getPublicConfig()); + const config = await CoreUtils.ignoreErrors(site.getPublicConfig({ + readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK, + })); CoreUtils.ignoreErrors(CoreSites.checkApplication(config)); } diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index 3666de2df..64c5af804 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -897,7 +897,9 @@ export class CoreSitesProvider { */ protected async getPublicConfigAndCheckApplication(site: CoreSite): Promise { try { - const config = await site.getPublicConfig(); + const config = await site.getPublicConfig({ + readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK, + }); await this.checkApplication(config); } catch {