doc sweep!

This commit is contained in:
lda
2026-04-06 05:43:37 +07:00 Unverified
parent 67aa50ec5c
commit 79a6157a3a
22 changed files with 188 additions and 23 deletions
+14
View File
@@ -3,6 +3,10 @@ use lda_ipjs::subcommands::address;
use std::collections::HashSet;
use wakey_core::{InterfaceAddr, InterfaceSummary};
/// Discover interface names from Linux without requiring `ip`.
///
/// This is the lowest-common-denominator interface listing path and is used for
/// quick existence checks and legacy string-only callers.
pub async fn list_devs() -> HashSet<String> {
fn get_dev() -> HashSet<String> {
let mut devs: HashSet<String> = HashSet::new();
@@ -50,6 +54,15 @@ pub async fn devs_sorted() -> Vec<String> {
v
}
/// Build condensed interface summaries from Linux address data.
///
/// On Unix this prefers the `ipjs` netlink-backed address path; elsewhere it
/// falls back to the JSON command path. The result is not a full `ip address show`
/// dump. It is a smaller projection containing the parts `wakey` currently uses:
/// interface name/index, operstate, MAC, bound addresses, and IPv4 broadcast
/// addresses for Wake-on-LAN delivery.
///
/// Loopback is intentionally excluded.
pub async fn list_interface_summaries() -> Result<Vec<InterfaceSummary>> {
#[cfg(unix)]
let rows = address::nl::get(None)
@@ -91,6 +104,7 @@ pub async fn list_interface_summaries() -> Result<Vec<InterfaceSummary>> {
Ok(out)
}
/// Return whether a named interface exists according to [`list_devs`].
pub async fn has_dev(name: &str) -> bool {
list_devs().await.contains(name)
}
+7
View File
@@ -5,6 +5,7 @@ use std::collections::HashSet;
use std::net::IpAddr;
use wakey_core::{DeviceQuery, NeighborEntry, NeighborState};
/// Resolve a hostname through the local resolver and return all reported IPs.
pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>> {
Ok(tokio::net::lookup_host((machine_name, 0))
.await
@@ -12,6 +13,11 @@ pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>>
.map(|c| c.ip()))
}
/// Query Linux neighbor data and project it into `wakey-core` neighbor rows.
///
/// `machine_names` are resolved first and intersected with any explicit `ips`
/// filter. On Unix this prefers the netlink-backed `ipjs` path; elsewhere it
/// falls back to the JSON command backend.
pub async fn get_neighbors(
machine_names: &[impl AsRef<str>],
ips: &[IpAddr],
@@ -100,6 +106,7 @@ pub async fn get_neighbors(
}
}
/// Convenience wrapper around [`get_neighbors`] using the legacy `DeviceQuery`.
pub async fn query_status(query: &DeviceQuery) -> Result<Vec<NeighborEntry>> {
get_neighbors(
query.name.as_slice(),
+4
View File
@@ -4,6 +4,10 @@ use wakey_core::{NeighborState, QueryInput, parse};
use crate::devices::interfaces::has_dev;
/// Classify one free-form input string into the most specific query variant.
///
/// The current precedence is:
/// IP address, MAC address, neighbor state, interface name, then plain text.
pub async fn classify_query(q: String) -> QueryInput {
let s = parse::extract_host(&q);
if let Some(ip) = parse::parse_numeric_ipv4(s).or_else(|| s.parse::<IpAddr>().ok()) {
+6
View File
@@ -5,6 +5,7 @@ use wakey_core::{DhcpLease, DhcpLeaseWithState};
const MAC_NAME_CACHE: &str = "/tmp/wakey_mac_names.json";
/// Load the MAC-to-name cache used to preserve useful names across lease churn.
pub async fn load_mac_name_cache() -> io::Result<std::collections::BTreeMap<String, String>> {
match tokio::fs::read_to_string(MAC_NAME_CACHE).await {
Ok(s) => serde_json::from_str(&s).map_err(io::Error::other),
@@ -13,12 +14,14 @@ pub async fn load_mac_name_cache() -> io::Result<std::collections::BTreeMap<Stri
}
}
/// Persist the MAC-to-name cache back to disk.
async fn save_mac_name_cache(map: &std::collections::BTreeMap<String, String>) -> io::Result<()> {
let s = serde_json::to_string(map).map_err(io::Error::other)?;
let _ = tokio::fs::write(MAC_NAME_CACHE, s).await;
Ok(())
}
/// Parse one `dnsmasq`-style DHCP lease line.
pub fn parse_dhcp_lease_line(line: &str) -> Option<DhcpLease> {
let mut c = line.split_whitespace();
let expires_epoch: u64 = c.next()?.parse().ok()?;
@@ -33,6 +36,7 @@ pub fn parse_dhcp_lease_line(line: &str) -> Option<DhcpLease> {
})
}
/// Read raw DHCP leases from `/tmp/dhcp.leases`.
pub async fn read_dhcp_leases() -> io::Result<Vec<DhcpLease>> {
match tokio::fs::read_to_string("/tmp/dhcp.leases").await {
Ok(file) => Ok(file.lines().filter_map(parse_dhcp_lease_line).collect()),
@@ -41,6 +45,7 @@ pub async fn read_dhcp_leases() -> io::Result<Vec<DhcpLease>> {
}
}
/// Read DHCP leases and fill missing names from the MAC-name cache.
pub async fn read_dhcp_leases_with_names() -> io::Result<Vec<DhcpLease>> {
let leases = read_dhcp_leases().await?;
let mut cache = load_mac_name_cache().await.unwrap_or_default();
@@ -64,6 +69,7 @@ pub async fn read_dhcp_leases_with_names() -> io::Result<Vec<DhcpLease>> {
Ok(leases_with_names)
}
/// Enrich DHCP leases with the best currently known neighbor state per IP.
pub async fn enrich_leases_with_nud_state(leases: Vec<DhcpLease>) -> Vec<DhcpLeaseWithState> {
let ips: Vec<IpAddr> = leases.iter().map(|l| l.ip).collect();
let mut map: std::collections::HashMap<IpAddr, wakey_core::NeighborState> =
+6
View File
@@ -5,6 +5,7 @@ use macaddr::MacAddr;
use tokio::net::UdpSocket;
use wakey_core::{WakeStatus, WakeTarget, WakeTargetResult};
/// Wake target with the minimum fields needed to send a magic packet.
#[derive(Debug, Clone, Copy, Hash)]
pub struct CompleteWakeTarget {
pub ip: IpAddr,
@@ -27,6 +28,7 @@ impl TryFrom<WakeTarget> for CompleteWakeTarget {
}
}
/// Send one Wake-on-LAN magic packet to a complete target.
pub async fn wake_one(sock: &UdpSocket, t: CompleteWakeTarget) -> WakeTargetResult {
let mac = t.mac;
let mb = mac.as_bytes();
@@ -60,6 +62,10 @@ pub async fn wake_one(sock: &UdpSocket, t: CompleteWakeTarget) -> WakeTargetResu
}
}
/// Send Wake-on-LAN packets for many targets using one UDP socket.
///
/// Incomplete targets are not rejected with an error; they are returned as
/// `WakeStatus::Incomplete` result rows.
pub async fn wake_many(
targets: impl IntoIterator<Item = WakeTarget>,
) -> io::Result<Vec<WakeTargetResult>> {