1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! use_online hook for network connectivity detection
//!
//! Provides a way to detect if the system has network connectivity.
//!
//! # Example
//!
//! ```rust,ignore
//! use rnk::prelude::*;
//!
//! fn app() -> Element {
//! let is_online = use_online();
//!
//! if is_online {
//! Text::new("Connected to network").into_element()
//! } else {
//! Text::new("Offline").into_element()
//! }
//! }
//! ```
use crate::hooks::use_signal::use_signal;
use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
/// Check if the system has network connectivity
///
/// Attempts to connect to common DNS servers to verify connectivity.
pub fn check_online() -> bool {
// Try to connect to common DNS servers
let targets = [
SocketAddr::from(([8, 8, 8, 8], 53)), // Google DNS
SocketAddr::from(([1, 1, 1, 1], 53)), // Cloudflare DNS
SocketAddr::from(([208, 67, 222, 222], 53)), // OpenDNS
];
for target in targets {
if let Ok(stream) = TcpStream::connect_timeout(&target, Duration::from_millis(500)) {
drop(stream);
return true;
}
}
false
}
/// Check if a specific host is reachable
pub fn check_host_reachable(host: &str, port: u16) -> bool {
if let Ok(addr) = format!("{}:{}", host, port).parse() {
if let Ok(stream) = TcpStream::connect_timeout(&addr, Duration::from_millis(1000)) {
drop(stream);
return true;
}
}
false
}
/// Hook to check if the system is online
///
/// Returns true if network connectivity is detected.
pub fn use_online() -> bool {
let online = use_signal(check_online);
online.get()
}
/// Hook to check if a specific host is reachable
pub fn use_host_reachable(host: &str, port: u16) -> bool {
let host = host.to_string();
let reachable = use_signal(move || check_host_reachable(&host, port));
reachable.get()
}
/// Network status information
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NetworkStatus {
/// Whether the system is online
pub online: bool,
/// Latency to DNS server in milliseconds (if online)
pub latency_ms: Option<u32>,
}
impl NetworkStatus {
/// Check network status with latency measurement
pub fn check() -> Self {
let start = std::time::Instant::now();
let online = check_online();
let latency_ms = if online {
Some(start.elapsed().as_millis() as u32)
} else {
None
};
Self { online, latency_ms }
}
}
/// Hook to get detailed network status
pub fn use_network_status() -> NetworkStatus {
let status = use_signal(NetworkStatus::check);
status.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_network_status_default() {
let status = NetworkStatus::default();
assert!(!status.online);
assert!(status.latency_ms.is_none());
}
#[test]
fn test_check_online_returns_bool() {
// Just verify it returns without panicking
let _ = check_online();
}
#[test]
fn test_check_host_reachable_invalid() {
// Invalid host should return false
assert!(!check_host_reachable(
"invalid.host.that.does.not.exist",
80
));
}
#[test]
fn test_network_status_check() {
let status = NetworkStatus::check();
// If online, latency should be Some
if status.online {
assert!(status.latency_ms.is_some());
} else {
assert!(status.latency_ms.is_none());
}
}
#[test]
fn test_use_online_compiles() {
fn _test() {
let _ = use_online();
}
}
#[test]
fn test_use_host_reachable_compiles() {
fn _test() {
let _ = use_host_reachable("example.com", 80);
}
}
#[test]
fn test_use_network_status_compiles() {
fn _test() {
let _ = use_network_status();
}
}
}