Log xmrig startup failures in peyawallet
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user