import 'dart:convert'; import 'dart:io'; import '../interfaces/resume_storage.dart'; // 注意:这个实现需要 path_provider 包 // 在实际使用时需要在 pubspec.yaml 中添加 path_provider: ^2.1.0 /// 基于本地文件的断点续传存储实现 class LocalResumeStorage implements ResumeStorage { static const String _storageDir = 'yx_oss_resume'; static const String _fileExtension = '.json'; Directory? _cacheDirectory; /// 获取缓存目录 Future get cacheDirectory async { if (_cacheDirectory != null) { return _cacheDirectory!; } // 简化实现:使用临时目录,避免依赖 path_provider // 在实际集成时可以替换为 getApplicationDocumentsDirectory() final tempDir = Directory.systemTemp; _cacheDirectory = Directory('${tempDir.path}/$_storageDir'); // 确保目录存在 if (!await _cacheDirectory!.exists()) { await _cacheDirectory!.create(recursive: true); } return _cacheDirectory!; } /// 获取任务文件路径 Future _getTaskFile(String taskId) async { final dir = await cacheDirectory; return File('${dir.path}/$taskId$_fileExtension'); } @override Future saveResumeInfo( String taskId, Map resumeInfo) async { try { final file = await _getTaskFile(taskId); final jsonString = jsonEncode(resumeInfo); await file.writeAsString(jsonString); } catch (e) { throw Exception('Failed to save resume info for task $taskId: $e'); } } @override Future?> loadResumeInfo(String taskId) async { try { final file = await _getTaskFile(taskId); if (!await file.exists()) { return null; } final jsonString = await file.readAsString(); return jsonDecode(jsonString) as Map; } catch (e) { // 文件损坏或格式错误时删除文件 try { final file = await _getTaskFile(taskId); if (await file.exists()) { await file.delete(); } } catch (_) { // 忽略删除错误 } return null; } } @override Future deleteResumeInfo(String taskId) async { try { final file = await _getTaskFile(taskId); if (await file.exists()) { await file.delete(); } } catch (e) { // 忽略删除错误,可能文件已不存在 } } @override Future> getAllTaskIds() async { try { final dir = await cacheDirectory; if (!await dir.exists()) { return []; } final files = await dir.list().toList(); final taskIds = []; for (final file in files) { if (file is File && file.path.endsWith(_fileExtension)) { final fileName = file.path.split('/').last; final taskId = fileName.substring(0, fileName.length - _fileExtension.length); taskIds.add(taskId); } } return taskIds; } catch (e) { return []; } } @override Future clearAll() async { try { final dir = await cacheDirectory; if (await dir.exists()) { await dir.delete(recursive: true); } _cacheDirectory = null; // 重置缓存目录 } catch (e) { // 忽略删除错误 } } @override Future getStorageSize() async { try { final dir = await cacheDirectory; if (!await dir.exists()) { return 0; } int totalSize = 0; final files = await dir.list().toList(); for (final file in files) { if (file is File) { final stat = await file.stat(); totalSize += stat.size; } } return totalSize; } catch (e) { return 0; } } /// 清理过期的断点续传信息 /// /// [maxAge] 最大保留时间(天数) Future cleanupExpiredTasks(int maxAge) async { try { final dir = await cacheDirectory; if (!await dir.exists()) { return; } final cutoffTime = DateTime.now().subtract(Duration(days: maxAge)); final files = await dir.list().toList(); for (final file in files) { if (file is File && file.path.endsWith(_fileExtension)) { final stat = await file.stat(); if (stat.modified.isBefore(cutoffTime)) { try { await file.delete(); } catch (_) { // 忽略删除错误 } } } } } catch (e) { // 忽略清理错误 } } /// 获取任务的文件大小 Future getTaskFileSize(String taskId) async { try { final file = await _getTaskFile(taskId); if (await file.exists()) { final stat = await file.stat(); return stat.size; } return 0; } catch (e) { return 0; } } }