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
});
futures::future::try_join_all(jobs).await?;
for result in futures::future::join_all(jobs).await {
result.log_err();
}
Ok::<_, Error>(())
})
@@ -824,7 +826,7 @@ impl Drop for PolicyRoutingCleanup {
.arg("50")
.invoke(ErrorKind::Network)
.await
.log_err();
.ok();
Command::new("ip")
.arg("route")
.arg("flush")
@@ -832,7 +834,7 @@ impl Drop for PolicyRoutingCleanup {
.arg(&table_str)
.invoke(ErrorKind::Network)
.await
.log_err();
.ok();
Command::new("iptables")
.arg("-t")
.arg("mangle")
@@ -850,7 +852,7 @@ impl Drop for PolicyRoutingCleanup {
.arg(&table_str)
.invoke(ErrorKind::Network)
.await
.log_err();
.ok();
});
}
}
@@ -1067,7 +1069,17 @@ async fn apply_policy_routing(
cmd.arg(part);
}
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> {
tracing::debug!("syncronizing {info:?} to db");
let mut wifi_iface = info
.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
.ok()
.and_then(|a| a)
.map(InternedString::from)
.map(GatewayId::from);
}
let wifi_iface = find_wifi_iface()
.await
.ok()
.and_then(|a| a)
.map(InternedString::from)
.map(GatewayId::from);
db.mutate(|db| {
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)
.await?;
}
let iface = if let Some(man) = ctx.wifi_manager.read().await.as_ref().filter(|_| enabled) {
Some(man.interface.clone())
} else {
None
};
ctx.db
.mutate(|d| {
d.as_public_mut()
.as_server_info_mut()
.as_network_mut()
.as_wifi_mut()
.as_interface_mut()
.ser(&iface)
.as_enabled_mut()
.ser(&enabled)
})
.await
.result?;