use super::ContainerNetworkInfo; use bollard::query_parameters::{ListContainersOptions, StatsOptions}; use bollard::Docker; use futures_util::stream::TryStreamExt; use std::error::Error; /// Get network statistics for all containers pub async fn get_all_containers_network_stats( docker: &Docker, ) -> Result, Box> { let containers = docker .list_containers(Some(ListContainersOptions { all: true, ..Default::default() })) .await?; let mut net_infos = Vec::new(); for container in containers { let id = container.id.unwrap_or_default(); // Skip if no ID if id.is_empty() { continue; } if let Some(net_info) = get_single_container_network_stats(docker, &id).await? { net_infos.push(net_info); } } Ok(net_infos) } /// Get network statistics for a specific container pub async fn get_single_container_network_stats( docker: &Docker, container_id: &str, ) -> Result, Box> { let mut stats_stream = docker.stats( container_id, Some(StatsOptions { stream: false, one_shot: true, }), ); if let Some(stats) = stats_stream.try_next().await? { if let Some(networks) = stats.networks { // Take the first network interface (usually eth0) if let Some((_name, net)) = networks.into_iter().next() { return Ok(Some(ContainerNetworkInfo { container_id: container_id.to_string(), rx_bytes: net.rx_bytes.unwrap(), tx_bytes: net.tx_bytes.unwrap(), rx_packets: net.rx_packets.unwrap(), tx_packets: net.tx_packets.unwrap(), rx_errors: net.rx_errors.unwrap(), tx_errors: net.tx_errors.unwrap(), })); } } } Ok(None) } /// Get total network statistics across all containers pub async fn get_total_network_stats( docker: &Docker, ) -> Result<(u64, u64), Box> { let net_infos = get_all_containers_network_stats(docker).await?; let total_rx: u64 = net_infos.iter().map(|net| net.rx_bytes).sum(); let total_tx: u64 = net_infos.iter().map(|net| net.tx_bytes).sum(); Ok((total_rx, total_tx)) }