fix: network error resilience and wifi state tracking

- Demote transient route-replace errors (vanishing interfaces) to trace
- Tolerate errors during policy routing cleanup on drop
- Use join_all instead of try_join_all for gateway watcher jobs
- Simplify wifi interface detection to always use find_wifi_iface()
- Write wifi enabled state to db instead of interface name
This commit is contained in:
Aiden McClelland
2026-03-24 19:16:52 -06:00
parent e0f27281d1
commit aaa43ce6af
2 changed files with 25 additions and 28 deletions

View File

@@ -765,7 +765,9 @@ async fn watcher(
} }
changed changed
}); });
futures::future::try_join_all(jobs).await?; for result in futures::future::join_all(jobs).await {
result.log_err();
}
Ok::<_, Error>(()) Ok::<_, Error>(())
}) })
@@ -824,7 +826,7 @@ impl Drop for PolicyRoutingCleanup {
.arg("50") .arg("50")
.invoke(ErrorKind::Network) .invoke(ErrorKind::Network)
.await .await
.log_err(); .ok();
Command::new("ip") Command::new("ip")
.arg("route") .arg("route")
.arg("flush") .arg("flush")
@@ -832,7 +834,7 @@ impl Drop for PolicyRoutingCleanup {
.arg(&table_str) .arg(&table_str)
.invoke(ErrorKind::Network) .invoke(ErrorKind::Network)
.await .await
.log_err(); .ok();
Command::new("iptables") Command::new("iptables")
.arg("-t") .arg("-t")
.arg("mangle") .arg("mangle")
@@ -850,7 +852,7 @@ impl Drop for PolicyRoutingCleanup {
.arg(&table_str) .arg(&table_str)
.invoke(ErrorKind::Network) .invoke(ErrorKind::Network)
.await .await
.log_err(); .ok();
}); });
} }
} }
@@ -1067,7 +1069,17 @@ async fn apply_policy_routing(
cmd.arg(part); cmd.arg(part);
} }
cmd.arg("table").arg(&table_str); cmd.arg("table").arg(&table_str);
cmd.invoke(ErrorKind::Network).await.log_err(); if let Err(e) = cmd.invoke(ErrorKind::Network).await {
// Transient interfaces (podman, wg-quick, etc.) may
// vanish between reading the main table and replaying
// the route — demote to debug to avoid log noise.
if e.source.to_string().contains("No such file or directory") {
tracing::trace!("ip route replace (transient device): {e}");
} else {
tracing::error!("{e}");
tracing::debug!("{e:?}");
}
}
} }
} }
@@ -1470,22 +1482,12 @@ impl NetworkInterfaceController {
) -> Result<(), Error> { ) -> Result<(), Error> {
tracing::debug!("syncronizing {info:?} to db"); tracing::debug!("syncronizing {info:?} to db");
let mut wifi_iface = info let wifi_iface = find_wifi_iface()
.iter()
.find(|(_, info)| {
info.ip_info.as_ref().map_or(false, |i| {
i.device_type == Some(NetworkInterfaceType::Wireless)
})
})
.map(|(id, _)| id.clone());
if wifi_iface.is_none() {
wifi_iface = find_wifi_iface()
.await .await
.ok() .ok()
.and_then(|a| a) .and_then(|a| a)
.map(InternedString::from) .map(InternedString::from)
.map(GatewayId::from); .map(GatewayId::from);
}
db.mutate(|db| { db.mutate(|db| {
let network = db.as_public_mut().as_server_info_mut().as_network_mut(); let network = db.as_public_mut().as_server_info_mut().as_network_mut();

View File

@@ -180,19 +180,14 @@ pub async fn set_enabled(
.invoke(ErrorKind::Wifi) .invoke(ErrorKind::Wifi)
.await?; .await?;
} }
let iface = if let Some(man) = ctx.wifi_manager.read().await.as_ref().filter(|_| enabled) {
Some(man.interface.clone())
} else {
None
};
ctx.db ctx.db
.mutate(|d| { .mutate(|d| {
d.as_public_mut() d.as_public_mut()
.as_server_info_mut() .as_server_info_mut()
.as_network_mut() .as_network_mut()
.as_wifi_mut() .as_wifi_mut()
.as_interface_mut() .as_enabled_mut()
.ser(&iface) .ser(&enabled)
}) })
.await .await
.result?; .result?;