ashpd 0.2.3

XDG portals wrapper in Rust using zbus
Documentation
//! **Note** This portal doesn't work for sandboxed applications.
//! # Examples
//!
//! ```rust,no_run
//! use ashpd::desktop::network_monitor::NetworkMonitorProxy;
//!
//! async fn run() -> ashpd::Result<()> {
//!     let connection = zbus::Connection::session().await?;
//!     let proxy = NetworkMonitorProxy::new(&connection).await?;
//!
//!     println!("{}", proxy.can_reach("www.google.com", 80).await?);
//!     println!("{}", proxy.is_available().await?);
//!     println!("{:#?}", proxy.connectivity().await?);
//!     println!("{}", proxy.is_metered().await?);
//!     println!("{:#?}", proxy.status().await?);
//!
//!     Ok(())
//! }
//! ```

use std::fmt;

use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{DeserializeDict, SerializeDict, Type};

use super::{DESTINATION, PATH};
use crate::{
    helpers::{call_method, receive_signal},
    Error,
};

#[derive(SerializeDict, DeserializeDict, Type, Debug)]
/// The network status, composed of the availability, metered & connectivity
#[zvariant(signature = "dict")]
pub struct NetworkStatus {
    /// Whether the network is considered available.
    available: bool,
    /// Whether the network is considered metered.
    metered: bool,
    /// More detailed information about the host's network connectivity
    connectivity: Connectivity,
}

impl NetworkStatus {
    pub fn is_available(&self) -> bool {
        self.available
    }

    pub fn is_metered(&self) -> bool {
        self.metered
    }

    pub fn connectivity(&self) -> Connectivity {
        self.connectivity
    }
}

#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, Copy, Type)]
#[repr(u8)]
/// Host's network activity
pub enum Connectivity {
    /// The host is not configured with a route to the internet.
    Local = 1,
    /// The host is connected to a network, but can't reach the full internet.
    Limited = 2,
    /// The host is behind a captive portal and cannot reach the full internet.
    CaptivePortal = 3,
    /// The host connected to a network, and can reach the full internet.
    FullNetwork = 4,
}

impl fmt::Display for Connectivity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let connectivity = match self {
            Self::Local => "local",
            Self::Limited => "limited",
            Self::CaptivePortal => "captive portal",
            Self::FullNetwork => "full network",
        };
        f.write_str(connectivity)
    }
}

/// The interface provides network status information to sandboxed applications.
/// It is not a portal in the strict sense, since it does not involve user
/// interaction. Applications are expected to use this interface indirectly,
/// via a library API such as the GLib [`gio::NetworkMonitor`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/gio/struct.NetworkMonitor.html) interface.
///
/// Wrapper of the DBus interface: [`org.freedesktop.portal.NetworkMonitor`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-org.freedesktop.portal.NetworkMonitor).
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.NetworkMonitor")]
pub struct NetworkMonitorProxy<'a>(zbus::Proxy<'a>);

impl<'a> NetworkMonitorProxy<'a> {
    /// Create a new instance of [`NetworkMonitorProxy`].
    pub async fn new(connection: &zbus::Connection) -> Result<NetworkMonitorProxy<'a>, Error> {
        let proxy = zbus::ProxyBuilder::new_bare(connection)
            .interface("org.freedesktop.portal.NetworkMonitor")?
            .path(PATH)?
            .destination(DESTINATION)?
            .build()
            .await?;
        Ok(Self(proxy))
    }

    /// Get a reference to the underlying Proxy.
    pub fn inner(&self) -> &zbus::Proxy<'_> {
        &self.0
    }

    /// Returns whether the given hostname is believed to be reachable.
    ///
    /// # Arguments
    ///
    /// * `hostname` - The hostname to reach.
    /// * `port` - The port to reach.
    ///
    /// # Specifications
    ///
    /// See also [`CanReach`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.CanReach).
    #[doc(alias = "CanReach")]
    pub async fn can_reach(&self, hostname: &str, port: u32) -> Result<bool, Error> {
        call_method(self.inner(), "CanReach", &(hostname, port)).await
    }

    /// Returns whether the network is considered available.
    /// That is, whether the system as a default route for at least one of IPv4
    /// or IPv6.
    ///
    /// # Specifications
    ///
    /// See also [`GetAvailable`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.GetAvailable).
    #[doc(alias = "GetAvailable")]
    #[doc(alias = "get_available")]
    pub async fn is_available(&self) -> Result<bool, Error> {
        call_method(self.inner(), "GetAvailable", &()).await
    }

    /// Returns more detailed information about the host's network connectivity
    ///
    /// # Specifications
    ///
    /// See also [`GetConnectivity`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.GetConnectivity).
    #[doc(alias = "GetConnectivity")]
    #[doc(alias = "get_connectivity")]
    pub async fn connectivity(&self) -> Result<Connectivity, Error> {
        call_method(self.inner(), "GetConnectivity", &()).await
    }

    /// Returns whether the network is considered metered.
    /// That is, whether the system as traffic flowing through the default
    /// connection that is subject to limitations by service providers.
    ///
    /// # Specifications
    ///
    /// See also [`GetMetered`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.GetMetered).
    #[doc(alias = "GetMetered")]
    #[doc(alias = "get_metered")]
    pub async fn is_metered(&self) -> Result<bool, Error> {
        call_method(self.inner(), "GetMetered", &()).await
    }

    /// Returns the three values all at once.
    ///
    /// # Specifications
    ///
    /// See also [`GetStatus`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-method-org-freedesktop-portal-NetworkMonitor.GetStatus).
    #[doc(alias = "GetStatus")]
    #[doc(alias = "get_status")]
    pub async fn status(&self) -> Result<NetworkStatus, Error> {
        call_method(self.inner(), "GetStatus", &()).await
    }

    /// Emitted when the network configuration changes.
    ///
    /// # Specifications
    ///
    /// See also [`changed`](https://flatpak.github.io/xdg-desktop-portal/index.html#gdbus-signal-org-freedesktop-portal-NetworkMonitor.changed).
    pub async fn receive_changed(&self) -> Result<(), Error> {
        receive_signal(self.inner(), "changed").await
    }
}