From afaf432ab08beeac08004e3ea75be4359d2df11a Mon Sep 17 00:00:00 2001 From: Ming Ming Date: Thu, 20 Jan 2022 13:23:49 +0800 Subject: [PATCH] Skip touch token check if etag matches --- lib/bloc/scan_account_dir.dart | 75 ++++++++++++++++++++++------------ lib/pref.dart | 31 ++++++++++++++ lib/touch_token_manager.dart | 24 +++++++++++ 3 files changed, 105 insertions(+), 25 deletions(-) diff --git a/lib/bloc/scan_account_dir.dart b/lib/bloc/scan_account_dir.dart index 381a183a..d887ce78 100644 --- a/lib/bloc/scan_account_dir.dart +++ b/lib/bloc/scan_account_dir.dart @@ -14,6 +14,7 @@ import 'package:nc_photos/event/event.dart'; import 'package:nc_photos/exception_event.dart'; import 'package:nc_photos/pref.dart'; import 'package:nc_photos/throttler.dart'; +import 'package:nc_photos/touch_token_manager.dart'; import 'package:nc_photos/use_case/ls.dart'; import 'package:nc_photos/use_case/scan_dir.dart'; import 'package:nc_photos/use_case/scan_dir_offline.dart'; @@ -307,7 +308,7 @@ class ScanAccountDirBloc Stream _queryOnline( ScanAccountDirBlocQueryBase ev, List? cache) async* { // 1st pass: scan for new files - final files = []; + var files = []; { final stopwatch = Stopwatch()..start(); final fileRepo = FileRepo(FileCachedDataSource(AppDb(), @@ -336,32 +337,56 @@ class ScanAccountDirBloc yield ScanAccountDirBlocLoading(files); } - if (_shouldCheckCache) { - // 2nd pass: check outdated cache - _shouldCheckCache = false; - final stopwatch = Stopwatch()..start(); - final fileRepo = FileRepo(FileCachedDataSource(AppDb(), - shouldCheckCache: true, - forwardCacheManager: FileForwardCacheManager(AppDb()))); - final fileRepoNoCache = - FileRepo(FileCachedDataSource(AppDb(), shouldCheckCache: true)); - final newFiles = []; - await for (final event in _queryWithFileRepo(fileRepo, ev, - fileRepoForShareDir: fileRepoNoCache)) { - if (event is ExceptionEvent) { - _log.shout("[_queryOnline] Exception while request (2nd pass)", - event.error, event.stackTrace); - yield ScanAccountDirBlocSuccess(files); - return; - } - newFiles.addAll(event); + try { + if (_shouldCheckCache) { + // 2nd pass: check outdated cache + _shouldCheckCache = false; + files = await _queryOnlinePass2(ev, files); } - _log.info( - "[_queryOnline] Elapsed time (pass2): ${stopwatch.elapsedMilliseconds}ms"); - yield ScanAccountDirBlocSuccess(newFiles); - } else { - yield ScanAccountDirBlocSuccess(files); + } catch (e, stackTrace) { + _log.shout( + "[_queryOnline] Failed while _queryOnlinePass2", e, stackTrace); } + yield ScanAccountDirBlocSuccess(files); + } + + Future> _queryOnlinePass2( + ScanAccountDirBlocQueryBase ev, List pass1Files) async { + const touchTokenManager = TouchTokenManager(); + final fileRepo = FileRepo(FileCachedDataSource(AppDb(), + shouldCheckCache: true, + forwardCacheManager: FileForwardCacheManager(AppDb()))); + final remoteTouchEtag = + await touchTokenManager.getRemoteRootEtag(fileRepo, account); + if (remoteTouchEtag == null) { + _log.info("[_queryOnlinePass2] remoteTouchEtag == null"); + await touchTokenManager.setLocalRootEtag(account, null); + return pass1Files; + } + final localTouchEtag = await touchTokenManager.getLocalRootEtag(account); + if (remoteTouchEtag == localTouchEtag) { + _log.info("[_queryOnlinePass2] remoteTouchEtag matched"); + return pass1Files; + } + + final stopwatch = Stopwatch()..start(); + final fileRepoNoCache = + FileRepo(FileCachedDataSource(AppDb(), shouldCheckCache: true)); + final newFiles = []; + await for (final event in _queryWithFileRepo(fileRepo, ev, + fileRepoForShareDir: fileRepoNoCache)) { + if (event is ExceptionEvent) { + _log.shout("[_queryOnlinePass2] Exception while request (2nd pass)", + event.error, event.stackTrace); + return pass1Files; + } + newFiles.addAll(event); + } + _log.info( + "[_queryOnlinePass2] Elapsed time (pass2): ${stopwatch.elapsedMilliseconds}ms"); + _log.info("[_queryOnlinePass2] Save new touch root etag: $remoteTouchEtag"); + await touchTokenManager.setLocalRootEtag(account, remoteTouchEtag); + return newFiles; } /// Emit all files under this account diff --git a/lib/pref.dart b/lib/pref.dart index a7c9ac13..3eaa0013 100644 --- a/lib/pref.dart +++ b/lib/pref.dart @@ -236,6 +236,14 @@ class AccountPref { value, (key, value) => provider.setBool(key, value)); + String? getTouchRootEtag() => provider.getString(PrefKey.touchRootEtag); + String getTouchRootEtagOr([String def = ""]) => getTouchRootEtag() ?? def; + Future setTouchRootEtag(String value) => _set( + PrefKey.touchRootEtag, + value, + (key, value) => provider.setString(key, value)); + Future removeTouchRootEtag() => _remove(PrefKey.touchRootEtag); + Future _set(PrefKey key, T value, Future Function(PrefKey key, T value) setFn) async { if (await setFn(key, value)) { @@ -248,6 +256,8 @@ class AccountPref { } } + Future _remove(PrefKey key) => provider.remove(key); + final PrefProvider provider; static final _insts = {}; @@ -267,6 +277,7 @@ abstract class PrefProvider { List? getStringList(PrefKey key); Future setStringList(PrefKey key, List value); + Future remove(PrefKey key); Future clear(); } @@ -311,6 +322,9 @@ class PrefSharedPreferencesProvider extends PrefProvider { setStringList(PrefKey key, List value) => _pref.setStringList(key.toStringKey(), value); + @override + remove(PrefKey key) => _pref.remove(key.toStringKey()); + @override clear() => _pref.clear(); @@ -348,6 +362,14 @@ class PrefUniversalStorageProvider extends PrefProvider { @override setStringList(PrefKey key, List value) => _set(key, value); + @override + remove(PrefKey key) async { + final newData = Map.of(_data)..remove(key.toStringKey()); + await platform.UniversalStorage().putString(name, jsonEncode(newData)); + _data.remove(key.toStringKey()); + return true; + } + @override clear() async { await platform.UniversalStorage().remove(name); @@ -395,6 +417,12 @@ class PrefMemoryProvider extends PrefProvider { @override setStringList(PrefKey key, List value) => _set(key, value); + @override + remove(PrefKey key) async { + _data.remove(key); + return true; + } + @override clear() async { _data.clear(); @@ -439,6 +467,7 @@ enum PrefKey { shareFolder, hasNewSharedAlbum, isEnableMemoryAlbum, + touchRootEtag, } extension on PrefKey { @@ -496,6 +525,8 @@ extension on PrefKey { return "hasNewSharedAlbum"; case PrefKey.isEnableMemoryAlbum: return "isEnableMemoryAlbum"; + case PrefKey.touchRootEtag: + return "touchRootEtag"; } } } diff --git a/lib/touch_token_manager.dart b/lib/touch_token_manager.dart index 20823eb3..06262096 100644 --- a/lib/touch_token_manager.dart +++ b/lib/touch_token_manager.dart @@ -8,6 +8,7 @@ import 'package:nc_photos/entity/file.dart'; import 'package:nc_photos/exception.dart'; import 'package:nc_photos/mobile/platform.dart' if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; +import 'package:nc_photos/pref.dart'; import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util; import 'package:nc_photos/use_case/get_file_binary.dart'; import 'package:nc_photos/use_case/put_file_binary.dart'; @@ -24,6 +25,29 @@ import 'package:nc_photos/use_case/remove.dart'; class TouchTokenManager { const TouchTokenManager(); + Future getRemoteRootEtag(FileRepo fileRepo, Account account) async { + try { + final touchDir = await fileRepo.listSingle( + account, File(path: remote_storage_util.getRemoteTouchDir(account))); + return touchDir.etag!; + } catch (_) { + // dir not found on server + return null; + } + } + + Future setLocalRootEtag(Account account, String? etag) async { + if (etag == null) { + await AccountPref.of(account).removeTouchRootEtag(); + } else { + await AccountPref.of(account).setTouchRootEtag(etag); + } + } + + Future getLocalRootEtag(Account account) async { + return AccountPref.of(account).getTouchRootEtag(); + } + Future setRemoteToken( FileRepo fileRepo, Account account, File file, String? token) async { _log.info(