Log xmrig startup failures in peyawallet
build / Build Linux (lite) (push) Successful in 2m54s
build / Build Linux (mining) (push) Successful in 2m22s
build / Build Windows (mining) (push) Has been cancelled
build / Build Windows (lite) (push) Has been cancelled

This commit is contained in:
Codex Bot
2026-04-20 23:46:09 +02:00
parent 067f1bc2f8
commit eef05a265d
2 changed files with 74 additions and 5 deletions
+58 -2
View File
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'package:logger/logger.dart';
import 'package:path/path.dart' as p;
@@ -142,6 +143,7 @@ class BundledMiningService implements MiningService {
final logFile = await AppPaths.minerLogFile();
final launcherLogFile = await AppPaths.minerLauncherLogFile();
await launcherLogFile.parent.create(recursive: true);
await _prepareBinary(binary);
final args = <String>[
'--coin',
@@ -180,6 +182,10 @@ class BundledMiningService implements MiningService {
}
try {
await _appendLauncherLog(
launcherLogFile,
'launch request: binary="$binary" cwd="${p.dirname(binary)}" args=${args.join(' ')}',
);
final process = await Process.start(
binary,
args,
@@ -191,11 +197,26 @@ class BundledMiningService implements MiningService {
final earlyExit = await _waitForEarlyExit(process);
if (earlyExit != null) {
_logger.w('xmrig exited immediately with code $earlyExit');
await _appendLauncherLog(
launcherLogFile,
'xmrig exited immediately with code $earlyExit',
);
return false;
}
return _waitForApi(config);
final ready = await _waitForApi(config);
if (!ready) {
await _appendLauncherLog(
launcherLogFile,
'xmrig process did not expose HTTP API on 127.0.0.1:${config.apiPort} within timeout',
);
}
return ready;
} catch (error) {
_logger.w('Failed to start xmrig: $error');
await _appendLauncherLog(
launcherLogFile,
'Failed to start xmrig: $error',
);
return false;
}
}
@@ -224,6 +245,15 @@ class BundledMiningService implements MiningService {
);
}
Future<void> _appendLauncherLog(File file, String line) async {
try {
await file.writeAsString(
'[${DateTime.now().toIso8601String()}] $line\n',
mode: FileMode.writeOnlyAppend,
);
} catch (_) {}
}
Future<int?> _waitForEarlyExit(Process process) async {
const grace = Duration(seconds: 2);
final result = await Future.any<Object?>([
@@ -243,6 +273,28 @@ class BundledMiningService implements MiningService {
return false;
}
Future<void> _prepareBinary(String binary) async {
if (!Platform.isLinux) {
return;
}
try {
final file = File(binary);
final stat = await file.stat();
final mode = stat.mode;
final execBits = 0x49; // user/group/other execute
if ((mode & execBits) == execBits) {
return;
}
await Process.run(
'chmod',
['755', binary],
runInShell: true,
);
} catch (error) {
_logger.w('Failed to ensure xmrig executable bit: $error');
}
}
Future<bool> _waitForExit(int pid, MinerLaunchConfig? config) async {
for (var i = 0; i < 20; i++) {
final alive = _isProcessAlive(pid);
@@ -319,6 +371,10 @@ class BundledMiningService implements MiningService {
if (index < 0 || index >= values.length) {
return null;
}
return (values[index] as num?)?.toDouble();
final value = (values[index] as num?)?.toDouble();
if (value == null) {
return null;
}
return math.max(0, value);
}
}
+16 -3
View File
@@ -419,13 +419,18 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
Future<void> _startMining() async {
final l10n = context.l10n;
final started = await ref.read(miningControllerProvider.notifier).start();
final miningState = ref.read(miningControllerProvider);
if (!mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
started ? l10n.miningMinerStartSuccess : l10n.miningMinerStartFailure,
started
? l10n.miningMinerStartSuccess
: (miningState.error?.isNotEmpty == true
? '${l10n.miningMinerStartFailure}: ${miningState.error}'
: l10n.miningMinerStartFailure),
),
),
);
@@ -434,13 +439,18 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
Future<void> _stopMining() async {
final l10n = context.l10n;
final stopped = await ref.read(miningControllerProvider.notifier).stop();
final miningState = ref.read(miningControllerProvider);
if (!mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
stopped ? l10n.miningMinerStopSuccess : l10n.miningMinerStopFailure,
stopped
? l10n.miningMinerStopSuccess
: (miningState.error?.isNotEmpty == true
? '${l10n.miningMinerStopFailure}: ${miningState.error}'
: l10n.miningMinerStopFailure),
),
),
);
@@ -449,6 +459,7 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
Future<void> _restartMining() async {
final l10n = context.l10n;
final restarted = await ref.read(miningControllerProvider.notifier).restart();
final miningState = ref.read(miningControllerProvider);
if (!mounted) {
return;
}
@@ -457,7 +468,9 @@ class _MiningScreenState extends ConsumerState<MiningScreen> {
content: Text(
restarted
? l10n.miningMinerRestartSuccess
: l10n.miningMinerRestartFailure,
: (miningState.error?.isNotEmpty == true
? '${l10n.miningMinerRestartFailure}: ${miningState.error}'
: l10n.miningMinerRestartFailure),
),
),
);