big day for the unemployed 2

we have uhhhh some shuffling around of the Shits
support of multiple queries (thanks copilot)
more idk
This commit is contained in:
lda
2025-08-25 00:39:25 +07:00 Unverified
parent 9346349b43
commit a3c91ae288
15 changed files with 380 additions and 42 deletions
+17
View File
@@ -0,0 +1,17 @@
use std::io;
enum cuh<T> {
DNSError(io::Error),
ToolUseError,
Other(T),
}
impl<T> From<io::Error> for cuh<T> {
fn from(value: io::Error) -> Self {
todo!()
// if matches!(value.kind(), ) {
// }
}
}
+71 -4
View File
@@ -62,12 +62,79 @@ pub async fn get_macs_1(machine_name: &str) -> io::Result<Vec<arpparse::IpNeighL
let res = futures::future::try_join_all(futures).await?; // async move block errs.
Ok(res
.into_iter()
.flatten() /* resolve double vec */
// .flatten() /* drop parse errors (flat_map cleared) */
.collect())
}
pub async fn get_macs(machine_name: Option<&str>, ips: Option<impl IntoIterator<Item = IpAddr>>, dev: Option<&str>, state: Option<NUDState>) -> io::Result<Vec<IpNeighLine>> {
todo!()
}
pub async fn get_macs(
machine_name: Option<&str>,
ips: Option<&[IpAddr]>,
dev: Option<&str>,
state: Option<NUDState>,
) -> io::Result<Vec<IpNeighLine>> {
// Collect IPs early (before any await) to avoid holding generics across await points
let ip_list: Option<Vec<IpAddr>> = ips.map(|slice| {
slice
.iter()
.copied()
.map(|ip| ip.to_canonical())
.collect()
});
// Resolve by machine name if no IPs provided but we have a name
let ip_list = match (ip_list, machine_name) {
(Some(list), _) => list,
(None, Some(name)) => get_ips(name).await?.into_iter().collect(),
(None, None) => Vec::new(),
};
// Helper to convert NUDState to the string expected by `ip neigh`
let nud_arg = state.map(NUDState::as_ip_neigh_arg);
// let nud_arg = Rc::new(state.map(|s| s.to_string().to_lowercase()));
// Build a closure to run one `ip neigh` invocation and parse results
let run_one = |to_ip: Option<IpAddr>| async move {
let mut args: Vec<String> = vec!["neigh".into(), "show".into()];
if let Some(ip) = to_ip {
args.push("to".into());
args.push(ip.to_string());
}
if let Some(d) = dev {
args.push("dev".into());
args.push(d.to_string());
}
if let Some(nud) = nud_arg {
args.push("nud".into());
args.push(nud.to_string());
}
let o = exec_command("ip", args.iter().map(String::as_str).collect::<Vec<_>>()).await?; // hope to rustc that it knows how to unfuck ts
if !o.status.success() {
return Err(io::Error::other(format!(
"`ip neigh` failed{ctx} (status: {st}): {err}",
ctx = to_ip.map(|ip| format!(" for {ip}")).unwrap_or_default(),
st = o.status,
err = String::from_utf8_lossy(&o.stderr),
)));
}
let lines = String::from_utf8_lossy(&o.stdout);
// Parse lines and, if a specific dev filter was used, stamp that dev onto rows
let parsed = lines.lines().flat_map(arpparse::parse_ip_neigh_line);
let rows: Vec<IpNeighLine> = if let Some(d) = dev {
parsed.map(IpNeighLine::with_dev(d)).collect()
} else {
parsed.collect()
};
Ok::<Vec<IpNeighLine>, io::Error>(rows)
};
// If we have specific IPs, query each; otherwise query the whole table once
if !ip_list.is_empty() {
let futures = ip_list.into_iter().map(|ip| run_one(Some(ip)));
let res = futures::future::try_join_all(futures).await?;
Ok(res.into_iter().flatten().collect())
} else {
run_one(None).await
}
}