mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-23 01:06:21 +01:00
152 lines
4.1 KiB
Dart
152 lines
4.1 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:collection/collection.dart';
|
|
import 'package:logging/logging.dart';
|
|
import 'package:nc_photos/account.dart';
|
|
import 'package:nc_photos/entity/album.dart';
|
|
import 'package:nc_photos/entity/file.dart';
|
|
import 'package:nc_photos/entity/file_descriptor.dart';
|
|
import 'package:nc_photos/exception.dart';
|
|
import 'package:np_codegen/np_codegen.dart';
|
|
import 'package:np_common/type.dart';
|
|
|
|
part 'repo2.g.dart';
|
|
|
|
abstract class AlbumRepo2 {
|
|
/// Query all [Album]s defined by [albumFiles]
|
|
Stream<List<Album>> getAlbums(
|
|
Account account,
|
|
List<File> albumFiles, {
|
|
ErrorWithValueHandler<File>? onError,
|
|
});
|
|
|
|
/// Create a new [album]
|
|
Future<Album> create(Account account, Album album);
|
|
|
|
/// Update an [album]
|
|
Future<void> update(Account account, Album album);
|
|
}
|
|
|
|
class BasicAlbumRepo2 implements AlbumRepo2 {
|
|
const BasicAlbumRepo2(this.dataSrc);
|
|
|
|
@override
|
|
Stream<List<Album>> getAlbums(
|
|
Account account,
|
|
List<File> albumFiles, {
|
|
ErrorWithValueHandler<File>? onError,
|
|
}) async* {
|
|
yield await dataSrc.getAlbums(account, albumFiles, onError: onError);
|
|
}
|
|
|
|
@override
|
|
Future<Album> create(Account account, Album album) =>
|
|
dataSrc.create(account, album);
|
|
|
|
@override
|
|
Future<void> update(Account account, Album album) =>
|
|
dataSrc.update(account, album);
|
|
|
|
final AlbumDataSource2 dataSrc;
|
|
}
|
|
|
|
@npLog
|
|
class CachedAlbumRepo2 implements AlbumRepo2 {
|
|
const CachedAlbumRepo2(this.remoteDataSrc, this.cacheDataSrc);
|
|
|
|
@override
|
|
Stream<List<Album>> getAlbums(
|
|
Account account,
|
|
List<File> albumFiles, {
|
|
ErrorWithValueHandler<File>? onError,
|
|
}) async* {
|
|
// get cache
|
|
final cached = <Album>[];
|
|
final failed = <File>[];
|
|
try {
|
|
cached.addAll(await cacheDataSrc.getAlbums(
|
|
account,
|
|
albumFiles,
|
|
onError: (f, e, stackTrace) {
|
|
failed.add(f);
|
|
if (e is CacheNotFoundException) {
|
|
// not in cache, normal
|
|
} else {
|
|
_log.shout("[getAlbums] Cache failure", e, stackTrace);
|
|
}
|
|
},
|
|
));
|
|
yield cached;
|
|
} catch (e, stackTrace) {
|
|
_log.shout("[getAlbums] Failed while getAlbums", e, stackTrace);
|
|
}
|
|
final cachedGroup = cached.groupListsBy((c) {
|
|
try {
|
|
return _validateCache(
|
|
c, albumFiles.firstWhere(c.albumFile!.compareServerIdentity));
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// query remote
|
|
final outdated = [
|
|
...failed,
|
|
...cachedGroup[false]?.map((e) =>
|
|
albumFiles.firstWhere(e.albumFile!.compareServerIdentity)) ??
|
|
const <File>[],
|
|
];
|
|
final remote =
|
|
await remoteDataSrc.getAlbums(account, outdated, onError: onError);
|
|
yield (cachedGroup[true] ?? []) + remote;
|
|
|
|
// update cache
|
|
for (final a in remote) {
|
|
unawaited(cacheDataSrc.update(account, a));
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<Album> create(Account account, Album album) =>
|
|
remoteDataSrc.create(account, album);
|
|
|
|
@override
|
|
Future<void> update(Account account, Album album) async {
|
|
await remoteDataSrc.update(account, album);
|
|
try {
|
|
await cacheDataSrc.update(account, album);
|
|
} catch (e, stackTrace) {
|
|
_log.warning("[update] Failed to update cache", e, stackTrace);
|
|
}
|
|
}
|
|
|
|
/// Return true if the cached album is considered up to date
|
|
bool _validateCache(Album cache, File albumFile) {
|
|
if (cache.albumFile!.etag?.isNotEmpty == true &&
|
|
cache.albumFile!.etag == albumFile.etag) {
|
|
// cache is good
|
|
_log.fine("[_validateCache] etag matched for ${albumFile.path}");
|
|
return true;
|
|
} else {
|
|
_log.info(
|
|
"[_validateCache] Remote content updated for ${albumFile.path}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
final AlbumDataSource2 remoteDataSrc;
|
|
final AlbumDataSource2 cacheDataSrc;
|
|
}
|
|
|
|
abstract class AlbumDataSource2 {
|
|
/// Query all [Album]s defined by [albumFiles]
|
|
Future<List<Album>> getAlbums(
|
|
Account account,
|
|
List<File> albumFiles, {
|
|
ErrorWithValueHandler<File>? onError,
|
|
});
|
|
|
|
Future<Album> create(Account account, Album album);
|
|
|
|
Future<void> update(Account account, Album album);
|
|
}
|