wayle-network 0.1.2

WiFi and wired network management
Documentation
use std::sync::{Arc, Weak};

use tokio_stream::StreamExt;
use tokio_util::sync::CancellationToken;
use tracing::debug;
use wayle_traits::ModelMonitoring;

use super::Wired;
use crate::{
    core::config::ip4_config::Ip4Config,
    error::Error,
    proxy::devices::DeviceProxy,
    types::states::{NMDeviceState, NetworkStatus},
};

impl ModelMonitoring for Wired {
    type Error = Error;

    async fn start_monitoring(self: Arc<Self>) -> Result<(), Self::Error> {
        let device_arc = Arc::new(self.device.clone());
        device_arc.start_monitoring().await?;

        let Some(ref cancellation_token) = self.device.core.cancellation_token else {
            return Err(Error::MissingCancellationToken);
        };

        let cancel_token = cancellation_token.clone();
        let weak_self = Arc::downgrade(&self);
        let device_proxy = DeviceProxy::new(
            &self.device.core.connection,
            self.device.core.object_path.clone(),
        )
        .await
        .map_err(Error::DbusError)?;

        tokio::spawn(async move {
            let _ = monitor_wired_connectivity(weak_self, device_proxy, cancel_token).await;
        });

        Ok(())
    }
}

async fn monitor_wired_connectivity(
    weak_wired: Weak<Wired>,
    proxy: DeviceProxy<'static>,
    cancellation_token: CancellationToken,
) -> Result<(), Error> {
    let mut connectivity_changed = proxy.receive_state_changed().await;
    let mut ip4_config_changed = proxy.receive_ip4_config_changed().await;

    loop {
        let Some(wired) = weak_wired.upgrade() else {
            return Ok(());
        };

        tokio::select! {
            _ = cancellation_token.cancelled() => {
                debug!("Wired monitoring cancelled for {}", wired.device.core.object_path);
                return Ok(());
            }
            Some(change) = connectivity_changed.next() => {
                if let Ok(new_connectivity) = change.get().await {
                    let device_state = NMDeviceState::from_u32(new_connectivity);
                    let status = NetworkStatus::from_device_state(device_state);
                    wired.connectivity.set(status);

                    if status == NetworkStatus::Connected {
                        let ip = Ip4Config::resolve_address(
                            &wired.device.core.connection,
                            wired.device.core.ip4_config.get(),
                        ).await;
                        wired.ip4_address.set(ip);
                    }
                }
            }
            Some(change) = ip4_config_changed.next() => {
                if let Ok(ip4_path) = change.get().await {
                    let ip = Ip4Config::resolve_address(
                        &wired.device.core.connection,
                        ip4_path,
                    ).await;
                    wired.ip4_address.set(ip);
                }
            }
            else => {
                break;
            }
        }
    }

    Ok(())
}