cli refactor and more tracing

This commit is contained in:
lda
2026-04-06 17:58:47 +07:00 Unverified
parent c393111cb0
commit 93a88741f9
7 changed files with 507 additions and 501 deletions
+10 -3
View File
@@ -1,4 +1,5 @@
use anyhow::Result;
use tracing::{debug, instrument};
use wakey_core::InterfaceSummary;
/// Return interface names only.
@@ -9,16 +10,22 @@ pub async fn list_interfaces() -> Result<Vec<String>> {
}
/// Return condensed interface summaries useful for CLI and wake routing.
#[instrument(skip_all)]
pub async fn get_interface_summaries() -> Result<Vec<InterfaceSummary>> {
wakey_linux::devices::list_interface_summaries().await
let summaries = wakey_linux::devices::list_interface_summaries().await?;
debug!(count = summaries.len(), "loaded interface summaries");
Ok(summaries)
}
/// Return one named interface summary when present.
#[instrument(skip_all, fields(ifname = name))]
pub async fn get_interface_summary(name: &str) -> Result<Option<InterfaceSummary>> {
Ok(get_interface_summaries()
let summary = get_interface_summaries()
.await?
.into_iter()
.find(|iface| iface.ifname == name))
.find(|iface| iface.ifname == name);
debug!(found = summary.is_some(), "resolved interface summary");
Ok(summary)
}
/// Resolve a hostname through the local resolver and collect all returned IPs.
+5 -1
View File
@@ -1,4 +1,5 @@
use anyhow::Result;
use tracing::{debug, instrument};
use wakey_core::{Device, DeviceQuery, NeighborEntry, Presence, Status};
use crate::service::inventory::inventory;
@@ -11,13 +12,15 @@ pub type StatusResponse = Status<NeighborEntry>;
///
/// This keeps the old status response shape alive while the underlying model is
/// increasingly device-centered.
#[instrument(skip_all, fields(name = ?query.name))]
pub async fn get_status(query: DeviceQuery) -> Result<StatusResponse> {
let inventory = inventory(query.clone()).await?;
let table = inventory
let table: Vec<NeighborEntry> = inventory
.devices
.iter()
.flat_map(device_to_status_rows)
.collect();
debug!(rows = table.len(), devices = inventory.devices.len(), "built status response");
Ok(Status {
name: query.name,
table,
@@ -26,6 +29,7 @@ pub async fn get_status(query: DeviceQuery) -> Result<StatusResponse> {
}
/// Convenience wrapper around [`get_status`] for free-form user input.
#[instrument(skip_all)]
pub async fn get_status_for_input(input: impl Into<String>) -> Result<StatusResponse> {
let query = resolve_query(input).await?;
get_status(query).await
+12 -2
View File
@@ -1,20 +1,24 @@
use anyhow::{Context, Result};
use macaddr::MacAddr;
use std::net::IpAddr;
use tracing::{debug, instrument};
use wakey_core::{InterfaceSummary, WakeResult, WakeTarget};
use crate::service::interfaces::get_interface_summaries;
use crate::service::inventory::resolve_devices;
/// Send Wake-on-LAN packets for already-concrete wake targets.
#[instrument(skip_all, fields(targets = targets.len()))]
pub async fn wake_targets(targets: Vec<WakeTarget>) -> Result<WakeResult> {
let result = wakey_linux::wake::wake_many(targets)
.await
.context("failed to send wake packets")?;
debug!(results = result.len(), "wake packets sent");
Ok(WakeResult { result })
}
/// Resolve free-form input into wake targets and send the packets.
#[instrument(skip_all)]
pub async fn wake_from_query(input: impl Into<String>) -> Result<WakeResult> {
let targets = resolve_wake_targets(input).await?;
wake_targets(targets).await
@@ -23,12 +27,14 @@ pub async fn wake_from_query(input: impl Into<String>) -> Result<WakeResult> {
/// Build broadcast wake targets for every broadcast-capable interface.
///
/// This is used by explicit manual wake mode when only a MAC address is supplied.
#[instrument(skip_all)]
pub async fn broadcast_wake_targets(mac: MacAddr) -> Result<Vec<WakeTarget>> {
let interfaces = get_interface_summaries().await?;
broadcast_wake_targets_from_interfaces(&interfaces, mac)
}
/// Wake a device explicitly by MAC, optionally targeting a specific IP/broadcast.
#[instrument(skip_all, fields(has_ip = ip.is_some()))]
pub async fn wake_explicit(mac: MacAddr, ip: Option<IpAddr>) -> Result<WakeResult> {
let targets = match ip {
Some(ip) => explicit_wake_targets_for_ip(mac, ip),
@@ -41,9 +47,10 @@ pub async fn wake_explicit(mac: MacAddr, ip: Option<IpAddr>) -> Result<WakeResul
///
/// The current resolution strategy fans out one wake target per resolved device IP,
/// using the first known MAC address for that device.
#[instrument(skip_all)]
pub async fn resolve_wake_targets(input: impl Into<String>) -> Result<Vec<WakeTarget>> {
let devices = resolve_devices(input).await?;
Ok(devices
let targets: Vec<WakeTarget> = devices
.into_iter()
.flat_map(|device| {
let mac = device.macs.first().copied();
@@ -52,7 +59,9 @@ pub async fn resolve_wake_targets(input: impl Into<String>) -> Result<Vec<WakeTa
.into_iter()
.map(move |ip| WakeTarget { ip: Some(ip), mac })
})
.collect())
.collect();
debug!(targets = targets.len(), "resolved wake targets");
Ok(targets)
}
fn explicit_wake_targets_for_ip(mac: MacAddr, ip: IpAddr) -> Vec<WakeTarget> {
@@ -80,6 +89,7 @@ fn broadcast_wake_targets_from_interfaces(
anyhow::bail!("no broadcast-capable interfaces found");
}
debug!(targets = targets.len(), interfaces = interfaces.len(), "built broadcast wake targets");
Ok(targets)
}