diff --git a/lib/data/model/container/ps.dart b/lib/data/model/container/ps.dart index e29858db..2bc4be90 100644 --- a/lib/data/model/container/ps.dart +++ b/lib/data/model/container/ps.dart @@ -20,7 +20,7 @@ sealed class ContainerPs { factory ContainerPs.fromRaw(String s, ContainerType typ) => typ.ps(s); - void parseStats(String s); + void parseStats(String s, [String? version]); } final class PodmanPs implements ContainerPs { @@ -55,7 +55,7 @@ final class PodmanPs implements ContainerPs { ContainerStatus get status => ContainerStatus.fromPodmanExited(exited); @override - void parseStats(String s) { + void parseStats(String s, [String? version]) { final stats = json.decode(s); final cpuD = (stats['CPU'] as double? ?? 0).toStringAsFixed(1); final cpuAvgD = (stats['AvgCPU'] as double? ?? 0).toStringAsFixed(1); @@ -63,12 +63,32 @@ final class PodmanPs implements ContainerPs { final memLimit = (stats['MemLimit'] as int? ?? 0).bytes2Str; final memUsage = (stats['MemUsage'] as int? ?? 0).bytes2Str; mem = '$memUsage / $memLimit'; - final netIn = (stats['NetInput'] as int? ?? 0).bytes2Str; - final netOut = (stats['NetOutput'] as int? ?? 0).bytes2Str; - net = '↓ $netIn / ↑ $netOut'; + + int netIn = 0; + int netOut = 0; + final majorVersion = version?.split('.').firstOrNull; + final majorVersionNum = majorVersion != null ? int.tryParse(majorVersion) : null; + + // Podman 4.x and earlier use top-level NetInput/NetOutput fields. + // Podman 5.x changed network backend (Netavark) and uses nested + // Network.{iface}.RxBytes/TxBytes structure instead. + if (majorVersionNum == null || majorVersionNum <= 4) { + netIn = stats['NetInput'] as int? ?? 0; + netOut = stats['NetOutput'] as int? ?? 0; + } else if (majorVersionNum >= 5) { + final network = stats['Network'] as Map?; + if (network != null) { + for (final interface in network.values) { + netIn += interface['RxBytes'] as int? ?? 0; + netOut += interface['TxBytes'] as int? ?? 0; + } + } + } + net = '↓ ${netIn.bytes2Str} / ↑ ${netOut.bytes2Str}'; + final diskIn = (stats['BlockInput'] as int? ?? 0).bytes2Str; final diskOut = (stats['BlockOutput'] as int? ?? 0).bytes2Str; - disk = '${l10n.read} $diskOut / ${l10n.write} $diskIn'; + disk = '${l10n.read} $diskIn / ${l10n.write} $diskOut'; } factory PodmanPs.fromRawJson(String str) => PodmanPs.fromJson(json.decode(str)); @@ -125,12 +145,18 @@ final class DockerPs implements ContainerPs { ContainerStatus get status => ContainerStatus.fromDockerState(state); @override - void parseStats(String s) { + void parseStats(String s, [String? version]) { final stats = json.decode(s); cpu = stats['CPUPerc']; mem = stats['MemUsage']; - net = stats['NetIO']; - disk = stats['BlockIO']; + + final netIO = stats['NetIO'] as String? ?? '0B / 0B'; + final netParts = netIO.split(' / '); + net = '↓ ${netParts.firstOrNull ?? '0B'} / ↑ ${netParts.length > 1 ? netParts[1] : '0B'}'; + + final blockIO = stats['BlockIO'] as String? ?? '0B / 0B'; + final blockParts = blockIO.split(' / '); + disk = '${l10n.read} ${blockParts.firstOrNull ?? '0B'} / ${l10n.write} ${blockParts.length > 1 ? blockParts[1] : '0B'}'; } /// CONTAINER ID NAMES IMAGE STATUS diff --git a/lib/data/provider/container.dart b/lib/data/provider/container.dart index 3c6a4507..5ccc83e7 100644 --- a/lib/data/provider/container.dart +++ b/lib/data/provider/container.dart @@ -186,7 +186,7 @@ class ContainerNotifier extends _$ContainerNotifier { (element) => element.contains(id.substring(0, 5)), ); if (statsLine == null) continue; - item.parseStats(statsLine); + item.parseStats(statsLine, state.version); } } catch (e, trace) { state = state.copyWith(