云算力平台windows桌面应用
This commit is contained in:
214
lib/core/mining_manager.dart
Normal file
214
lib/core/mining_manager.dart
Normal file
@@ -0,0 +1,214 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'mining_task_info.dart';
|
||||
|
||||
/// 挖矿管理器 - 管理挖矿软件的启动、停止
|
||||
class MiningManager {
|
||||
static final MiningManager _instance = MiningManager._internal();
|
||||
factory MiningManager() => _instance;
|
||||
MiningManager._internal();
|
||||
|
||||
final Logger _logger = Logger('MiningManager');
|
||||
Process? _currentProcess;
|
||||
MiningTaskInfo? _currentTask;
|
||||
Timer? _taskMonitor;
|
||||
final StreamController<String> _minerLogController = StreamController<String>.broadcast();
|
||||
|
||||
/// 启动挖矿
|
||||
Future<bool> startMining(MiningTaskInfo task, MiningConfig config) async {
|
||||
if (_currentProcess != null) {
|
||||
_logger.warning('已有挖矿任务在运行');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final minerPath = _getMinerPath(task.miner, config);
|
||||
if (minerPath == null) {
|
||||
_logger.severe('挖矿软件路径未配置: ${task.miner}');
|
||||
return false;
|
||||
}
|
||||
|
||||
final args = _buildMinerArgs(task, config);
|
||||
String executable;
|
||||
|
||||
switch (task.miner.toLowerCase()) {
|
||||
case 'lolminer':
|
||||
executable = Platform.isWindows
|
||||
? '${minerPath}\\lolMiner.exe'
|
||||
: '$minerPath/lolMiner';
|
||||
break;
|
||||
case 'rigel':
|
||||
executable = Platform.isWindows
|
||||
? '${minerPath}\\rigel.exe'
|
||||
: '$minerPath/rigel';
|
||||
break;
|
||||
case 'bzminer':
|
||||
executable = Platform.isWindows
|
||||
? '${minerPath}\\bzminer.exe'
|
||||
: '$minerPath/bzminer';
|
||||
break;
|
||||
default:
|
||||
throw Exception('不支持的挖矿软件: ${task.miner}');
|
||||
}
|
||||
|
||||
// 确保可执行文件存在
|
||||
final executableFile = File(executable);
|
||||
if (!await executableFile.exists()) {
|
||||
throw Exception('挖矿软件不存在: $executable');
|
||||
}
|
||||
|
||||
_logger.info('启动挖矿: $executable ${args.join(' ')}');
|
||||
|
||||
_currentProcess = await Process.start(
|
||||
executable,
|
||||
args,
|
||||
workingDirectory: minerPath,
|
||||
mode: ProcessStartMode.normal, // 改为 normal 以捕获输出
|
||||
);
|
||||
|
||||
_currentTask = task;
|
||||
_startTaskMonitor(task);
|
||||
_startLogCapture();
|
||||
|
||||
_logger.info('挖矿已启动 (PID: ${_currentProcess!.pid})');
|
||||
return true;
|
||||
} catch (e) {
|
||||
_logger.severe('启动挖矿失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 停止挖矿
|
||||
Future<void> stopMining() async {
|
||||
_taskMonitor?.cancel();
|
||||
_taskMonitor = null;
|
||||
|
||||
if (_currentProcess != null) {
|
||||
try {
|
||||
_currentProcess!.kill();
|
||||
await _currentProcess!.exitCode;
|
||||
_logger.info('挖矿已停止');
|
||||
} catch (e) {
|
||||
_logger.severe('停止挖矿失败: $e');
|
||||
} finally {
|
||||
_currentProcess = null;
|
||||
_currentTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取挖矿软件路径
|
||||
String? _getMinerPath(String miner, MiningConfig config) {
|
||||
switch (miner.toLowerCase()) {
|
||||
case 'lolminer':
|
||||
return config.lolMinerPath;
|
||||
case 'rigel':
|
||||
return config.rigelPath;
|
||||
case 'bzminer':
|
||||
return config.bzMinerPath;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 构建挖矿软件参数
|
||||
List<String> _buildMinerArgs(MiningTaskInfo task, MiningConfig config) {
|
||||
final address = task.walletMining ? task.walletAddress : (task.poolUser ?? task.walletAddress);
|
||||
|
||||
switch (task.miner.toLowerCase()) {
|
||||
case 'lolminer':
|
||||
return [
|
||||
'--algo', task.coin,
|
||||
'--pool', task.poolUrl,
|
||||
'--user', '$address.${task.workerId}',
|
||||
];
|
||||
case 'rigel':
|
||||
return [
|
||||
'--no-watchdog',
|
||||
'-a', task.algo.toLowerCase(),
|
||||
'-o', task.poolUrl,
|
||||
'-u', address,
|
||||
'-w', task.workerId,
|
||||
'--log-file', 'logs/miner.log',
|
||||
];
|
||||
case 'bzminer':
|
||||
return [
|
||||
'-a', task.coin,
|
||||
'-w', '$address.${task.workerId}',
|
||||
'-p', task.poolUrl,
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// 启动任务监控
|
||||
void _startTaskMonitor(MiningTaskInfo task) {
|
||||
_taskMonitor?.cancel();
|
||||
|
||||
final endTime = DateTime.fromMillisecondsSinceEpoch(task.endTimestamp * 1000);
|
||||
final now = DateTime.now();
|
||||
|
||||
if (endTime.isBefore(now)) {
|
||||
// 任务已过期,立即停止
|
||||
stopMining();
|
||||
return;
|
||||
}
|
||||
|
||||
final duration = endTime.difference(now);
|
||||
_taskMonitor = Timer(duration, () {
|
||||
_logger.info('挖矿任务已到期,自动停止');
|
||||
stopMining();
|
||||
});
|
||||
}
|
||||
|
||||
/// 开始捕获挖矿进程输出
|
||||
void _startLogCapture() {
|
||||
if (_currentProcess == null) return;
|
||||
|
||||
_currentProcess!.stdout
|
||||
.transform(const SystemEncoding().decoder)
|
||||
.transform(const LineSplitter())
|
||||
.listen((line) {
|
||||
_minerLogController.add('[${DateTime.now().toString().substring(11, 19)}] $line');
|
||||
});
|
||||
|
||||
_currentProcess!.stderr
|
||||
.transform(const SystemEncoding().decoder)
|
||||
.transform(const LineSplitter())
|
||||
.listen((line) {
|
||||
_minerLogController.add('[${DateTime.now().toString().substring(11, 19)}] [ERROR] $line');
|
||||
});
|
||||
}
|
||||
|
||||
/// 获取挖矿日志流
|
||||
Stream<String> get minerLogStream => _minerLogController.stream;
|
||||
|
||||
MiningTaskInfo? get currentTask => _currentTask;
|
||||
bool get isMining => _currentProcess != null;
|
||||
|
||||
/// 清理资源
|
||||
void dispose() {
|
||||
_minerLogController.close();
|
||||
}
|
||||
}
|
||||
|
||||
class MiningConfig {
|
||||
final String? lolMinerPath;
|
||||
final String? rigelPath;
|
||||
final String? bzMinerPath;
|
||||
final bool proxyEnabled;
|
||||
final String? serverUrl;
|
||||
final String? updateUrl;
|
||||
|
||||
MiningConfig({
|
||||
this.lolMinerPath,
|
||||
this.rigelPath,
|
||||
this.bzMinerPath,
|
||||
this.proxyEnabled = false,
|
||||
this.serverUrl,
|
||||
this.updateUrl,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user