woah calm down blud
This commit is contained in:
+7
-2
@@ -11,8 +11,9 @@ use axum::Router;
|
|||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
use wakey_core::{
|
use wakey_core::{
|
||||||
Device, DeviceFilters, DeviceInventory, DeviceQuery, DhcpLease, DhcpLeaseWithState, LeaseQuery,
|
Device, DeviceFilters, DeviceInventory, DeviceQuery, DhcpLease, DhcpLeaseWithState,
|
||||||
NeighborEntry, Presence, Query, QueryInput, Status, WakeResult, WakeTarget,
|
InterfaceSummary, LeaseQuery, NeighborEntry, Presence, Query, QueryInput, Status, WakeResult,
|
||||||
|
WakeTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type StatusResponse = Status<NeighborEntry>;
|
pub type StatusResponse = Status<NeighborEntry>;
|
||||||
@@ -116,6 +117,10 @@ pub async fn list_interfaces() -> Result<Vec<String>> {
|
|||||||
Ok(wakey_linux::devices::devs_sorted().await)
|
Ok(wakey_linux::devices::devs_sorted().await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_interface_summaries() -> Result<Vec<InterfaceSummary>> {
|
||||||
|
wakey_linux::devices::list_interface_summaries().await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_ips(name: impl AsRef<str>) -> Result<Vec<std::net::IpAddr>> {
|
pub async fn get_ips(name: impl AsRef<str>) -> Result<Vec<std::net::IpAddr>> {
|
||||||
Ok(wakey_linux::devices::get_ips(name.as_ref())
|
Ok(wakey_linux::devices::get_ips(name.as_ref())
|
||||||
.await?
|
.await?
|
||||||
|
|||||||
+60
-10
@@ -2,8 +2,8 @@ use std::net::{IpAddr, SocketAddr};
|
|||||||
|
|
||||||
use chrono::{DateTime, Local, Utc};
|
use chrono::{DateTime, Local, Utc};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use comfy_table::{Cell, ContentArrangement, Table, presets::UTF8_FULL};
|
use comfy_table::{Cell, ContentArrangement, Table, presets};
|
||||||
use wakey_core::{DeviceFilters, DeviceQuery, DhcpLeaseWithState, WakeResult};
|
use wakey_core::{DeviceFilters, DeviceQuery, DhcpLeaseWithState, InterfaceSummary, WakeResult};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "wakey")]
|
#[command(name = "wakey")]
|
||||||
@@ -19,7 +19,7 @@ enum Command {
|
|||||||
Status(StatusArgs),
|
Status(StatusArgs),
|
||||||
Leases(LeasesArgs),
|
Leases(LeasesArgs),
|
||||||
Wake(WakeArgs),
|
Wake(WakeArgs),
|
||||||
Devs,
|
Devs(DevsArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
@@ -62,6 +62,12 @@ struct StatusArgs {
|
|||||||
json: bool,
|
json: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
struct DevsArgs {
|
||||||
|
#[arg(long)]
|
||||||
|
json: bool,
|
||||||
|
}
|
||||||
|
|
||||||
fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
|
fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
|
||||||
if let Some(query) = args.query.as_ref()
|
if let Some(query) = args.query.as_ref()
|
||||||
&& args.name.is_none()
|
&& args.name.is_none()
|
||||||
@@ -90,7 +96,7 @@ fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
|
|||||||
fn base_table() -> Table {
|
fn base_table() -> Table {
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
table
|
table
|
||||||
.load_preset(UTF8_FULL)
|
.load_preset(presets::UTF8_FULL_CONDENSED)
|
||||||
.set_content_arrangement(ContentArrangement::Dynamic);
|
.set_content_arrangement(ContentArrangement::Dynamic);
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
@@ -143,11 +149,51 @@ fn render_wake_table(result: &WakeResult) -> Table {
|
|||||||
table
|
table
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_devs_table(devs: &[String]) -> Table {
|
fn render_devs_table(devs: &[InterfaceSummary]) -> Table {
|
||||||
let mut table = base_table();
|
let mut table = base_table();
|
||||||
table.set_header(["Interface"]);
|
table.set_header([
|
||||||
|
"Interface",
|
||||||
|
"State",
|
||||||
|
"MAC",
|
||||||
|
"Addresses",
|
||||||
|
"Broadcasts",
|
||||||
|
"Scope/Label",
|
||||||
|
]);
|
||||||
for dev in devs {
|
for dev in devs {
|
||||||
table.add_row([Cell::new(dev)]);
|
let addresses = dev
|
||||||
|
.addrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|addr| addr.cidr.as_deref())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let broadcasts = dev
|
||||||
|
.addrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|addr| addr.broadcast)
|
||||||
|
.map(|addr| addr.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
let scope_label = dev
|
||||||
|
.addrs
|
||||||
|
.iter()
|
||||||
|
.map(|addr| match (&addr.scope, &addr.label) {
|
||||||
|
(Some(scope), Some(label)) => format!("{scope} ({label})"),
|
||||||
|
(Some(scope), None) => scope.clone(),
|
||||||
|
(None, Some(label)) => label.clone(),
|
||||||
|
(None, None) => String::new(),
|
||||||
|
})
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
table.add_row([
|
||||||
|
Cell::new(&dev.ifname),
|
||||||
|
Cell::new(&dev.operstate),
|
||||||
|
Cell::new(dev.mac.map(|m| m.to_string()).unwrap_or_default()),
|
||||||
|
Cell::new(addresses),
|
||||||
|
Cell::new(broadcasts),
|
||||||
|
Cell::new(scope_label),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
@@ -219,9 +265,13 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
println!("{}", render_wake_table(&result));
|
println!("{}", render_wake_table(&result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Devs => {
|
Command::Devs(args) => {
|
||||||
let devs = wakey::list_interfaces().await?;
|
let devs = wakey::get_interface_summaries().await?;
|
||||||
println!("{}", render_devs_table(&devs));
|
if args.json {
|
||||||
|
println!("{}", serde_json::to_string_pretty(&devs)?);
|
||||||
|
} else {
|
||||||
|
println!("{}", render_devs_table(&devs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -250,6 +250,27 @@ pub struct DeviceInventory {
|
|||||||
pub devices: Vec<Device>,
|
pub devices: Vec<Device>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct InterfaceSummary {
|
||||||
|
pub ifindex: u32,
|
||||||
|
pub ifname: String,
|
||||||
|
pub operstate: String,
|
||||||
|
#[serde(with = "mac::option_mac")]
|
||||||
|
pub mac: Option<MacAddr>,
|
||||||
|
pub addrs: Vec<InterfaceAddr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct InterfaceAddr {
|
||||||
|
pub family: Option<String>,
|
||||||
|
pub cidr: Option<String>,
|
||||||
|
pub broadcast: Option<std::net::Ipv4Addr>,
|
||||||
|
pub scope: Option<String>,
|
||||||
|
pub label: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct WakeTarget {
|
pub struct WakeTarget {
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ use anyhow::{Context, Result};
|
|||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use wakey_core::{DeviceQuery, NeighborEntry, NeighborState, QueryInput, parse};
|
use wakey_core::{
|
||||||
|
DeviceQuery, InterfaceAddr, InterfaceSummary, NeighborEntry, NeighborState, QueryInput, parse,
|
||||||
|
};
|
||||||
|
|
||||||
use lda_ipjs::subcommands::neighbor;
|
use lda_ipjs::subcommands::{address, neighbor};
|
||||||
|
|
||||||
pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>> {
|
pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>> {
|
||||||
Ok(tokio::net::lookup_host((machine_name, 0))
|
Ok(tokio::net::lookup_host((machine_name, 0))
|
||||||
@@ -159,6 +161,47 @@ pub async fn devs_sorted() -> Vec<String> {
|
|||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_interface_summaries() -> Result<Vec<InterfaceSummary>> {
|
||||||
|
#[cfg(unix)]
|
||||||
|
let rows = address::nl::get(None)
|
||||||
|
.await
|
||||||
|
.context("rtnetlink address query failed")?;
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
let rows = address::get_with_backend(address::Backend::Json, None)
|
||||||
|
.await
|
||||||
|
.context("ip -j address show failed")?;
|
||||||
|
|
||||||
|
let mut out: Vec<InterfaceSummary> = rows
|
||||||
|
.into_iter()
|
||||||
|
.filter(|row| row.ifname != "lo")
|
||||||
|
.map(|row| InterfaceSummary {
|
||||||
|
ifindex: row.ifindex,
|
||||||
|
ifname: row.ifname,
|
||||||
|
operstate: row.operstate.as_str().to_ascii_lowercase(),
|
||||||
|
mac: row.address,
|
||||||
|
addrs: row
|
||||||
|
.addr_info
|
||||||
|
.into_iter()
|
||||||
|
.map(|info| InterfaceAddr {
|
||||||
|
family: info.family.map(|family| family.as_str().to_string()),
|
||||||
|
cidr: info
|
||||||
|
.cidr
|
||||||
|
.local
|
||||||
|
.zip(info.cidr.prefixlen)
|
||||||
|
.map(|(addr, prefixlen)| format!("{addr}/{prefixlen}")),
|
||||||
|
broadcast: info.broadcast,
|
||||||
|
scope: info.scope,
|
||||||
|
label: info.label,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
out.sort_by(|a, b| a.ifname.cmp(&b.ifname));
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn has_dev(name: &str) -> bool {
|
pub async fn has_dev(name: &str) -> bool {
|
||||||
list_devs().await.contains(name)
|
list_devs().await.contains(name)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user