import 'dart:async'; import '../core/utils/app_logger.dart'; import '../data/models/sync_config_model.dart'; import '../data/models/sync_event_model.dart'; import '../data/models/sync_status_model.dart'; import '../data/models/sync_task_model.dart'; import '../src/rust/api/ffi.dart' as ffi; import '../src/rust/api/ffi_types.dart' as ffi_types; /// 同步服务单例 - 桥接 Flutter UI 和 Rust 同步引擎 class SyncService { static final SyncService instance = SyncService._(); SyncService._(); bool _initialized = false; /// 事件流,供 SyncProvider 订阅 final _eventController = StreamController.broadcast(); Stream get events => _eventController.stream; /// 初始化同步引擎(已初始化时更新配置) Future init(SyncConfigModel config) async { if (_initialized) { AppLogger.d('[FFI] → updateSyncConfig: mode=${config.syncMode}, conflict=${config.conflictStrategy}, concurrent=${config.maxConcurrentTransfers}, bandwidth=${config.bandwidthLimitKbps}kbps'); await ffi.updateSyncConfig(config: config.toFfi()); AppLogger.d('[FFI] ← updateSyncConfig: ok'); return; } AppLogger.d('[FFI] → initSyncEngine: localRoot=${config.localRoot}, mode=${config.syncMode}, conflict=${config.conflictStrategy}, logLevel=${config.logLevel}'); await ffi.initSyncEngine(config: config.toFfi()); _initialized = true; AppLogger.d('[FFI] ← initSyncEngine: ok'); } /// 执行初始全量同步 Future startInitialSync() async { AppLogger.d('[FFI] → startInitialSync'); final summary = await ffi.startInitialSync(); AppLogger.d('[FFI] ← startInitialSync: uploaded=${summary.uploaded}, downloaded=${summary.downloaded}, conflicts=${summary.conflicts}, failed=${summary.failed}'); return SyncSummaryModel.fromFfi(summary); } /// 启动持续同步 Future startContinuousSync() async { AppLogger.d('[FFI] → startContinuousSync'); await ffi.startContinuousSync(); AppLogger.d('[FFI] ← startContinuousSync: spawned'); } /// 停止同步 Future stop() async { AppLogger.d('[FFI] → stopSync'); await ffi.stopSync(); AppLogger.d('[FFI] ← stopSync: ok'); } /// 暂停同步 Future pause() async { AppLogger.d('[FFI] → pauseSync'); await ffi.pauseSync(); AppLogger.d('[FFI] ← pauseSync: ok'); } /// 恢复同步 Future resume() async { AppLogger.d('[FFI] → resumeSync'); await ffi.resumeSync(); AppLogger.d('[FFI] ← resumeSync: ok'); } /// 强制重新同步 Future forceSync() async { AppLogger.d('[FFI] → forceSync'); final summary = await ffi.forceSync(); AppLogger.d('[FFI] ← forceSync: uploaded=${summary.uploaded}, downloaded=${summary.downloaded}, conflicts=${summary.conflicts}, failed=${summary.failed}'); return SyncSummaryModel.fromFfi(summary); } /// Token 变更时推送给 Rust Future updateTokens(String accessToken) async { AppLogger.d('[FFI] → updateTokens: token_len=${accessToken.length}'); await ffi.updateTokens(accessToken: accessToken); AppLogger.d('[FFI] ← updateTokens: ok'); } /// 更新同步配置(推送到 Rust 引擎,引擎未初始化时忽略) Future updateConfig(SyncConfigModel config) async { if (!_initialized) return; AppLogger.d('[FFI] → updateSyncConfig: mode=${config.syncMode}, conflict=${config.conflictStrategy}, concurrent=${config.maxConcurrentTransfers}, bandwidth=${config.bandwidthLimitKbps}kbps'); try { await ffi.updateSyncConfig(config: config.toFfi()); AppLogger.d('[FFI] ← updateSyncConfig: ok'); } catch (e) { AppLogger.e('[FFI] ← updateSyncConfig: error=$e'); } } // ========== 以下为轮询/查询类,用 trace 避免刷屏 ========== /// 获取同步状态快照(轮询高频调用,trace 级别) Future getStatus() async { final status = await ffi.getSyncStatus(); AppLogger.t('[FFI] ← getSyncStatus: state=${status.state}, synced=${status.syncedFiles}, total=${status.totalFiles}'); return SyncStatusModel.fromFfi(status); } /// 获取活跃 Worker 数量(轮询高频调用,trace 级别) Future getActiveWorkerCount() async { final count = await ffi.getActiveWorkerCount(); AppLogger.t('[FFI] ← getActiveWorkerCount: $count'); return count; } /// 获取活跃的同步任务列表(轮询高频调用,trace 级别) Future> getActiveTasksTyped() async { final tasks = await ffi.getActiveTasks(); AppLogger.t('[FFI] ← getActiveTasks: count=${tasks.length}'); return tasks.map((t) => SyncTaskModel( id: t.id, trigger: t.trigger, totalCount: t.totalCount, completedCount: t.completedCount, failedCount: t.failedCount, status: t.status, createdAt: t.createdAt, updatedAt: t.updatedAt, finishedAt: t.finishedAt, )).toList(); } /// 获取最近同步任务列表(轮询高频调用,trace 级别) Future> getRecentTasksTyped({int limit = 20}) async { AppLogger.t('[FFI] → getRecentTasks: limit=$limit'); final tasks = await ffi.getRecentTasks(limit: limit); AppLogger.t('[FFI] ← getRecentTasks: count=${tasks.length}'); return tasks.map((t) => SyncTaskModel( id: t.id, trigger: t.trigger, totalCount: t.totalCount, completedCount: t.completedCount, failedCount: t.failedCount, status: t.status, createdAt: t.createdAt, updatedAt: t.updatedAt, finishedAt: t.finishedAt, )).toList(); } /// 获取任务详情(按需查询,trace 级别) Future> getTaskDetailTyped(String taskId) async { AppLogger.t('[FFI] → getTaskDetail: taskId=$taskId'); final items = await ffi.getTaskDetail(taskId: taskId); AppLogger.t('[FFI] ← getTaskDetail: count=${items.length}'); return items.map((i) => SyncTaskItemModel( id: i.id.toInt(), taskId: i.taskId, relativePath: i.relativePath, actionType: i.actionType, status: i.status, fileSize: i.fileSize.toInt(), errorMessage: i.errorMessage, createdAt: i.createdAt, updatedAt: i.updatedAt, )).toList(); } /// 分页查询任务详情(trace 级别) Future> queryTaskItemsTyped({ required String taskId, int limit = 20, int offset = 0, }) async { AppLogger.t('[FFI] → queryTaskItems: taskId=$taskId, limit=$limit, offset=$offset'); final items = await ffi.queryTaskItems(filter: ffi_types.TaskItemFilterFfi( taskId: taskId, limit: limit, offset: offset, )); AppLogger.t('[FFI] ← queryTaskItems: count=${items.length}'); return items.map((i) => SyncTaskItemModel( id: i.id.toInt(), taskId: i.taskId, relativePath: i.relativePath, actionType: i.actionType, status: i.status, fileSize: i.fileSize.toInt(), errorMessage: i.errorMessage, createdAt: i.createdAt, updatedAt: i.updatedAt, )).toList(); } // ========== 以下为低频操作,保持 debug 级别 ========== /// 水合文件 (Windows CFAPi) Future hydrateFile(String localPath) async { AppLogger.d('[FFI] → hydrateFile: path=$localPath'); await ffi.hydrateFile(localPath: localPath); AppLogger.d('[FFI] ← hydrateFile: ok'); } /// 检查云端相册目录 (Android) Future> checkCloudAlbumDirs(String baseUri) async { AppLogger.d('[FFI] → checkCloudAlbumDirs: uri=$baseUri'); final result = await ffi.checkCloudAlbumDirs(baseUri: baseUri); AppLogger.d('[FFI] ← checkCloudAlbumDirs: dcim=${result.dcimExists}, pictures=${result.picturesExists}'); return { 'dcimExists': result.dcimExists, 'picturesExists': result.picturesExists, 'dcimUri': result.dcimUri, 'picturesUri': result.picturesUri, }; } /// 创建云端相册目录 (Android) Future createCloudAlbumDirs(String baseUri) async { AppLogger.d('[FFI] → createCloudAlbumDirs: uri=$baseUri'); await ffi.createCloudAlbumDirs(baseUri: baseUri); AppLogger.d('[FFI] ← createCloudAlbumDirs: ok'); } /// 销毁同步引擎 Future dispose() async { AppLogger.d('[FFI] → disposeSyncEngine'); await _eventController.close(); await ffi.disposeSyncEngine(); _initialized = false; AppLogger.d('[FFI] ← disposeSyncEngine: ok'); } /// 热修改日志级别(立即生效,无需重启) Future setLogLevel(String level) async { AppLogger.d('[FFI] → setSyncLogLevel: level=$level'); await ffi.setSyncLogLevel(level: level); AppLogger.d('[FFI] ← setSyncLogLevel: ok'); } /// 重置同步:停止任务 → 清空 DB → 清空本地目录 → 回到初始状态 Future resetSync() async { AppLogger.d('[FFI] → resetSync'); await ffi.resetSync(); AppLogger.d('[FFI] ← resetSync: ok'); } }