donglora_client/
connect.rs1use std::time::Duration;
8
9use tracing::debug;
10
11use crate::client::Client;
12use crate::discovery;
13use crate::transport::{AnyTransport, MuxTransport, SerialTransport};
14
15const DEFAULT_TIMEOUT: Duration = Duration::from_secs(2);
17
18pub fn default_socket_path() -> String {
24 if let Ok(env) = std::env::var("DONGLORA_MUX") {
25 return env;
26 }
27 if let Ok(xdg) = std::env::var("XDG_RUNTIME_DIR") {
28 return format!("{xdg}/donglora/mux.sock");
29 }
30 "/tmp/donglora-mux.sock".to_string()
31}
32
33fn find_mux_socket() -> Option<String> {
35 if let Ok(env) = std::env::var("DONGLORA_MUX") {
36 if std::path::Path::new(&env).exists() {
37 return Some(env);
38 }
39 return None;
40 }
41 if let Ok(xdg) = std::env::var("XDG_RUNTIME_DIR") {
42 let p = format!("{xdg}/donglora/mux.sock");
43 if std::path::Path::new(&p).exists() {
44 return Some(p);
45 }
46 }
47 let p = "/tmp/donglora-mux.sock";
48 if std::path::Path::new(p).exists() {
49 return Some(p.to_string());
50 }
51 None
52}
53
54#[cfg(unix)]
56pub fn mux_connect(path: Option<&str>, timeout: Duration) -> anyhow::Result<Client<MuxTransport>> {
57 let path = match path {
58 Some(p) => p.to_string(),
59 None => find_mux_socket().ok_or_else(|| anyhow::anyhow!("no mux socket found"))?,
60 };
61 let transport = MuxTransport::unix(&path, timeout)?;
62 let mut client = Client::new(transport);
63 client.validate()?;
64 Ok(client)
65}
66
67pub fn mux_tcp_connect(host: &str, port: u16, timeout: Duration) -> anyhow::Result<Client<MuxTransport>> {
69 let transport = MuxTransport::tcp(host, port, timeout)?;
70 let mut client = Client::new(transport);
71 client.validate()?;
72 Ok(client)
73}
74
75pub fn connect(port: Option<&str>, timeout: Duration) -> anyhow::Result<Client<AnyTransport>> {
84 if let Some(port) = port {
86 debug!("opening serial port {port}");
87 let transport = SerialTransport::open(port, timeout)?;
88 let mut client = Client::new(AnyTransport::Serial(transport));
89 client.validate()?;
90 return Ok(client);
91 }
92
93 if let Ok(tcp) = std::env::var("DONGLORA_MUX_TCP")
95 && let Some(transport) = try_tcp_mux(&tcp, timeout)
96 {
97 debug!("connected to TCP mux at {tcp}");
98 let mut client = Client::new(AnyTransport::Mux(transport));
99 client.validate()?;
100 return Ok(client);
101 }
102
103 #[cfg(unix)]
107 if let Some(path) = find_mux_socket() {
108 debug!("mux socket found at {path} — connecting via mux only");
109 let transport = MuxTransport::unix(&path, timeout)?;
110 let mut client = Client::new(AnyTransport::Mux(transport));
111 client.validate()?;
112 return Ok(client);
113 }
114
115 let port_path = discovery::find_port().unwrap_or_else(discovery::wait_for_device);
117 debug!("opening serial port {port_path}");
118 let transport = SerialTransport::open(&port_path, timeout)?;
119 let mut client = Client::new(AnyTransport::Serial(transport));
120 client.validate()?;
121 Ok(client)
122}
123
124pub fn connect_default() -> anyhow::Result<Client<AnyTransport>> {
126 connect(None, DEFAULT_TIMEOUT)
127}
128
129pub fn connect_mux_auto(timeout: Duration) -> anyhow::Result<Client<AnyTransport>> {
137 if let Ok(tcp) = std::env::var("DONGLORA_MUX_TCP")
139 && let Some(transport) = try_tcp_mux(&tcp, timeout)
140 {
141 debug!("connected to TCP mux at {tcp}");
142 let mut client = Client::new(AnyTransport::Mux(transport));
143 client.validate()?;
144 return Ok(client);
145 }
146
147 #[cfg(unix)]
149 {
150 let path = find_mux_socket().ok_or_else(|| anyhow::anyhow!("no mux socket found"))?;
151 let transport = MuxTransport::unix(&path, timeout)?;
152 debug!("connected to mux socket at {path}");
153 let mut client = Client::new(AnyTransport::Mux(transport));
154 client.validate()?;
155 Ok(client)
156 }
157
158 #[cfg(not(unix))]
159 anyhow::bail!("mux-only mode requires Unix socket support or DONGLORA_MUX_TCP")
160}
161
162pub fn try_connect(timeout: Duration) -> anyhow::Result<Client<AnyTransport>> {
169 if let Ok(tcp) = std::env::var("DONGLORA_MUX_TCP")
171 && let Some(transport) = try_tcp_mux(&tcp, timeout)
172 {
173 debug!("connected to TCP mux at {tcp}");
174 let mut client = Client::new(AnyTransport::Mux(transport));
175 client.validate()?;
176 return Ok(client);
177 }
178
179 #[cfg(unix)]
181 if let Some(path) = find_mux_socket() {
182 debug!("mux socket found at {path} — connecting via mux only");
183 let transport = MuxTransport::unix(&path, timeout)?;
184 let mut client = Client::new(AnyTransport::Mux(transport));
185 client.validate()?;
186 return Ok(client);
187 }
188
189 let port_path =
191 discovery::find_port().ok_or_else(|| anyhow::anyhow!("no DongLoRa device found (no mux, no USB device)"))?;
192 debug!("opening serial port {port_path}");
193 let transport = SerialTransport::open(&port_path, timeout)?;
194 let mut client = Client::new(AnyTransport::Serial(transport));
195 client.validate()?;
196 Ok(client)
197}
198
199fn try_tcp_mux(addr: &str, timeout: Duration) -> Option<MuxTransport> {
200 let (host, port) = if let Some((h, p)) = addr.rsplit_once(':') {
201 let host = if h.is_empty() { "localhost" } else { h };
202 let port: u16 = p.parse().ok()?;
203 (host.to_string(), port)
204 } else {
205 let port: u16 = addr.parse().ok()?;
206 ("localhost".to_string(), port)
207 };
208 MuxTransport::tcp(&host, port, timeout).ok()
209}