cranpose_services/
network_status.rs1use std::sync::{Arc, OnceLock};
9
10use crate::registry::{RecoveryGate, ServiceRegistry};
11
12#[derive(Clone, Copy, PartialEq, Eq, Debug)]
14pub struct NetworkStatus {
15 pub online: bool,
17 pub metered: bool,
19}
20
21impl Default for NetworkStatus {
22 fn default() -> Self {
23 Self {
24 online: true,
25 metered: false,
26 }
27 }
28}
29
30pub trait NetworkMonitor: Send + Sync {
32 fn status(&self) -> NetworkStatus;
33 fn is_alive(&self) -> bool;
34 fn reconnect(&self);
35}
36
37pub type NetworkMonitorRef = Arc<dyn NetworkMonitor>;
38
39struct DefaultNetworkMonitor;
40
41impl NetworkMonitor for DefaultNetworkMonitor {
42 fn status(&self) -> NetworkStatus {
43 NetworkStatus::default()
44 }
45
46 fn is_alive(&self) -> bool {
47 true
48 }
49
50 fn reconnect(&self) {}
51}
52
53static PLATFORM_NETWORK_MONITOR: ServiceRegistry<dyn NetworkMonitor> = ServiceRegistry::new();
54static DEFAULT_NETWORK_MONITOR: OnceLock<NetworkMonitorRef> = OnceLock::new();
55static NETWORK_MONITOR_HANDLE: OnceLock<NetworkMonitorRef> = OnceLock::new();
56static NETWORK_RECOVERY: RecoveryGate = RecoveryGate::new();
57
58struct PlatformNetworkMonitor;
59
60fn registered_network_monitor() -> NetworkMonitorRef {
61 PLATFORM_NETWORK_MONITOR
62 .get_or_warn("network monitor")
63 .unwrap_or_else(|| {
64 DEFAULT_NETWORK_MONITOR
65 .get_or_init(|| Arc::new(DefaultNetworkMonitor))
66 .clone()
67 })
68}
69
70fn active_network_monitor() -> NetworkMonitorRef {
71 let monitor = registered_network_monitor();
72 if monitor.is_alive() {
73 NETWORK_RECOVERY.succeeded();
74 } else if NETWORK_RECOVERY.try_start() {
75 monitor.reconnect();
76 }
77 monitor
78}
79
80impl NetworkMonitor for PlatformNetworkMonitor {
81 fn status(&self) -> NetworkStatus {
82 active_network_monitor().status()
83 }
84
85 fn is_alive(&self) -> bool {
86 registered_network_monitor().is_alive()
87 }
88
89 fn reconnect(&self) {
90 registered_network_monitor().reconnect();
91 }
92}
93
94pub fn set_platform_network_monitor(monitor: NetworkMonitorRef) {
96 PLATFORM_NETWORK_MONITOR.set(monitor);
97 NETWORK_RECOVERY.succeeded();
98}
99
100pub fn clear_platform_network_monitor() {
102 PLATFORM_NETWORK_MONITOR.clear();
103}
104
105pub fn network_monitor() -> NetworkMonitorRef {
108 NETWORK_MONITOR_HANDLE
109 .get_or_init(|| Arc::new(PlatformNetworkMonitor))
110 .clone()
111}
112
113pub fn network_status() -> NetworkStatus {
115 let monitor = network_monitor();
116 if monitor.is_alive() {
117 NETWORK_RECOVERY.succeeded();
118 } else if NETWORK_RECOVERY.try_start() {
119 monitor.reconnect();
120 }
121 monitor.status()
122}
123
124#[cfg(test)]
125#[path = "tests/network_status_tests.rs"]
126mod tests;