Skip touch token check if etag matches

This commit is contained in:
Ming Ming 2022-01-20 13:23:49 +08:00
parent 7a515fdad1
commit afaf432ab0
3 changed files with 105 additions and 25 deletions

View file

@ -14,6 +14,7 @@ import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception_event.dart'; import 'package:nc_photos/exception_event.dart';
import 'package:nc_photos/pref.dart'; import 'package:nc_photos/pref.dart';
import 'package:nc_photos/throttler.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/ls.dart';
import 'package:nc_photos/use_case/scan_dir.dart'; import 'package:nc_photos/use_case/scan_dir.dart';
import 'package:nc_photos/use_case/scan_dir_offline.dart'; import 'package:nc_photos/use_case/scan_dir_offline.dart';
@ -307,7 +308,7 @@ class ScanAccountDirBloc
Stream<ScanAccountDirBlocState> _queryOnline( Stream<ScanAccountDirBlocState> _queryOnline(
ScanAccountDirBlocQueryBase ev, List<File>? cache) async* { ScanAccountDirBlocQueryBase ev, List<File>? cache) async* {
// 1st pass: scan for new files // 1st pass: scan for new files
final files = <File>[]; var files = <File>[];
{ {
final stopwatch = Stopwatch()..start(); final stopwatch = Stopwatch()..start();
final fileRepo = FileRepo(FileCachedDataSource(AppDb(), final fileRepo = FileRepo(FileCachedDataSource(AppDb(),
@ -336,32 +337,56 @@ class ScanAccountDirBloc
yield ScanAccountDirBlocLoading(files); yield ScanAccountDirBlocLoading(files);
} }
if (_shouldCheckCache) { try {
// 2nd pass: check outdated cache if (_shouldCheckCache) {
_shouldCheckCache = false; // 2nd pass: check outdated cache
final stopwatch = Stopwatch()..start(); _shouldCheckCache = false;
final fileRepo = FileRepo(FileCachedDataSource(AppDb(), files = await _queryOnlinePass2(ev, files);
shouldCheckCache: true,
forwardCacheManager: FileForwardCacheManager(AppDb())));
final fileRepoNoCache =
FileRepo(FileCachedDataSource(AppDb(), shouldCheckCache: true));
final newFiles = <File>[];
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);
} }
_log.info( } catch (e, stackTrace) {
"[_queryOnline] Elapsed time (pass2): ${stopwatch.elapsedMilliseconds}ms"); _log.shout(
yield ScanAccountDirBlocSuccess(newFiles); "[_queryOnline] Failed while _queryOnlinePass2", e, stackTrace);
} else {
yield ScanAccountDirBlocSuccess(files);
} }
yield ScanAccountDirBlocSuccess(files);
}
Future<List<File>> _queryOnlinePass2(
ScanAccountDirBlocQueryBase ev, List<File> 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 = <File>[];
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 /// Emit all files under this account

View file

@ -236,6 +236,14 @@ class AccountPref {
value, value,
(key, value) => provider.setBool(key, value)); (key, value) => provider.setBool(key, value));
String? getTouchRootEtag() => provider.getString(PrefKey.touchRootEtag);
String getTouchRootEtagOr([String def = ""]) => getTouchRootEtag() ?? def;
Future<bool> setTouchRootEtag(String value) => _set<String>(
PrefKey.touchRootEtag,
value,
(key, value) => provider.setString(key, value));
Future<bool> removeTouchRootEtag() => _remove(PrefKey.touchRootEtag);
Future<bool> _set<T>(PrefKey key, T value, Future<bool> _set<T>(PrefKey key, T value,
Future<bool> Function(PrefKey key, T value) setFn) async { Future<bool> Function(PrefKey key, T value) setFn) async {
if (await setFn(key, value)) { if (await setFn(key, value)) {
@ -248,6 +256,8 @@ class AccountPref {
} }
} }
Future<bool> _remove(PrefKey key) => provider.remove(key);
final PrefProvider provider; final PrefProvider provider;
static final _insts = <String, AccountPref>{}; static final _insts = <String, AccountPref>{};
@ -267,6 +277,7 @@ abstract class PrefProvider {
List<String>? getStringList(PrefKey key); List<String>? getStringList(PrefKey key);
Future<bool> setStringList(PrefKey key, List<String> value); Future<bool> setStringList(PrefKey key, List<String> value);
Future<bool> remove(PrefKey key);
Future<bool> clear(); Future<bool> clear();
} }
@ -311,6 +322,9 @@ class PrefSharedPreferencesProvider extends PrefProvider {
setStringList(PrefKey key, List<String> value) => setStringList(PrefKey key, List<String> value) =>
_pref.setStringList(key.toStringKey(), value); _pref.setStringList(key.toStringKey(), value);
@override
remove(PrefKey key) => _pref.remove(key.toStringKey());
@override @override
clear() => _pref.clear(); clear() => _pref.clear();
@ -348,6 +362,14 @@ class PrefUniversalStorageProvider extends PrefProvider {
@override @override
setStringList(PrefKey key, List<String> value) => _set(key, value); setStringList(PrefKey key, List<String> 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 @override
clear() async { clear() async {
await platform.UniversalStorage().remove(name); await platform.UniversalStorage().remove(name);
@ -395,6 +417,12 @@ class PrefMemoryProvider extends PrefProvider {
@override @override
setStringList(PrefKey key, List<String> value) => _set(key, value); setStringList(PrefKey key, List<String> value) => _set(key, value);
@override
remove(PrefKey key) async {
_data.remove(key);
return true;
}
@override @override
clear() async { clear() async {
_data.clear(); _data.clear();
@ -439,6 +467,7 @@ enum PrefKey {
shareFolder, shareFolder,
hasNewSharedAlbum, hasNewSharedAlbum,
isEnableMemoryAlbum, isEnableMemoryAlbum,
touchRootEtag,
} }
extension on PrefKey { extension on PrefKey {
@ -496,6 +525,8 @@ extension on PrefKey {
return "hasNewSharedAlbum"; return "hasNewSharedAlbum";
case PrefKey.isEnableMemoryAlbum: case PrefKey.isEnableMemoryAlbum:
return "isEnableMemoryAlbum"; return "isEnableMemoryAlbum";
case PrefKey.touchRootEtag:
return "touchRootEtag";
} }
} }
} }

View file

@ -8,6 +8,7 @@ import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/exception.dart'; import 'package:nc_photos/exception.dart';
import 'package:nc_photos/mobile/platform.dart' import 'package:nc_photos/mobile/platform.dart'
if (dart.library.html) 'package:nc_photos/web/platform.dart' as platform; 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/remote_storage_util.dart' as remote_storage_util;
import 'package:nc_photos/use_case/get_file_binary.dart'; import 'package:nc_photos/use_case/get_file_binary.dart';
import 'package:nc_photos/use_case/put_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 { class TouchTokenManager {
const TouchTokenManager(); const TouchTokenManager();
Future<String?> 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<void> setLocalRootEtag(Account account, String? etag) async {
if (etag == null) {
await AccountPref.of(account).removeTouchRootEtag();
} else {
await AccountPref.of(account).setTouchRootEtag(etag);
}
}
Future<String?> getLocalRootEtag(Account account) async {
return AccountPref.of(account).getTouchRootEtag();
}
Future<void> setRemoteToken( Future<void> setRemoteToken(
FileRepo fileRepo, Account account, File file, String? token) async { FileRepo fileRepo, Account account, File file, String? token) async {
_log.info( _log.info(