import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:iperf3gui/domain/models/iperf3_result.dart'; import 'package:iperf3gui/domain/models/test_configuration.dart'; /// Service that runs iperf3 via [Process.start] and captures output. class Iperf3Service { final String _binaryPath; // ignore: prefer_initializing_formals Iperf3Service({required String binaryPath}) : _binaryPath = binaryPath; /// Run iperf3 with the given configuration. /// /// Returns an [Iperf3Result] with stdout/stderr and exit code. Future run(TestConfiguration config) async { final args = config.toCliArgs(); debugPrint( 'Iperf3Service: running $_binaryPath ${args.join(" ")}', ); final process = await Process.start( _binaryPath, args, runInShell: false, // must execve directly — Android sh can't exec ELF binaries ); final stdoutBuffer = []; final stderrBuffer = []; final stdoutStream = process.stdout.transform(utf8.decoder).listen( (data) { stdoutBuffer.addAll(utf8.encode(data)); debugPrint('Iperf3Service stdout: $data'); }, ); final stderrStream = process.stderr.transform(utf8.decoder).listen( (data) { stderrBuffer.addAll(utf8.encode(data)); debugPrint('Iperf3Service stderr: $data'); }, ); final exitCode = await process.exitCode; await stdoutStream.cancel(); await stderrStream.cancel(); final rawOutput = utf8.decode(stdoutBuffer) + utf8.decode(stderrBuffer); debugPrint( 'Iperf3Service: finished with exit code $exitCode, output length ${rawOutput.length}', ); return Iperf3Result( rawOutput: rawOutput, exitCode: exitCode, ); } }