MOBILE-3437 files: Ignore downloaded files on prefetch calculations

main
Pau Ferrer Ocaña 2020-06-03 10:09:40 +02:00
parent 4f9adba63e
commit 2052080673
6 changed files with 109 additions and 78 deletions

View File

@ -28,6 +28,7 @@ import { CoreGroupsProvider } from '@providers/groups';
import { AddonModFeedbackSyncProvider } from './sync';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
import { CoreWSExternalFile } from '@providers/ws';
/**
* Handler to prefetch feedbacks.
@ -68,26 +69,31 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
* @param single True if we're downloading a single module, false if we're downloading a whole section.
* @return Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
async getFiles(module: any, courseId: number, single?: boolean): Promise<CoreWSExternalFile[]> {
let files = [];
return this.feedbackProvider.getFeedback(courseId, module.id).then((feedback) => {
const feedback = await this.feedbackProvider.getFeedback(courseId, module.id);
// Get intro files and page after submit files.
files = feedback.pageaftersubmitfiles || [];
files = files.concat(this.getIntroFilesFromInstance(module, feedback));
// Get intro files and page after submit files.
files = feedback.pageaftersubmitfiles || [];
files = files.concat(this.getIntroFilesFromInstance(module, feedback));
try {
const response = await this.feedbackProvider.getItems(feedback.id);
return this.feedbackProvider.getItems(feedback.id);
}).then((response) => {
response.items.forEach((item) => {
files = files.concat(item.itemfiles);
files = files.concat(item.itemfiles.map((file) => {
file.fileurl = file.fileurl || file.url;
return file;
}));
});
return files;
}).catch(() => {
// Any error, return the list we have.
return files;
});
} catch (e) {
// Ignore errors.
}
return files;
}
/**
@ -97,7 +103,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
* @param courseId Course ID.
* @return Promise resolved with list of intro files.
*/
getIntroFiles(module: any, courseId: number): Promise<any[]> {
getIntroFiles(module: any, courseId: number): Promise<CoreWSExternalFile[]> {
return this.feedbackProvider.getFeedback(courseId, module.id).catch(() => {
// Not found, return undefined so module description is used.
}).then((feedback) => {

View File

@ -111,7 +111,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
let files = lesson.mediafiles || [];
files = files.concat(this.getIntroFilesFromInstance(module, lesson));
return this.pluginFileDelegate.getFilesSize(files);
return this.pluginFileDelegate.getFilesDownloadSize(files);
}).then((res) => {
result = res;

View File

@ -97,7 +97,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
siteId = this.sitesProvider.getCurrentSiteId();
promises.push(this.getFiles(module, courseId, single, siteId).then((files) => {
return this.pluginFileDelegate.getFilesSize(files);
return this.pluginFileDelegate.getFilesDownloadSize(files);
}));
promises.push(this.getAllPages(module, courseId, false, true, siteId).then((pages) => {

View File

@ -19,6 +19,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '../providers/course';
import { CoreWSExternalFile } from '@providers/ws';
import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate';
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
@ -114,7 +115,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param module The module object returned by WS.
* @return List of files.
*/
getContentDownloadableFiles(module: any): any[] {
getContentDownloadableFiles(module: any): CoreWSExternalFile[] {
const files = [];
if (module.contents && module.contents.length) {
@ -139,7 +140,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> {
return this.getFiles(module, courseId).then((files) => {
return this.pluginFileDelegate.getFilesSize(files);
return this.pluginFileDelegate.getFilesDownloadSize(files);
}).catch(() => {
return { size: -1, total: false };
});
@ -166,7 +167,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param single True if we're downloading a single module, false if we're downloading a whole section.
* @return Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
getFiles(module: any, courseId: number, single?: boolean): Promise<CoreWSExternalFile[]> {
// To be overridden.
return Promise.resolve([]);
}
@ -179,7 +180,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
* @return Promise resolved with list of intro files.
*/
getIntroFiles(module: any, courseId: number, ignoreCache?: boolean): Promise<any[]> {
getIntroFiles(module: any, courseId: number, ignoreCache?: boolean): Promise<CoreWSExternalFile[]> {
return Promise.resolve(this.getIntroFilesFromInstance(module));
}
@ -190,7 +191,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param instance The instance to get the intro files (book, assign, ...). If not defined, module will be used.
* @return List of intro files.
*/
getIntroFilesFromInstance(module: any, instance?: any): any[] {
getIntroFilesFromInstance(module: any, instance?: any): CoreWSExternalFile[] {
if (instance) {
if (typeof instance.introfiles != 'undefined') {
return instance.introfiles;

View File

@ -1397,7 +1397,7 @@ export class CoreFilepoolProvider {
* @param html HTML code.
* @return List of fake file objects with file URLs.
*/
extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] {
extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): CoreWSExternalFile[] {
const urls = this.extractDownloadableFilesFromHtml(html);
// Convert them to fake file objects.
@ -1768,46 +1768,50 @@ export class CoreFilepoolProvider {
* @param revision File revision. If not defined, it will be calculated using the URL.
* @return Promise resolved with the file state.
*/
getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string, revision?: number)
async getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string, revision?: number)
: Promise<string> {
let fileId;
let file;
return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => {
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl);
fileId = this.getFileIdByUrl(fileUrl);
// Check if the file is in queue (waiting to be downloaded).
return this.hasFileInQueue(siteId, fileId).then(() => {
return CoreConstants.DOWNLOADING;
}).catch(() => {
// Check if the file is being downloaded right now.
const extension = this.mimeUtils.guessExtensionFromUrl(fileUrl),
path = filePath ? filePath : this.getFilePath(siteId, fileId, extension);
return Promise.resolve(path).then((filePath) => {
const downloadId = this.getFileDownloadId(fileUrl, filePath);
if (this.filePromises[siteId] && this.filePromises[siteId][downloadId]) {
return CoreConstants.DOWNLOADING;
}
// File is not being downloaded. Check if it's downloaded and if it's outdated.
return this.hasFileInPool(siteId, fileId).then((entry) => {
if (this.isFileOutdated(entry, revision, timemodified)) {
return CoreConstants.OUTDATED;
} else {
return CoreConstants.DOWNLOADED;
}
}).catch(() => {
return CoreConstants.NOT_DOWNLOADED;
});
});
});
}, () => {
try {
file = await this.fixPluginfileURL(siteId, fileUrl, timemodified);
} catch (e) {
return CoreConstants.NOT_DOWNLOADABLE;
});
}
fileUrl = file.fileurl;
timemodified = file.timemodified || timemodified;
revision = revision || this.getRevisionFromUrl(fileUrl);
const fileId = this.getFileIdByUrl(fileUrl);
try {
// Check if the file is in queue (waiting to be downloaded).
await this.hasFileInQueue(siteId, fileId);
return CoreConstants.DOWNLOADING;
} catch (e) {
// Check if the file is being downloaded right now.
const extension = this.mimeUtils.guessExtensionFromUrl(fileUrl);
filePath = filePath || (await this.getFilePath(siteId, fileId, extension));
const downloadId = this.getFileDownloadId(fileUrl, filePath);
if (this.filePromises[siteId] && this.filePromises[siteId][downloadId]) {
return CoreConstants.DOWNLOADING;
}
try {
// File is not being downloaded. Check if it's downloaded and if it's outdated.
const entry = await this.hasFileInPool(siteId, fileId);
if (this.isFileOutdated(entry, revision, timemodified)) {
return CoreConstants.OUTDATED;
}
return CoreConstants.DOWNLOADED;
} catch (e) {
return CoreConstants.NOT_DOWNLOADED;
}
}
}
/**

View File

@ -18,6 +18,8 @@ import { CoreLoggerProvider } from './logger';
import { CoreSitesProvider } from './sites';
import { CoreWSExternalFile } from '@providers/ws';
import { FileEntry } from '@ionic-native/file';
import { CoreFilepool } from './filepool';
import { CoreConstants } from '@core/constants';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
import { makeSingleton } from '@singletons/core.singletons';
@ -234,6 +236,27 @@ export class CorePluginFileDelegate extends CoreDelegate {
return files;
}
/**
* Sum the filesizes from a list if they are not downloaded.
*
* @param files List of files to sum its filesize.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with file size and a boolean to indicate if it is the total size or only partial.
*/
async getFilesDownloadSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> {
const filteredFiles = [];
await Promise.all(files.map(async (file) => {
const state = await CoreFilepool.instance.getFileStateByUrl(siteId, file.fileurl, file.timemodified);
if (state != CoreConstants.DOWNLOADED && state != CoreConstants.NOT_DOWNLOADABLE) {
filteredFiles.push(file);
}
}));
return this.getFilesSize(filteredFiles, siteId);
}
/**
* Sum the filesizes from a list of files checking if the size will be partial or totally calculated.
*
@ -241,27 +264,24 @@ export class CorePluginFileDelegate extends CoreDelegate {
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with file size and a boolean to indicate if it is the total size or only partial.
*/
getFilesSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> {
const promises = [],
result = {
size: 0,
total: true
};
async getFilesSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> {
const result = {
size: 0,
total: true
};
files.forEach((file) => {
promises.push(this.getFileSize(file, siteId).then((size) => {
if (typeof size == 'undefined') {
// We don't have the file size, cannot calculate its total size.
result.total = false;
} else {
result.size += size;
}
}));
});
await Promise.all(files.map(async (file) => {
const size = await this.getFileSize(file, siteId);
return Promise.all(promises).then(() => {
return result;
});
if (typeof size == 'undefined') {
// We don't have the file size, cannot calculate its total size.
result.total = false;
} else {
result.size += size;
}
}));
return result;
}
/**