mac explicit
This commit is contained in:
+31
@@ -113,6 +113,30 @@ pub async fn wake_from_query(input: impl Into<String>) -> Result<WakeResult> {
|
||||
wake_targets(targets).await
|
||||
}
|
||||
|
||||
pub async fn broadcast_wake_targets(mac: macaddr::MacAddr) -> Result<Vec<WakeTarget>> {
|
||||
Ok(get_interface_summaries()
|
||||
.await?
|
||||
.into_iter()
|
||||
.flat_map(|iface| iface.addrs.into_iter())
|
||||
.filter_map(|addr| addr.broadcast)
|
||||
.map(|ip| WakeTarget {
|
||||
ip: Some(std::net::IpAddr::V4(ip)),
|
||||
mac: Some(mac),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn wake_explicit(mac: macaddr::MacAddr, ip: Option<std::net::IpAddr>) -> Result<WakeResult> {
|
||||
let targets = match ip {
|
||||
Some(ip) => vec![WakeTarget {
|
||||
ip: Some(ip),
|
||||
mac: Some(mac),
|
||||
}],
|
||||
None => broadcast_wake_targets(mac).await?,
|
||||
};
|
||||
wake_targets(targets).await
|
||||
}
|
||||
|
||||
pub async fn list_interfaces() -> Result<Vec<String>> {
|
||||
Ok(wakey_linux::devices::devs_sorted().await)
|
||||
}
|
||||
@@ -121,6 +145,13 @@ pub async fn get_interface_summaries() -> Result<Vec<InterfaceSummary>> {
|
||||
wakey_linux::devices::list_interface_summaries().await
|
||||
}
|
||||
|
||||
pub async fn get_interface_summary(name: &str) -> Result<Option<InterfaceSummary>> {
|
||||
Ok(get_interface_summaries()
|
||||
.await?
|
||||
.into_iter()
|
||||
.find(|iface| iface.ifname == name))
|
||||
}
|
||||
|
||||
pub async fn get_ips(name: impl AsRef<str>) -> Result<Vec<std::net::IpAddr>> {
|
||||
Ok(wakey_linux::devices::get_ips(name.as_ref())
|
||||
.await?
|
||||
|
||||
+113
-4
@@ -40,7 +40,11 @@ struct LeasesArgs {
|
||||
|
||||
#[derive(Args)]
|
||||
struct WakeArgs {
|
||||
query: String,
|
||||
query: Option<String>,
|
||||
#[arg(long)]
|
||||
mac: Option<macaddr::MacAddr>,
|
||||
#[arg(long)]
|
||||
ip: Option<IpAddr>,
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
}
|
||||
@@ -64,6 +68,9 @@ struct StatusArgs {
|
||||
|
||||
#[derive(Args)]
|
||||
struct DevsArgs {
|
||||
dev: Option<String>,
|
||||
#[arg(long)]
|
||||
up: bool,
|
||||
#[arg(long)]
|
||||
json: bool,
|
||||
}
|
||||
@@ -149,6 +156,36 @@ fn render_wake_table(result: &WakeResult) -> Table {
|
||||
table
|
||||
}
|
||||
|
||||
fn validate_wake_args(args: &WakeArgs) -> anyhow::Result<()> {
|
||||
let has_query = args.query.is_some();
|
||||
let has_mac = args.mac.is_some();
|
||||
let has_ip = args.ip.is_some();
|
||||
|
||||
if has_ip && !has_mac {
|
||||
anyhow::bail!("`wakey wake --ip` needs `--mac`");
|
||||
}
|
||||
|
||||
if has_query && (has_mac || has_ip) {
|
||||
anyhow::bail!("query mode and explicit `--mac/--ip` mode are mutually exclusive");
|
||||
}
|
||||
|
||||
if !has_query && !has_mac {
|
||||
anyhow::bail!("provide either a query or `--mac`");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_wake(args: WakeArgs) -> anyhow::Result<WakeResult> {
|
||||
validate_wake_args(&args)?;
|
||||
|
||||
match (args.query, args.mac, args.ip) {
|
||||
(Some(query), None, None) => wakey::wake_from_query(query).await,
|
||||
(None, Some(mac), ip) => wakey::wake_explicit(mac, ip).await,
|
||||
_ => unreachable!("wake args validated before dispatch"),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_devs_table(devs: &[InterfaceSummary]) -> Table {
|
||||
let mut table = base_table();
|
||||
table.set_header([
|
||||
@@ -198,6 +235,16 @@ fn render_devs_table(devs: &[InterfaceSummary]) -> Table {
|
||||
table
|
||||
}
|
||||
|
||||
fn filter_interface_summaries(mut devs: Vec<InterfaceSummary>, args: &DevsArgs) -> Vec<InterfaceSummary> {
|
||||
if args.up {
|
||||
devs.retain(|dev| dev.operstate == "up");
|
||||
}
|
||||
if let Some(name) = &args.dev {
|
||||
devs.retain(|dev| &dev.ifname == name);
|
||||
}
|
||||
devs
|
||||
}
|
||||
|
||||
fn format_epoch_local(epoch: u64) -> String {
|
||||
match DateTime::<Utc>::from_timestamp(epoch as i64, 0) {
|
||||
Some(dt) => dt
|
||||
@@ -258,15 +305,24 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
Command::Wake(args) => {
|
||||
let result = wakey::wake_from_query(args.query).await?;
|
||||
if args.json {
|
||||
let as_json = args.json;
|
||||
let result = run_wake(args).await?;
|
||||
if as_json {
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
} else {
|
||||
println!("{}", render_wake_table(&result));
|
||||
}
|
||||
}
|
||||
Command::Devs(args) => {
|
||||
let devs = wakey::get_interface_summaries().await?;
|
||||
let devs = if let Some(name) = &args.dev {
|
||||
wakey::get_interface_summary(name)
|
||||
.await?
|
||||
.into_iter()
|
||||
.collect()
|
||||
} else {
|
||||
wakey::get_interface_summaries().await?
|
||||
};
|
||||
let devs = filter_interface_summaries(devs, &args);
|
||||
if args.json {
|
||||
println!("{}", serde_json::to_string_pretty(&devs)?);
|
||||
} else {
|
||||
@@ -276,3 +332,56 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::WakeArgs;
|
||||
|
||||
#[test]
|
||||
fn wake_rejects_ip_without_mac() {
|
||||
let err = super::validate_wake_args(&WakeArgs {
|
||||
query: None,
|
||||
mac: None,
|
||||
ip: Some("192.168.1.10".parse().expect("ip")),
|
||||
json: false,
|
||||
})
|
||||
.expect_err("ip-only wake should be rejected");
|
||||
|
||||
assert!(err.to_string().contains("--ip"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wake_rejects_mixed_query_and_explicit_mode() {
|
||||
let err = super::validate_wake_args(&WakeArgs {
|
||||
query: Some("pc".into()),
|
||||
mac: Some("aa:bb:cc:dd:ee:ff".parse().expect("mac")),
|
||||
ip: None,
|
||||
json: false,
|
||||
})
|
||||
.expect_err("mixed wake mode should be rejected");
|
||||
|
||||
assert!(err.to_string().contains("mutually exclusive"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wake_accepts_query_mode() {
|
||||
super::validate_wake_args(&WakeArgs {
|
||||
query: Some("pc".into()),
|
||||
mac: None,
|
||||
ip: None,
|
||||
json: false,
|
||||
})
|
||||
.expect("query mode should be accepted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wake_accepts_manual_mac_mode() {
|
||||
super::validate_wake_args(&WakeArgs {
|
||||
query: None,
|
||||
mac: Some("aa:bb:cc:dd:ee:ff".parse().expect("mac")),
|
||||
ip: None,
|
||||
json: false,
|
||||
})
|
||||
.expect("manual mac mode should be accepted");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user