fix: connect() no longer falls through from mux to USB serial
When a mux socket file exists, connect(None, timeout) and try_connect() now commit to the mux — returning an error if unreachable instead of silently falling through to USB serial. This prevents a race condition where a client could steal the serial port from the mux during reconnect. Callers with explicit port = Some(...) are unaffected.
This commit is contained in:
4 files changed
+29
-33
No files matched your search
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 0.2.1 — 2026-04-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`connect()` no longer falls through from mux to USB serial.** If a mux
|
||||
socket file exists, `connect(None, timeout)` and `try_connect(timeout)` now
|
||||
commit to the mux and return an error if the mux is unreachable — instead of
|
||||
silently bypassing it and grabbing the USB port directly. This prevents a
|
||||
race condition where a client could steal the serial port from the mux during
|
||||
reconnect. Callers with explicit `port = Some(...)` are unaffected.
|
||||
|
||||
## 0.2.0 — 2026-04-07
|
||||
|
||||
### Features
|
||||
|
||||
Generated
+1
-1
@@ -44,7 +44,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "donglora-client"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serialport",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "donglora-client"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
authors = ["Stephen Waits <steve@waits.net>"]
|
||||
|
||||
+16
-31
@@ -100,26 +100,19 @@ pub fn connect(port: Option<&str>, timeout: Duration) -> anyhow::Result<Client<A
|
||||
return Ok(client);
|
||||
}
|
||||
|
||||
// Try Unix socket mux
|
||||
// Try Unix socket mux — if a mux socket exists, commit to it. Never fall through
|
||||
// to USB serial when a mux is (or was) running. This prevents a client from
|
||||
// stealing the serial port while the mux is temporarily reconnecting.
|
||||
#[cfg(unix)]
|
||||
if let Some(path) = find_mux_socket() {
|
||||
match MuxTransport::unix(&path, timeout) {
|
||||
Ok(transport) => {
|
||||
debug!("connected to mux socket at {path}");
|
||||
let mut client = Client::new(AnyTransport::Mux(transport));
|
||||
if client.validate().is_ok() {
|
||||
return Ok(client);
|
||||
}
|
||||
debug!("mux at {path} did not validate, falling back to USB");
|
||||
}
|
||||
Err(_) => {
|
||||
// Stale socket or connection refused — fall through
|
||||
debug!("mux socket at {path} not reachable, falling back to USB");
|
||||
}
|
||||
}
|
||||
debug!("mux socket found at {path} — connecting via mux only");
|
||||
let transport = MuxTransport::unix(&path, timeout)?;
|
||||
let mut client = Client::new(AnyTransport::Mux(transport));
|
||||
client.validate()?;
|
||||
return Ok(client);
|
||||
}
|
||||
|
||||
// Direct USB serial — auto-detect or wait
|
||||
// Direct USB serial — only reached when no mux socket exists at all
|
||||
let port_path = discovery::find_port().unwrap_or_else(discovery::wait_for_device);
|
||||
debug!("opening serial port {port_path}");
|
||||
let transport = SerialTransport::open(&port_path, timeout)?;
|
||||
@@ -183,25 +176,17 @@ pub fn try_connect(timeout: Duration) -> anyhow::Result<Client<AnyTransport>> {
|
||||
return Ok(client);
|
||||
}
|
||||
|
||||
// Try Unix socket mux
|
||||
// Try Unix socket mux — commit to it if socket exists (same rationale as connect())
|
||||
#[cfg(unix)]
|
||||
if let Some(path) = find_mux_socket() {
|
||||
match MuxTransport::unix(&path, timeout) {
|
||||
Ok(transport) => {
|
||||
debug!("connected to mux socket at {path}");
|
||||
let mut client = Client::new(AnyTransport::Mux(transport));
|
||||
if client.validate().is_ok() {
|
||||
return Ok(client);
|
||||
}
|
||||
debug!("mux socket at {path} did not validate, falling back to USB");
|
||||
}
|
||||
Err(_) => {
|
||||
debug!("mux socket at {path} not reachable, falling back to USB");
|
||||
}
|
||||
}
|
||||
debug!("mux socket found at {path} — connecting via mux only");
|
||||
let transport = MuxTransport::unix(&path, timeout)?;
|
||||
let mut client = Client::new(AnyTransport::Mux(transport));
|
||||
client.validate()?;
|
||||
return Ok(client);
|
||||
}
|
||||
|
||||
// Direct USB serial — single non-blocking scan
|
||||
// Direct USB serial — single non-blocking scan (only when no mux socket exists)
|
||||
let port_path =
|
||||
discovery::find_port().ok_or_else(|| anyhow::anyhow!("no DongLoRa device found (no mux, no USB device)"))?;
|
||||
debug!("opening serial port {port_path}");
|
||||
|
||||
Reference in new issue
Block a user