Skip to main content

macstate_core/
network.rs

1use serde::Serialize;
2
3#[derive(Debug, Clone, Serialize)]
4#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
5pub struct Network {
6    /// True when the path is on a Low Data Mode network
7    /// (`NWPath.isConstrained`).
8    pub constrained: bool,
9    /// True when the path is on an expensive interface such as cellular or
10    /// a personal hotspot (`NWPath.isExpensive`).
11    pub expensive: bool,
12    pub interface: Interface,
13}
14
15#[derive(Debug, Clone, Copy, Serialize)]
16#[serde(rename_all = "lowercase")]
17#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
18#[cfg_attr(feature = "schema", schemars(rename_all = "lowercase"))]
19#[cfg_attr(
20    feature = "schema",
21    schemars(description = "Primary interface kind reported by NWPathMonitor for the current path. `other` is reported when the path uses none of the well-known kinds (e.g. unknown VPN).")
22)]
23pub enum Interface {
24    Wifi,
25    Cellular,
26    Wired,
27    Loopback,
28    Other,
29}
30
31#[cfg(target_os = "macos")]
32impl Network {
33    pub fn collect() -> Self {
34        use macstate_sys::nwpath::{snapshot, InterfaceType};
35        use std::time::Duration;
36
37        // NWPathMonitor delivers its first update very quickly (<100ms typical),
38        // but allow generous slack on cold starts.
39        let Some(snap) = snapshot(Duration::from_secs(2)) else {
40            return Self {
41                constrained: false,
42                expensive: false,
43                interface: Interface::Other,
44            };
45        };
46
47        let interface = match snap.interface {
48            Some(InterfaceType::Wifi) => Interface::Wifi,
49            Some(InterfaceType::Cellular) => Interface::Cellular,
50            Some(InterfaceType::WiredEthernet) => Interface::Wired,
51            Some(InterfaceType::Loopback) => Interface::Loopback,
52            _ => Interface::Other,
53        };
54
55        Self {
56            constrained: snap.constrained,
57            expensive: snap.expensive,
58            interface,
59        }
60    }
61}
62
63#[cfg(not(target_os = "macos"))]
64impl Network {
65    pub fn collect() -> Self {
66        Self {
67            constrained: false,
68            expensive: false,
69            interface: Interface::Other,
70        }
71    }
72}