Files
windows-application/lib/core/sustain_miner.dart
2026-01-23 16:11:20 +08:00

261 lines
7.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:io';
import 'package:logging/logging.dart';
// import 'package:ini/ini.dart';
import 'mining_manager.dart';
import 'mining_task_info.dart';
import '../utils/ini_utils.dart';
import '../utils/path_utils.dart';
/// 持续挖矿管理器
class SustainMiner {
static final SustainMiner _instance = SustainMiner._internal();
factory SustainMiner() => _instance;
SustainMiner._internal();
final Logger _logger = Logger('SustainMiner');
final MiningManager _miningManager = MiningManager();
SustainMiningConfig? _config;
MiningConfig? _miningConfig;
Timer? _monitorTimer;
StreamSubscription<void>? _processExitSubscription;
bool _isRunning = false;
bool _isPaused = false;
/// 加载配置
Future<bool> loadConfig(MiningConfig miningConfig) async {
try {
_miningConfig = miningConfig;
final configFile = File(PathUtils.binFile('mining.windows.conf'));
if (!await configFile.exists()) {
_logger.warning('配置文件不存在');
return false;
}
final content = await configFile.readAsString();
final config = parseIni(content);
// ini 2.x: 使用 get(section, option)
final enabledStr = (config.get('sustain', 'enabled') ?? '').toLowerCase();
final enabled = enabledStr == 'true';
if (!enabled) {
_logger.info('持续挖矿未启用');
return false;
}
_config = SustainMiningConfig(
enabled: enabled,
algo: _trimQuotes(config.get('sustain', 'algo') ?? ''),
coin: _trimQuotes(config.get('sustain', 'coin') ?? ''),
miner: _trimQuotes(config.get('sustain', 'miner') ?? ''),
poolUrl: _trimQuotes(config.get('sustain', 'pool_url') ?? ''),
wallet: _trimQuotes(config.get('sustain', 'wallet') ?? ''),
workerId: _trimQuotes(config.get('sustain', 'worker_id') ?? ''),
poolUser: _trimQuotes(config.get('sustain', 'pool_user') ?? ''),
walletMining: (config.get('sustain', 'wallet_mining') ?? '').toLowerCase() == 'true',
);
// 验证配置
if (_config!.algo.isEmpty ||
_config!.coin.isEmpty ||
_config!.miner.isEmpty ||
_config!.poolUrl.isEmpty ||
_config!.wallet.isEmpty ||
_config!.workerId.isEmpty) {
_logger.severe('持续挖矿配置不完整');
return false;
}
// 验证挖矿软件路径
final minerPath = _getMinerPath(_config!.miner);
if (minerPath == null || minerPath.isEmpty) {
_logger.severe('${_config!.miner} 路径未配置');
return false;
}
_logger.info('持续挖矿配置加载成功: 算法=${_config!.algo}, 币种=${_config!.coin}, 挖矿软件=${_config!.miner}');
return true;
} catch (e) {
_logger.severe('加载持续挖矿配置失败: $e');
return false;
}
}
/// 启动持续挖矿
Future<void> start() async {
if (_config == null || !_config!.enabled) {
return;
}
if (_isRunning) {
_logger.info('持续挖矿已在运行中');
return;
}
if (_miningManager.isMining) {
_logger.info('当前有挖矿任务,等待任务结束后启动持续挖矿');
return;
}
_isRunning = true;
_isPaused = false;
_logger.info('启动持续挖矿...');
await _startMining();
_startProcessMonitor();
}
/// 停止持续挖矿
Future<void> stop() async {
_isRunning = false;
_monitorTimer?.cancel();
_monitorTimer = null;
_processExitSubscription?.cancel();
_processExitSubscription = null;
if (_miningManager.isMining && _miningManager.currentTask == null) {
// 只有持续挖矿任务在运行时才停止
await _miningManager.stopMining();
}
_logger.info('持续挖矿已停止');
}
/// 暂停持续挖矿
Future<void> pause() async {
if (!_isRunning || _isPaused) {
return;
}
_logger.info('暂停持续挖矿(有新任务)...');
_isPaused = true;
if (_miningManager.isMining && _miningManager.currentTask == null) {
await _miningManager.stopMining();
}
}
/// 恢复持续挖矿
Future<void> resume() async {
if (!_isRunning || !_isPaused) {
return;
}
if (_miningManager.isMining) {
_logger.info('当前有挖矿任务,等待任务结束后恢复持续挖矿');
return;
}
_logger.info('恢复持续挖矿...');
_isPaused = false;
await _startMining();
// 确保进程监控已启动
if (_processExitSubscription == null) {
_startProcessMonitor();
}
}
/// 启动挖矿
Future<void> _startMining() async {
if (_config == null || _isPaused || _miningConfig == null) {
return;
}
if (_miningManager.isMining) {
return;
}
final task = MiningTaskInfo(
coin: _config!.coin,
algo: _config!.algo,
pool: '',
poolUrl: _config!.poolUrl,
walletAddress: _config!.wallet,
workerId: _config!.workerId,
poolUser: _config!.poolUser,
walletMining: _config!.walletMining,
endTimestamp: DateTime.now().add(const Duration(days: 365)).millisecondsSinceEpoch ~/ 1000, // 持续挖矿设置很长的结束时间
miner: _config!.miner,
);
await _miningManager.startMining(task, _miningConfig!);
}
/// 启动进程监控
void _startProcessMonitor() {
_processExitSubscription?.cancel();
// 监听挖矿进程退出事件
_processExitSubscription = _miningManager.processExitStream.listen((_) {
// 检查是否是持续挖矿进程退出
if (_isRunning && !_isPaused && !_miningManager.isMining && _miningManager.currentTask == null) {
_logger.warning('持续挖矿进程意外退出将在5秒后自动重启...');
// 延迟5秒后重启避免频繁重启
Future.delayed(const Duration(seconds: 5), () {
if (_isRunning && !_isPaused && !_miningManager.isMining) {
_logger.info('自动重启持续挖矿...');
_startMining();
}
});
}
});
}
String _trimQuotes(String value) {
var v = value.trim();
if (v.length >= 2) {
final first = v[0];
final last = v[v.length - 1];
if ((first == '"' && last == '"') || (first == "'" && last == "'")) {
v = v.substring(1, v.length - 1);
}
}
return v;
}
String? _getMinerPath(String miner) {
if (_miningConfig == null) return null;
switch (miner.toLowerCase()) {
case 'lolminer':
return _miningConfig!.lolMinerPath;
case 'rigel':
return _miningConfig!.rigelPath;
case 'bzminer':
return _miningConfig!.bzMinerPath;
default:
return null;
}
}
bool get isRunning => _isRunning;
bool get isPaused => _isPaused;
}
class SustainMiningConfig {
final bool enabled;
final String algo;
final String coin;
final String miner;
final String poolUrl;
final String wallet;
final String workerId;
final String poolUser;
final bool walletMining;
SustainMiningConfig({
required this.enabled,
required this.algo,
required this.coin,
required this.miner,
required this.poolUrl,
required this.wallet,
required this.workerId,
required this.poolUser,
required this.walletMining,
});
}