Files
windows-application/lib/core/sustain_miner.dart

261 lines
7.2 KiB
Dart
Raw Permalink Normal View History

2026-01-22 15:14:27 +08:00
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;
2026-01-23 16:11:20 +08:00
StreamSubscription<void>? _processExitSubscription;
2026-01-22 15:14:27 +08:00
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();
2026-01-23 16:11:20 +08:00
_startProcessMonitor();
2026-01-22 15:14:27 +08:00
}
/// 停止持续挖矿
Future<void> stop() async {
_isRunning = false;
_monitorTimer?.cancel();
_monitorTimer = null;
2026-01-23 16:11:20 +08:00
_processExitSubscription?.cancel();
_processExitSubscription = null;
2026-01-22 15:14:27 +08:00
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();
2026-01-23 16:11:20 +08:00
// 确保进程监控已启动
if (_processExitSubscription == null) {
_startProcessMonitor();
}
2026-01-22 15:14:27 +08:00
}
/// 启动挖矿
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!);
}
2026-01-23 16:11:20 +08:00
/// 启动进程监控
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();
}
});
}
});
}
2026-01-22 15:14:27 +08:00
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,
});
}