MOBILE-3817 filter: Apply update in background to filters

main
Dani Palou 2022-07-25 10:39:59 +02:00
parent 01df501cad
commit 979e995166
5 changed files with 138 additions and 76 deletions

View File

@ -2409,7 +2409,7 @@ export function chainRequests<T, O extends ObservableInput<any>>(
return source.subscribe({ return source.subscribe({
next: async (value) => { next: async (value) => {
if (readingStrategy !== CoreSitesReadingStrategy.UPDATE_IN_BACKGROUND) { if (readingStrategy !== CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE) {
// Just use same strategy. // Just use same strategy.
subscriber.next({ data: value, readingStrategy }); subscriber.next({ data: value, readingStrategy });

View File

@ -54,6 +54,9 @@ import { CoreDatabaseCachingStrategy } from '@classes/database/database-table-pr
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB } from '@classes/sqlitedb';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreTime } from '@singletons/time'; import { CoreTime } from '@singletons/time';
import { Observable } from 'rxjs';
import { asyncObservable, firstValueFrom } from '@/core/utils/rxjs';
import { map } from 'rxjs/operators';
const ROOT_CACHE_KEY = 'mmCourse:'; const ROOT_CACHE_KEY = 'mmCourse:';
@ -402,8 +405,22 @@ export class CoreCourseProvider {
* @return Promise resolved with the list of blocks. * @return Promise resolved with the list of blocks.
* @since 3.7 * @since 3.7
*/ */
async getCourseBlocks(courseId: number, siteId?: string): Promise<CoreCourseBlock[]> { getCourseBlocks(courseId: number, siteId?: string): Promise<CoreCourseBlock[]> {
const site = await CoreSites.getSite(siteId); return firstValueFrom(this.getCourseBlocksObservable(courseId, { siteId }));
}
/**
* Get course blocks.
*
* @param courseId Course ID.
* @param options Options.
* @return Observable that returns the blocks.
* @since 3.7
*/
getCourseBlocksObservable(courseId: number, options: CoreSitesCommonWSOptions = {}): Observable<CoreCourseBlock[]> {
return asyncObservable(async () => {
const site = await CoreSites.getSite(options.siteId);
const params: CoreBlockGetCourseBlocksWSParams = { const params: CoreBlockGetCourseBlocksWSParams = {
courseid: courseId, courseid: courseId,
returncontents: true, returncontents: true,
@ -411,10 +428,13 @@ export class CoreCourseProvider {
const preSets: CoreSiteWSPreSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getCourseBlocksCacheKey(courseId), cacheKey: this.getCourseBlocksCacheKey(courseId),
updateFrequency: CoreSite.FREQUENCY_RARELY, updateFrequency: CoreSite.FREQUENCY_RARELY,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
}; };
const result = await site.read<CoreCourseBlocksWSResponse>('core_block_get_course_blocks', params, preSets);
return result.blocks || []; return site.readObservable<CoreCourseBlocksWSResponse>('core_block_get_course_blocks', params, preSets).pipe(
map(result => result.blocks),
);
});
} }
/** /**
@ -908,7 +928,7 @@ export class CoreCourseProvider {
* @param includeStealthModules Whether to include stealth modules. Defaults to true. * @param includeStealthModules Whether to include stealth modules. Defaults to true.
* @return The reject contains the error message, else contains the sections. * @return The reject contains the error message, else contains the sections.
*/ */
async getSections( getSections(
courseId: number, courseId: number,
excludeModules: boolean = false, excludeModules: boolean = false,
excludeContents: boolean = false, excludeContents: boolean = false,
@ -916,11 +936,37 @@ export class CoreCourseProvider {
siteId?: string, siteId?: string,
includeStealthModules: boolean = true, includeStealthModules: boolean = true,
): Promise<CoreCourseWSSection[]> { ): Promise<CoreCourseWSSection[]> {
return firstValueFrom(this.getSectionsObservable(courseId, {
excludeModules,
excludeContents,
includeStealthModules,
preSets,
siteId,
}));
}
const site = await CoreSites.getSite(siteId); /**
preSets = preSets || {}; * Get the course sections.
preSets.cacheKey = this.getSectionsCacheKey(courseId); *
preSets.updateFrequency = preSets.updateFrequency || CoreSite.FREQUENCY_RARELY; * @param courseId The course ID.
* @param options Options.
* @return Observable that returns the sections.
*/
getSectionsObservable(
courseId: number,
options: CoreCourseGetSectionsOptions = {},
): Observable<CoreCourseWSSection[]> {
options.includeStealthModules = options.includeStealthModules ?? true;
return asyncObservable(async () => {
const site = await CoreSites.getSite(options.siteId);
const preSets: CoreSiteWSPreSets = {
...options.preSets,
cacheKey: this.getSectionsCacheKey(courseId),
updateFrequency: CoreSite.FREQUENCY_RARELY,
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
};
const params: CoreCourseGetContentsParams = { const params: CoreCourseGetContentsParams = {
courseid: courseId, courseid: courseId,
@ -928,32 +974,23 @@ export class CoreCourseProvider {
params.options = [ params.options = [
{ {
name: 'excludemodules', name: 'excludemodules',
value: excludeModules, value: !!options.excludeModules,
}, },
{ {
name: 'excludecontents', name: 'excludecontents',
value: excludeContents, value: !!options.excludeContents,
}, },
]; ];
if (this.canRequestStealthModules(site)) { if (this.canRequestStealthModules(site)) {
params.options.push({ params.options.push({
name: 'includestealthmodules', name: 'includestealthmodules',
value: includeStealthModules, value: !!options.includeStealthModules,
}); });
} }
let sections: CoreCourseGetContentsWSSection[]; return site.readObservable<CoreCourseGetContentsWSSection[]>('core_course_get_contents', params, preSets).pipe(
try { map(sections => {
sections = await site.read('core_course_get_contents', params, preSets);
} catch {
// Error getting the data, it could fail because we added a new parameter and the call isn't cached.
// Retry without the new parameter and forcing cache.
preSets.omitExpires = true;
params.options.splice(-1, 1);
sections = await site.read('core_course_get_contents', params, preSets);
}
const siteHomeId = site.getSiteHomeId(); const siteHomeId = site.getSiteHomeId();
let showSections = true; let showSections = true;
if (courseId == siteHomeId) { if (courseId == siteHomeId) {
@ -971,6 +1008,9 @@ export class CoreCourseProvider {
...section, ...section,
modules: section.modules.map((module) => this.addAdditionalModuleData(module, courseId, section.id)), modules: section.modules.map((module) => this.addAdditionalModuleData(module, courseId, section.id)),
})); }));
}),
);
});
} }
/** /**
@ -1933,3 +1973,13 @@ export type CoreCourseStoreModuleViewedOptions = {
timeaccess?: number; timeaccess?: number;
siteId?: string; siteId?: string;
}; };
/**
* Options for getSections.
*/
export type CoreCourseGetSectionsOptions = CoreSitesCommonWSOptions & {
excludeModules?: boolean;
excludeContents?: boolean;
includeStealthModules?: boolean; // Defaults to true.
preSets?: CoreSiteWSPreSets;
};

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreNetwork } from '@services/network'; import { CoreNetwork } from '@services/network';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreFilterDelegate } from './filter-delegate'; import { CoreFilterDelegate } from './filter-delegate';
import { import {
CoreFilter, CoreFilter,
@ -31,6 +31,7 @@ import { CoreEvents, CoreEventSiteData } from '@singletons/events';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreSite } from '@classes/site'; import { CoreSite } from '@classes/site';
import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreCourseHelper } from '@features/course/services/course-helper';
import { firstValueFrom } from '@/core/utils/rxjs';
/** /**
* Helper service to provide filter functionalities. * Helper service to provide filter functionalities.
@ -75,7 +76,11 @@ export class CoreFilterHelperProvider {
* @return Promise resolved with the contexts. * @return Promise resolved with the contexts.
*/ */
async getBlocksContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> { async getBlocksContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> {
const blocks = await CoreCourse.getCourseBlocks(courseId, siteId); // Use stale while revalidate, but always use the first value. If data is updated it will be stored in DB.
const blocks = await firstValueFrom(CoreCourse.getCourseBlocksObservable(courseId, {
readingStrategy: CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE,
siteId,
}));
const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = []; const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = [];
@ -153,7 +158,12 @@ export class CoreFilterHelperProvider {
* @return Promise resolved with the contexts. * @return Promise resolved with the contexts.
*/ */
async getCourseModulesContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> { async getCourseModulesContexts(courseId: number, siteId?: string): Promise<CoreFiltersGetAvailableInContextWSParamContext[]> {
const sections = await CoreCourse.getSections(courseId, false, true, undefined, siteId); // Use stale while revalidate, but always use the first value. If data is updated it will be stored in DB.
const sections = await firstValueFrom(CoreCourse.getSectionsObservable(courseId, {
excludeContents: true,
readingStrategy: CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE,
siteId,
}));
const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = []; const contexts: CoreFiltersGetAvailableInContextWSParamContext[] = [];

View File

@ -15,8 +15,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreNetwork } from '@services/network'; import { CoreNetwork } from '@services/network';
import { CoreSites } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreSite } from '@classes/site'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { CoreWSExternalWarning } from '@services/ws'; import { CoreWSExternalWarning } from '@services/ws';
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
import { CoreFilterDelegate } from './filter-delegate'; import { CoreFilterDelegate } from './filter-delegate';
@ -284,13 +284,15 @@ export class CoreFilterProvider {
const data: CoreFiltersGetAvailableInContextWSParams = { const data: CoreFiltersGetAvailableInContextWSParams = {
contexts: contextsToSend, contexts: contextsToSend,
}; };
const preSets = { const preSets: CoreSiteWSPreSets = {
cacheKey: this.getAvailableInContextsCacheKey(contextsToSend), cacheKey: this.getAvailableInContextsCacheKey(contextsToSend),
updateFrequency: CoreSite.FREQUENCY_RARELY, updateFrequency: CoreSite.FREQUENCY_RARELY,
splitRequest: { splitRequest: {
param: 'contexts', param: 'contexts',
maxLength: 300, maxLength: 300,
}, },
// Use stale while revalidate, but always use the first value. If data is updated it will be stored in DB.
...CoreSites.getReadingStrategyPreSets(CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE),
}; };
const result = await site.read<CoreFilterGetAvailableInContextResult>( const result = await site.read<CoreFilterGetAvailableInContextResult>(

View File

@ -1796,7 +1796,7 @@ export class CoreSitesProvider {
getFromCache: false, getFromCache: false,
emergencyCache: false, emergencyCache: false,
}; };
case CoreSitesReadingStrategy.UPDATE_IN_BACKGROUND: case CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE:
return { return {
updateInBackground: true, updateInBackground: true,
getFromCache: true, getFromCache: true,
@ -2023,7 +2023,7 @@ export const enum CoreSitesReadingStrategy {
PREFER_CACHE, PREFER_CACHE,
ONLY_NETWORK, ONLY_NETWORK,
PREFER_NETWORK, PREFER_NETWORK,
UPDATE_IN_BACKGROUND, STALE_WHILE_REVALIDATE,
} }
/** /**