import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:logging/logging.dart'; import '../core/client_core.dart'; import '../core/system_info.dart'; import '../core/mining_manager.dart'; import '../core/sustain_miner.dart'; import '../core/database.dart'; import '../core/mining_task_info.dart'; import '../services/config_service.dart'; import '../services/update_service.dart'; import '../models/client_status.dart'; /// 客户端状态管理 Provider class ClientProvider with ChangeNotifier { final Logger _logger = Logger('ClientProvider'); final ClientCore _clientCore = ClientCore(); final SystemInfoService _systemInfo = SystemInfoService(); final MiningManager _miningManager = MiningManager(); final SustainMiner _sustainMiner = SustainMiner(); final DatabaseService _database = DatabaseService(); final ConfigService _configService = ConfigService(); final UpdateService _updateService = UpdateService(); Timer? _refreshTimer; ClientInfo? _clientInfo; bool _isInitialized = false; bool _isLoading = false; MiningTaskInfo? _currentMiningTask; // 服务器地址(从配置文件读取) String? _serverUrl; // 版本信息 String? _remoteVersion; bool _hasUpdate = false; ClientProvider() { _initialize(); } /// 初始化客户端 Future _initialize() async { _isLoading = true; notifyListeners(); try { // 初始化数据库 await _database.initialize(); // 加载系统信息(先加载简单的文件读取,延迟执行 Process 调用) final version = await _systemInfo.getVersion(); final auth = await _systemInfo.getAuth(); // 检查权限 final hasPermission = await _systemInfo.checkAdminPermission(); if (!hasPermission) { _logger.warning('未检测到管理员权限'); } // 加载挖矿配置 final miningConfig = await _configService.parseMiningConfig(); // 从配置文件读取服务器地址 _serverUrl = miningConfig?.serverUrl ?? '18.183.240.108:2345'; // 检查版本更新(如果有配置 update_url) if (miningConfig?.updateUrl != null) { _checkForUpdates(miningConfig!.updateUrl!, version); } // 获取机器码和GPU信息(延迟执行,避免启动时崩溃) // 只在启动时获取一次,如果失败就显示空列表 String machineCode = '正在获取...'; List gpus = []; try { // 延迟3秒后获取,避免启动时崩溃 await Future.delayed(const Duration(seconds: 3)); _logger.info('开始获取系统信息...'); machineCode = await _systemInfo.getMachineCode(); gpus = await _systemInfo.getGPUInfo(); _logger.info('系统信息获取完成: MAC=$machineCode, GPUs=${gpus.length}'); } catch (e) { _logger.warning('获取系统信息失败: $e'); // 获取失败时使用默认值 machineCode = '获取失败'; gpus = []; } // 准备GPU信息(转换为服务器需要的格式) final gpusMap = {}; for (var gpu in gpus) { gpusMap[gpu.index.toString()] = gpu.toJson(); } // 获取支持的挖矿软件列表 final miningSofts = _getMiningSofts(miningConfig); // 初始化客户端核心(先连接,但不发送身份认证) final initialized = await _clientCore.initialize( serverUrl: _serverUrl ?? '18.183.240.108:2345', auth: auth, machineCode: machineCode, // 此时可能还是"正在获取...",需要等待真实值 gpusInfo: gpusMap, miningSofts: miningSofts, ); if (!initialized) { _logger.severe('客户端初始化失败'); // 即使初始化失败,也创建 ClientInfo 以便显示基本信息 _clientInfo = ClientInfo( version: version, auth: auth, gpus: gpus, machineCode: machineCode, status: ClientStatus.offline, miningInfo: null, ); _isInitialized = true; _isLoading = false; notifyListeners(); return; } // 设置回调 _clientCore.onStatusChanged = _onStatusChanged; _clientCore.onMiningTaskChanged = _onMiningTaskChanged; // 等待机器码获取完成后,发送身份认证消息(使用 身份信息::硬盘身份码 格式) if (machineCode != '正在获取...' && machineCode != '获取失败') { // 更新客户端核心的机器码 _clientCore.updateMachineCode(machineCode, gpusMap, miningSofts); // 发送身份认证消息 _clientCore.sendMachineCode(); } // 恢复未完成的挖矿任务 final unfinishedTask = await _database.loadUnfinishedTask(); if (unfinishedTask != null) { if (miningConfig != null) { await _miningManager.startMining(unfinishedTask, miningConfig); _currentMiningTask = unfinishedTask; } } // 加载持续挖矿配置并启动(恢复任务之后) if (miningConfig != null) { final loaded = await _sustainMiner.loadConfig(miningConfig); if (loaded && _currentMiningTask == null) { await _sustainMiner.start(); } } // 更新客户端信息 _clientInfo = ClientInfo( version: version, auth: auth, gpus: gpus.map((gpu) => GPUInfo( index: gpu.index, brand: gpu.brand, model: gpu.model, memory: gpu.memory, )).toList(), machineCode: machineCode, status: _getInitialStatus(), miningInfo: _getMiningInfo(), ); _isInitialized = true; _startAutoRefresh(); } catch (e, stackTrace) { _logger.severe('初始化失败: $e', e, stackTrace); // 即使初始化失败,也创建基本的 ClientInfo 以便显示错误信息 try { final version = await _systemInfo.getVersion(); final auth = await _systemInfo.getAuth(); _clientInfo = ClientInfo( version: version, auth: auth, gpus: [], machineCode: '初始化失败', status: ClientStatus.offline, miningInfo: null, ); } catch (e2) { _logger.severe('创建基本 ClientInfo 也失败: $e2'); // 如果连基本信息都获取不到,至少创建一个空的信息对象 _clientInfo = ClientInfo( version: '未知', auth: '未知', gpus: [], machineCode: '错误', status: ClientStatus.offline, miningInfo: null, ); } } finally { _isLoading = false; notifyListeners(); } } /// 状态变化回调 void _onStatusChanged(ClientStatus status) { if (_clientInfo != null) { // 判断当前状态:优先显示挖矿状态 ClientStatus newStatus; if (_miningManager.isMining) { // 如果有租约任务,显示挖矿中;否则显示持续挖矿中 newStatus = _currentMiningTask != null ? ClientStatus.mining : (_sustainMiner.isRunning ? ClientStatus.sustainingMining : ClientStatus.mining); } else { newStatus = status; } _clientInfo = ClientInfo( version: _clientInfo!.version, auth: _clientInfo!.auth, gpus: _clientInfo!.gpus, machineCode: _clientInfo!.machineCode, status: newStatus, miningInfo: _getMiningInfo(), ); notifyListeners(); } } /// 挖矿任务变化回调 void _onMiningTaskChanged(MiningTaskInfo? task) async { final previousTask = _currentMiningTask; _currentMiningTask = task; if (task != null) { // 暂停持续挖矿 await _sustainMiner.pause(); // 启动挖矿 final miningConfig = await _configService.parseMiningConfig(); if (miningConfig != null) { await _miningManager.startMining(task, miningConfig); await _database.insertMiningTask(task); } } else { // 停止挖矿 await _miningManager.stopMining(); // 挖矿任务完成后,从日志中删除该任务 if (previousTask != null) { await _database.finishMiningTask(previousTask); } // 恢复持续挖矿 await _sustainMiner.resume(); } // 更新状态 _onStatusChanged(_clientCore.isConnected ? ClientStatus.online : ClientStatus.offline); } /// 开始自动刷新 void _startAutoRefresh() { _refreshTimer?.cancel(); _refreshTimer = Timer.periodic(const Duration(seconds: 5), (_) { refresh(); }); } /// 手动刷新(不重新获取GPU信息,只更新状态) Future refresh() async { if (!_isInitialized || _clientInfo == null) return; try { // 只更新状态,不重新获取GPU信息(GPU信息只在启动时获取一次) ClientStatus status; if (_miningManager.isMining) { // 如果有租约任务,显示挖矿中;否则显示持续挖矿中 status = _currentMiningTask != null ? ClientStatus.mining : (_sustainMiner.isRunning ? ClientStatus.sustainingMining : ClientStatus.mining); } else { status = _clientCore.isConnected ? ClientStatus.online : ClientStatus.offline; } _clientInfo = ClientInfo( version: _clientInfo!.version, auth: _clientInfo!.auth, gpus: _clientInfo!.gpus, // 使用已有的GPU信息,不重新获取 machineCode: _clientInfo!.machineCode, status: status, miningInfo: _getMiningInfo(), ); notifyListeners(); } catch (e) { _logger.warning('刷新失败: $e'); } } /// 获取初始状态 ClientStatus _getInitialStatus() { if (_miningManager.isMining) { return _currentMiningTask != null ? ClientStatus.mining : (_sustainMiner.isRunning ? ClientStatus.sustainingMining : ClientStatus.mining); } return _clientCore.isConnected ? ClientStatus.online : ClientStatus.offline; } /// 获取挖矿信息(支持租约挖矿和持续挖矿) MiningInfo? _getMiningInfo() { if (_currentMiningTask != null) { // 租约挖矿任务 return MiningInfo( coin: _currentMiningTask!.coin, algo: _currentMiningTask!.algo, pool: _currentMiningTask!.pool, poolUrl: _currentMiningTask!.poolUrl, walletAddress: _currentMiningTask!.walletAddress, workerId: _currentMiningTask!.workerId, pid: null, miner: _currentMiningTask!.miner, endTimestamp: _currentMiningTask!.endTimestamp, ); } else if (_miningManager.isMining && _sustainMiner.isRunning) { // 持续挖矿任务 final sustainTask = _miningManager.currentTask; if (sustainTask != null) { return MiningInfo( coin: sustainTask.coin, algo: sustainTask.algo, pool: sustainTask.pool, poolUrl: sustainTask.poolUrl, walletAddress: sustainTask.walletAddress, workerId: sustainTask.workerId, pid: null, miner: sustainTask.miner, endTimestamp: sustainTask.endTimestamp, ); } } return null; } /// 重启客户端 Future restart() async { _clientCore.stop(); await _miningManager.stopMining(); await _sustainMiner.stop(); _isInitialized = false; await _initialize(); } /// 获取支持的挖矿软件列表(辅助方法) List _getMiningSofts(MiningConfig? miningConfig) { final miningSofts = []; if (miningConfig?.lolMinerPath != null && miningConfig!.lolMinerPath!.isNotEmpty) { miningSofts.add('lolminer'); } if (miningConfig?.rigelPath != null && miningConfig!.rigelPath!.isNotEmpty) { miningSofts.add('rigel'); } if (miningConfig?.bzMinerPath != null && miningConfig!.bzMinerPath!.isNotEmpty) { miningSofts.add('bzminer'); } return miningSofts; } /// 获取日志流 Stream get logStream => _clientCore.logStream; ClientInfo? get clientInfo => _clientInfo; bool get isLoading => _isLoading; bool get isInitialized => _isInitialized; bool get hasUpdate => _hasUpdate; String? get remoteVersion => _remoteVersion; /// 检查版本更新 Future _checkForUpdates(String updateUrl, String localVersion) async { try { final remoteInfo = await _updateService.checkVersion(updateUrl); if (remoteInfo != null) { _remoteVersion = remoteInfo.version; _hasUpdate = _updateService.isNewerVersion(remoteInfo.version, localVersion); if (_hasUpdate) { _logger.info('发现新版本: $localVersion -> ${remoteInfo.version}'); } notifyListeners(); } } catch (e) { _logger.warning('检查更新失败: $e'); } } /// 执行更新 Future performUpdate() async { if (!_hasUpdate || _remoteVersion == null) { return false; } try { final miningConfig = await _configService.parseMiningConfig(); if (miningConfig?.updateUrl == null) { _logger.warning('更新URL未配置'); return false; } // 获取下载URL final remoteInfo = await _updateService.checkVersion(miningConfig!.updateUrl!); if (remoteInfo == null || remoteInfo.downloadUrl.isEmpty) { _logger.warning('无法获取下载URL'); return false; } // 下载并更新 final success = await _updateService.downloadAndUpdate(remoteInfo.downloadUrl); if (success) { _logger.info('更新下载完成,将在下次启动时应用'); } return success; } catch (e) { _logger.severe('执行更新失败: $e'); return false; } } @override void dispose() { _refreshTimer?.cancel(); _clientCore.stop(); _database.close(); super.dispose(); } }