feat: 添加缓存作用域支持多用户数据隔离
This commit is contained in:
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
typedef CacheScopeProvider = String? Function();
|
||||
|
||||
class CacheScope {
|
||||
CacheScope._();
|
||||
|
||||
static CacheScopeProvider? _provider;
|
||||
|
||||
static void configureProvider(CacheScopeProvider provider) {
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
static void resetProvider() {
|
||||
_provider = null;
|
||||
}
|
||||
|
||||
static String token() {
|
||||
final raw = _provider?.call()?.trim();
|
||||
if (raw == null || raw.isEmpty) {
|
||||
return 'anonymous';
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
static String scopedKey(String key, {String? scopeToken}) {
|
||||
final scope = scopeToken ?? token();
|
||||
return 'cache:$scope:$key';
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -3,6 +3,8 @@ import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'cache_scope.dart';
|
||||
|
||||
class CacheEntry<T> {
|
||||
const CacheEntry({required this.value, required this.fetchedAt});
|
||||
|
||||
@@ -196,7 +198,7 @@ class CacheInvalidator {
|
||||
void invalidate(String key) {
|
||||
final store = _store;
|
||||
if (store != null) {
|
||||
unawaited(store.remove(key));
|
||||
unawaited(store.remove(CacheScope.scopedKey(key)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-13
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'cache_scope.dart';
|
||||
import 'cache_policy.dart';
|
||||
import 'cache_store.dart';
|
||||
|
||||
@@ -31,18 +32,21 @@ abstract class CachedRepository<T> {
|
||||
bool Function(T loaded)? shouldWriteLoaded,
|
||||
bool forceRefresh = false,
|
||||
}) async {
|
||||
final scopeToken = CacheScope.token();
|
||||
final scopedKey = CacheScope.scopedKey(key, scopeToken: scopeToken);
|
||||
|
||||
if (forceRefresh) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
scopedKey,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
final cached = await readCacheEntry(key);
|
||||
final cached = await _readDecodedEntry(scopedKey);
|
||||
if (cached == null) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
scopedKey,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
@@ -51,14 +55,14 @@ abstract class CachedRepository<T> {
|
||||
final decision = policy.evaluate(now: now(), fetchedAt: cached.fetchedAt);
|
||||
if (decision.shouldRefreshInBackground) {
|
||||
refreshInBackground(
|
||||
key: key,
|
||||
key: scopedKey,
|
||||
loadFromRemote: loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
}
|
||||
if (decision.mustBlockForNetwork || !decision.canUseCached) {
|
||||
return _refreshAndWrite(
|
||||
key,
|
||||
scopedKey,
|
||||
loadFromRemote,
|
||||
shouldWriteLoaded: shouldWriteLoaded,
|
||||
);
|
||||
@@ -66,13 +70,13 @@ abstract class CachedRepository<T> {
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
Future<CacheEntry<T>?> readCacheEntry(String key) {
|
||||
return _readDecodedEntry(key);
|
||||
Future<CacheEntry<T>?> readCacheEntry(String key, {String? scopeToken}) {
|
||||
return _readDecodedEntry(CacheScope.scopedKey(key, scopeToken: scopeToken));
|
||||
}
|
||||
|
||||
Future<void> writeCacheEntry(String key, T value) {
|
||||
Future<void> writeCacheEntry(String key, T value, {String? scopeToken}) {
|
||||
return store.write<CacheEntry<Object?>>(
|
||||
key,
|
||||
_scopedKey(key, scopeToken: scopeToken),
|
||||
CacheEntry<Object?>(value: encodeValue(value), fetchedAt: now()),
|
||||
);
|
||||
}
|
||||
@@ -93,8 +97,8 @@ abstract class CachedRepository<T> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> removeCacheKey(String key) {
|
||||
return store.remove(key);
|
||||
Future<void> removeCacheKey(String key, {String? scopeToken}) {
|
||||
return store.remove(CacheScope.scopedKey(key, scopeToken: scopeToken));
|
||||
}
|
||||
|
||||
void refreshInBackground({
|
||||
@@ -118,7 +122,7 @@ abstract class CachedRepository<T> {
|
||||
}
|
||||
|
||||
Future<T> _refreshAndWrite(
|
||||
String key,
|
||||
String scopedKey,
|
||||
Future<T> Function() loadFromRemote, {
|
||||
bool Function(T loaded)? shouldWriteLoaded,
|
||||
}) async {
|
||||
@@ -126,7 +130,14 @@ abstract class CachedRepository<T> {
|
||||
if (shouldWriteLoaded != null && !shouldWriteLoaded(remote)) {
|
||||
return remote;
|
||||
}
|
||||
await writeCacheEntry(key, remote);
|
||||
await store.write<CacheEntry<Object?>>(
|
||||
scopedKey,
|
||||
CacheEntry<Object?>(value: encodeValue(remote), fetchedAt: now()),
|
||||
);
|
||||
return remote;
|
||||
}
|
||||
|
||||
String _scopedKey(String key, {String? scopeToken}) {
|
||||
return CacheScope.scopedKey(key, scopeToken: scopeToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user