From 3bdcdef19860c3e92192b8db0f7e532bdd607c84 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Apr 2022 23:37:48 -0500 Subject: [PATCH] Fixed backup stuck at unsupported format (#108) * Added webp as supported file type, allow continue upload when an image fail * Added webp as supported file type, allow continue upload when an image fail * Solved issue with bad assets cause backup to stop --- .../lib/shared/providers/backup.provider.dart | 52 ++++++++++++------- .../lib/shared/services/backup.service.dart | 5 +- .../shared/views/backup_controller_page.dart | 17 +++--- mobile/lib/utils/files_helper.dart | 3 ++ server/src/config/multer-option.config.ts | 2 +- 5 files changed, 52 insertions(+), 27 deletions(-) diff --git a/mobile/lib/shared/providers/backup.provider.dart b/mobile/lib/shared/providers/backup.provider.dart index 3111b33abf..d94a00a168 100644 --- a/mobile/lib/shared/providers/backup.provider.dart +++ b/mobile/lib/shared/providers/backup.provider.dart @@ -37,24 +37,29 @@ class BackupNotifier extends StateNotifier { Ref? ref; final BackupService _backupService = BackupService(); final ServerInfoService _serverInfoService = ServerInfoService(); - final StreamController _onAssetBackupStreamCtrl = StreamController.broadcast(); + final StreamController _onAssetBackupStreamCtrl = + StreamController.broadcast(); void getBackupInfo() async { _updateServerInfo(); - List list = await PhotoManager.getAssetPathList(onlyAll: true, type: RequestType.common); + List list = await PhotoManager.getAssetPathList( + onlyAll: true, type: RequestType.common); List didBackupAsset = await _backupService.getDeviceBackupAsset(); if (list.isEmpty) { debugPrint("No Asset On Device"); state = state.copyWith( - backupProgress: BackUpProgressEnum.idle, totalAssetCount: 0, assetOnDatabase: didBackupAsset.length); + backupProgress: BackUpProgressEnum.idle, + totalAssetCount: 0, + assetOnDatabase: didBackupAsset.length); return; } int totalAsset = list[0].assetCount; - state = state.copyWith(totalAssetCount: totalAsset, assetOnDatabase: didBackupAsset.length); + state = state.copyWith( + totalAssetCount: totalAsset, assetOnDatabase: didBackupAsset.length); } void startBackupProcess() async { @@ -67,8 +72,8 @@ class BackupNotifier extends StateNotifier { await PhotoManager.clearFileCache(); // await PhotoManager.presentLimited(); // Gather assets info - List list = - await PhotoManager.getAssetPathList(hasAll: true, onlyAll: true, type: RequestType.common); + List list = await PhotoManager.getAssetPathList( + hasAll: true, onlyAll: true, type: RequestType.common); // Get device assets info from database // Compare and find different assets that has not been backing up @@ -78,14 +83,18 @@ class BackupNotifier extends StateNotifier { if (list.isEmpty) { debugPrint("No Asset On Device - Abort Backup Process"); state = state.copyWith( - backupProgress: BackUpProgressEnum.idle, totalAssetCount: 0, assetOnDatabase: backupAsset.length); + backupProgress: BackUpProgressEnum.idle, + totalAssetCount: 0, + assetOnDatabase: backupAsset.length); return; } int totalAsset = list[0].assetCount; - List currentAssets = await list[0].getAssetListRange(start: 0, end: totalAsset); + List currentAssets = + await list[0].getAssetListRange(start: 0, end: totalAsset); - state = state.copyWith(totalAssetCount: totalAsset, assetOnDatabase: backupAsset.length); + state = state.copyWith( + totalAssetCount: totalAsset, assetOnDatabase: backupAsset.length); // Remove item that has already been backed up for (var backupAssetId in backupAsset) { currentAssets.removeWhere((e) => e.id == backupAssetId); @@ -97,9 +106,10 @@ class BackupNotifier extends StateNotifier { state = state.copyWith(backingUpAssetCount: currentAssets.length); - // Perform Packup + // Perform Backup state = state.copyWith(cancelToken: CancelToken()); - _backupService.backupAsset(currentAssets, state.cancelToken, _onAssetUploaded, _onUploadProgress); + _backupService.backupAsset(currentAssets, state.cancelToken, + _onAssetUploaded, _onUploadProgress); } else { PhotoManager.openSetting(); } @@ -107,22 +117,26 @@ class BackupNotifier extends StateNotifier { void cancelBackup() { state.cancelToken.cancel('Cancel Backup'); - state = state.copyWith(backupProgress: BackUpProgressEnum.idle, progressInPercentage: 0.0); + state = state.copyWith( + backupProgress: BackUpProgressEnum.idle, progressInPercentage: 0.0); } void _onAssetUploaded(String deviceAssetId, String deviceId) { - state = - state.copyWith(backingUpAssetCount: state.backingUpAssetCount - 1, assetOnDatabase: state.assetOnDatabase + 1); + state = state.copyWith( + backingUpAssetCount: state.backingUpAssetCount - 1, + assetOnDatabase: state.assetOnDatabase + 1); if (state.backingUpAssetCount == 0) { - state = state.copyWith(backupProgress: BackUpProgressEnum.done, progressInPercentage: 0.0); + state = state.copyWith( + backupProgress: BackUpProgressEnum.done, progressInPercentage: 0.0); } _updateServerInfo(); } void _onUploadProgress(int sent, int total) { - state = state.copyWith(progressInPercentage: (sent.toDouble() / total.toDouble() * 100)); + state = state.copyWith( + progressInPercentage: (sent.toDouble() / total.toDouble() * 100)); } void _updateServerInfo() async { @@ -156,7 +170,8 @@ class BackupNotifier extends StateNotifier { } // Check if this device is enable backup by the user - if ((authState.deviceInfo.deviceId == authState.deviceId) && authState.deviceInfo.isAutoBackup) { + if ((authState.deviceInfo.deviceId == authState.deviceId) && + authState.deviceInfo.isAutoBackup) { // check if backup is alreayd in process - then return if (state.backupProgress == BackUpProgressEnum.inProgress) { debugPrint("[resumeBackup] Backup is already in progress - abort"); @@ -173,6 +188,7 @@ class BackupNotifier extends StateNotifier { } } -final backupProvider = StateNotifierProvider((ref) { +final backupProvider = + StateNotifierProvider((ref) { return BackupNotifier(ref: ref); }); diff --git a/mobile/lib/shared/services/backup.service.dart b/mobile/lib/shared/services/backup.service.dart index d4af18959d..6337a7de01 100644 --- a/mobile/lib/shared/services/backup.service.dart +++ b/mobile/lib/shared/services/backup.service.dart @@ -112,7 +112,10 @@ class BackupService { } } on DioError catch (e) { debugPrint("DioError backupAsset: ${e.response}"); - break; + if (e.type == DioErrorType.cancel || e.type == DioErrorType.other) { + return; + } + continue; } catch (e) { debugPrint("ERROR backupAsset: ${e.toString()}"); continue; diff --git a/mobile/lib/shared/views/backup_controller_page.dart b/mobile/lib/shared/views/backup_controller_page.dart index 3fd1399a10..5962bab575 100644 --- a/mobile/lib/shared/views/backup_controller_page.dart +++ b/mobile/lib/shared/views/backup_controller_page.dart @@ -87,13 +87,16 @@ class BackupControllerPage extends HookConsumerWidget { style: TextStyle(fontSize: 14), ) : Container(), - OutlinedButton( - onPressed: () { - isAutoBackup - ? ref.watch(authenticationProvider.notifier).setAutoBackup(false) - : ref.watch(authenticationProvider.notifier).setAutoBackup(true); - }, - child: Text("Turn $backupBtnText Backup"), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: OutlinedButton( + onPressed: () { + isAutoBackup + ? ref.watch(authenticationProvider.notifier).setAutoBackup(false) + : ref.watch(authenticationProvider.notifier).setAutoBackup(true); + }, + child: Text("Turn $backupBtnText Backup", style: const TextStyle(fontWeight: FontWeight.bold)), + ), ) ], ), diff --git a/mobile/lib/utils/files_helper.dart b/mobile/lib/utils/files_helper.dart index 1c9d64cc52..4d9ba2c7fa 100644 --- a/mobile/lib/utils/files_helper.dart +++ b/mobile/lib/utils/files_helper.dart @@ -35,6 +35,9 @@ class FileHelper { case 'dng': return {"type": "image", "subType": "dng"}; + case 'webp': + return {"type": "image", "subType": "webp"}; + default: return {"type": "unsupport", "subType": "unsupport"}; } diff --git a/server/src/config/multer-option.config.ts b/server/src/config/multer-option.config.ts index 281c825ee2..2d8a87dc9f 100644 --- a/server/src/config/multer-option.config.ts +++ b/server/src/config/multer-option.config.ts @@ -12,7 +12,7 @@ export const multerConfig = { export const multerOption: MulterOptions = { fileFilter: (req: Request, file: any, cb: any) => { - if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif|dng)$/)) { + if (file.mimetype.match(/\/(jpg|jpeg|png|gif|mp4|x-msvideo|quicktime|heic|heif|dng|webp)$/)) { cb(null, true); } else { cb(new HttpException(`Unsupported file type ${extname(file.originalname)}`, HttpStatus.BAD_REQUEST), false);