二次开发源码提交
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:cloudreve4_flutter/core/utils/app_logger.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import '../data/models/cache_settings_model.dart';
|
||||
import '../core/constants/storage_keys.dart';
|
||||
import 'storage_service.dart';
|
||||
|
||||
/// 缓存管理器服务
|
||||
class CacheManagerService {
|
||||
static CacheManagerService? _instance;
|
||||
BaseCacheManager? _manager;
|
||||
CacheSettingsModel _settings = CacheSettingsModel();
|
||||
|
||||
CacheManagerService._();
|
||||
|
||||
/// 获取单例
|
||||
static CacheManagerService get instance {
|
||||
_instance ??= CacheManagerService._();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
/// 初始化
|
||||
Future<void> initialize() async {
|
||||
try {
|
||||
await loadSettings();
|
||||
await _initializeManager();
|
||||
} catch (e) {
|
||||
// 忽略初始化错误,使用默认值
|
||||
AppLogger.e('CacheManagerService initialize error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化管理器
|
||||
Future<void> _initializeManager() async {
|
||||
_manager = CacheManager(
|
||||
Config(
|
||||
'cloudreve_cache',
|
||||
stalePeriod: Duration(milliseconds: _settings.cacheExpireDuration),
|
||||
maxNrOfCacheObjects: 1000,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取缓存管理器
|
||||
BaseCacheManager get manager {
|
||||
if (_manager == null) {
|
||||
throw Exception('CacheManagerService 未初始化,请先调用 initialize()');
|
||||
}
|
||||
return _manager!;
|
||||
}
|
||||
|
||||
/// 获取缓存目录
|
||||
Future<Directory> getCacheDir() async {
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final cacheDir = Directory('${tempDir.path}/cloudreve_cache');
|
||||
if (!cacheDir.existsSync()) {
|
||||
cacheDir.createSync(recursive: true);
|
||||
}
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
/// 获取当前缓存大小
|
||||
Future<int> getCacheSize() async {
|
||||
final cacheDir = await getCacheDir();
|
||||
if (!cacheDir.existsSync()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
int totalSize = 0;
|
||||
final entities = cacheDir.listSync(recursive: true, followLinks: false);
|
||||
for (final entity in entities) {
|
||||
if (entity is File) {
|
||||
try {
|
||||
totalSize += entity.lengthSync();
|
||||
} catch (e) {
|
||||
// 忽略无法读取的文件
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalSize;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 清空缓存
|
||||
Future<void> clearCache() async {
|
||||
final cacheDir = await getCacheDir();
|
||||
if (cacheDir.existsSync()) {
|
||||
try {
|
||||
await cacheDir.delete(recursive: true);
|
||||
} on PathAccessException {
|
||||
// Windows 文件占用,逐个删除可删除的文件
|
||||
try {
|
||||
final entities = cacheDir.listSync(recursive: true, followLinks: false);
|
||||
for (final entity in entities) {
|
||||
if (entity is File) {
|
||||
try { await entity.delete(); } catch (_) {}
|
||||
}
|
||||
}
|
||||
try { await cacheDir.delete(recursive: true); } catch (_) {}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
await _manager?.emptyCache();
|
||||
} on PathAccessException {
|
||||
// nothing to do
|
||||
}
|
||||
await _initializeManager();
|
||||
}
|
||||
|
||||
/// 清理过期文件
|
||||
Future<void> cleanExpiredFiles() async {
|
||||
try {
|
||||
await manager.emptyCache();
|
||||
} catch (e) {
|
||||
// 忽略清理错误
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载设置
|
||||
Future<void> loadSettings() async {
|
||||
final settingsJson = await StorageService.instance.getString(
|
||||
StorageKeys.cacheSettings,
|
||||
);
|
||||
if (settingsJson != null && settingsJson.isNotEmpty) {
|
||||
try {
|
||||
final settings = CacheSettingsModel.fromJson(
|
||||
jsonDecode(settingsJson) as Map<String, dynamic>,
|
||||
);
|
||||
_settings = settings;
|
||||
} catch (e) {
|
||||
// 使用默认设置
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 保存设置
|
||||
Future<void> saveSettings(CacheSettingsModel settings) async {
|
||||
_settings = settings;
|
||||
await StorageService.instance.setString(
|
||||
StorageKeys.cacheSettings,
|
||||
jsonEncode(settings.toJson()),
|
||||
);
|
||||
await _initializeManager();
|
||||
}
|
||||
|
||||
/// 获取当前设置
|
||||
CacheSettingsModel get settings => _settings;
|
||||
|
||||
/// 获取缓存文件信息
|
||||
Future<List<CacheFileInfo>> getCacheFiles() async {
|
||||
final cacheDir = await getCacheDir();
|
||||
final files = <CacheFileInfo>[];
|
||||
|
||||
if (!cacheDir.existsSync()) {
|
||||
return files;
|
||||
}
|
||||
|
||||
await for (final entity in cacheDir.list(recursive: true, followLinks: false)) {
|
||||
if (entity is File) {
|
||||
try {
|
||||
final stat = await entity.stat();
|
||||
files.add(
|
||||
CacheFileInfo(
|
||||
path: entity.path,
|
||||
name: entity.uri.pathSegments.last,
|
||||
size: stat.size,
|
||||
lastModified: stat.modified,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
// 忽略无法读取的文件
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/// 删除指定的缓存文件
|
||||
Future<void> deleteCacheFile(String path) async {
|
||||
final file = File(path);
|
||||
if (file.existsSync()) {
|
||||
try {
|
||||
await file.delete();
|
||||
} on PathAccessException {
|
||||
// Windows 文件占用,忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 自动清理最旧文件(当超过最大缓存大小时)
|
||||
Future<void> autoCleanOldFiles() async {
|
||||
if (!_settings.autoCleanOldFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
final currentSize = await getCacheSize();
|
||||
if (currentSize <= _settings.maxCacheSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
final files = await getCacheFiles();
|
||||
// 按最后修改时间排序,最旧的在前
|
||||
files.sort((a, b) => a.lastModified.compareTo(b.lastModified));
|
||||
|
||||
int deletedSize = 0;
|
||||
for (final file in files) {
|
||||
if (currentSize - deletedSize <= _settings.maxCacheSize) {
|
||||
break;
|
||||
}
|
||||
await deleteCacheFile(file.path);
|
||||
deletedSize += file.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 缓存文件信息
|
||||
class CacheFileInfo {
|
||||
final String path;
|
||||
final String name;
|
||||
final int size;
|
||||
final DateTime lastModified;
|
||||
|
||||
CacheFileInfo({
|
||||
required this.path,
|
||||
required this.name,
|
||||
required this.size,
|
||||
required this.lastModified,
|
||||
});
|
||||
|
||||
String get sizeReadable {
|
||||
if (size < 1024) {
|
||||
return '$size B';
|
||||
} else if (size < 1024 * 1024) {
|
||||
return '${(size / 1024).toStringAsFixed(1)} KB';
|
||||
} else if (size < 1024 * 1024 * 1024) {
|
||||
return '${(size / (1024 * 1024)).toStringAsFixed(1)} MB';
|
||||
} else {
|
||||
return '${(size / (1024 * 1024 * 1024)).toStringAsFixed(1)} GB';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user