This commit is contained in:
lda
2026-04-05 02:34:17 +07:00 Unverified
parent 0712e87e6f
commit 7eee1e0bab
9 changed files with 382 additions and 68 deletions
Generated
+225 -9
View File
@@ -329,12 +329,46 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "comfy-table"
version = "7.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47"
dependencies = [
"crossterm",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"document-features",
"parking_lot",
"rustix",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "darling"
version = "0.21.3"
@@ -380,6 +414,15 @@ dependencies = [
"serde_core",
]
[[package]]
name = "document-features"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
dependencies = [
"litrs",
]
[[package]]
name = "dyn-clone"
version = "1.0.20"
@@ -749,6 +792,28 @@ version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litrs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.29"
@@ -914,6 +979,29 @@ version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
[[package]]
name = "parking_lot"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.6",
]
[[package]]
name = "paste"
version = "1.0.15"
@@ -962,6 +1050,15 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "ref-cast"
version = "1.0.25"
@@ -1006,6 +1103,19 @@ version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustix"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
@@ -1042,6 +1152,12 @@ dependencies = [
"serde_json",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.228"
@@ -1471,6 +1587,18 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-segmentation"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
[[package]]
name = "unicode-width"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "urlencoding"
version = "2.1.3"
@@ -1496,8 +1624,10 @@ dependencies = [
"anyhow",
"axum",
"axum-extra",
"chrono",
"clap",
"color-eyre",
"comfy-table",
"futures",
"lda-ipjs",
"macaddr",
@@ -1586,6 +1716,28 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.62.2"
@@ -1651,7 +1803,7 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
"windows-targets 0.53.5",
]
[[package]]
@@ -1663,6 +1815,22 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
@@ -1670,58 +1838,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
+2
View File
@@ -8,8 +8,10 @@ publish = ["gitea"]
anyhow = "1"
axum = { version = "0", features = ["macros"] }
axum-extra = { version = "0", features = ["query"] }
chrono = { version = "0.4", default-features = false, features = ["clock"] }
clap = { version = "4", features = ["derive"] }
color-eyre = "0"
comfy-table = "7"
futures = "0"
macaddr = { version = "1", features = ["serde", "serde_std"] }
serde = { version = "1", features = ["derive"] }
+2 -1
View File
@@ -171,7 +171,8 @@ mod tests {
vec![],
)],
};
let legacy = legacy_status_from_inventory(inventory, Some("pc".into()), DeviceFilters::default());
let legacy =
legacy_status_from_inventory(inventory, Some("pc".into()), DeviceFilters::default());
assert_eq!(legacy.name.as_deref(), Some("pc"));
assert_eq!(legacy.table.len(), 1);
assert_eq!(legacy.table[0].state, NeighborState::Reachable);
+104 -5
View File
@@ -1,7 +1,9 @@
use std::net::{IpAddr, SocketAddr};
use chrono::{DateTime, Local, Utc};
use clap::{Args, Parser, Subcommand};
use wakey_core::{DeviceFilters, DeviceQuery};
use comfy_table::{Cell, ContentArrangement, Table, presets::UTF8_FULL};
use wakey_core::{DeviceFilters, DeviceQuery, DhcpLeaseWithState, WakeResult};
#[derive(Parser)]
#[command(name = "wakey")]
@@ -32,11 +34,15 @@ struct HttpArgs {
struct LeasesArgs {
#[arg(long)]
include_state: bool,
#[arg(long)]
json: bool,
}
#[derive(Args)]
struct WakeArgs {
query: String,
#[arg(long)]
json: bool,
}
#[derive(Args)]
@@ -52,6 +58,8 @@ struct StatusArgs {
nuds: Vec<wakey_core::NeighborState>,
#[arg(long = "mac")]
macs: Vec<macaddr::MacAddr>,
#[arg(long)]
json: bool,
}
fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
@@ -79,6 +87,81 @@ fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
}
}
fn base_table() -> Table {
let mut table = Table::new();
table
.load_preset(UTF8_FULL)
.set_content_arrangement(ContentArrangement::Dynamic);
table
}
fn render_status_table(status: &wakey::StatusResponse) -> Table {
let mut table = base_table();
table.set_header(["IP", "MAC", "State", "IF"]);
for row in &status.table {
table.add_row([
Cell::new(row.ip),
Cell::new(row.mac.map(|m| m.to_string()).unwrap_or_default()),
Cell::new(format!("{:?}", row.state).to_lowercase()),
Cell::new(row.dev.clone().unwrap_or_default()),
]);
}
table
}
fn render_leases_table(leases: &[DhcpLeaseWithState]) -> Table {
let mut table = base_table();
table.set_header(["IP", "MAC", "Name", "Expires", "NUD"]);
for lease in leases {
let expires = format_epoch_local(lease.lease_line.expires_epoch);
table.add_row([
Cell::new(lease.lease_line.ip),
Cell::new(lease.lease_line.mac),
Cell::new(lease.lease_line.name.clone().unwrap_or_default()),
Cell::new(expires),
Cell::new(
lease
.nud_state
.map(|s| format!("{:?}", s).to_lowercase())
.unwrap_or_default(),
),
]);
}
table
}
fn render_wake_table(result: &WakeResult) -> Table {
let mut table = base_table();
table.set_header(["IP", "MAC", "Status"]);
for row in &result.result {
table.add_row([
Cell::new(row.target.ip.map(|ip| ip.to_string()).unwrap_or_default()),
Cell::new(row.target.mac.map(|m| m.to_string()).unwrap_or_default()),
Cell::new(format!("{:?}", row.status).to_lowercase()),
]);
}
table
}
fn render_devs_table(devs: &[String]) -> Table {
let mut table = base_table();
table.set_header(["Interface"]);
for dev in devs {
table.add_row([Cell::new(dev)]);
}
table
}
fn format_epoch_local(epoch: u64) -> String {
match DateTime::<Utc>::from_timestamp(epoch as i64, 0) {
Some(dt) => dt
.with_timezone(&Local)
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
None => epoch.to_string(),
}
}
#[cfg(not(target_os = "linux"))]
fn main() -> anyhow::Result<()> {
Err(anyhow::anyhow!(
@@ -96,6 +179,7 @@ async fn main() -> anyhow::Result<()> {
wakey::serve_http_from_current_exe(addr).await?;
}
Command::Status(args) => {
let as_json = args.json;
let query = status_args_to_query(args);
let status = if query.name.is_some()
&& query.filter.ips.is_empty()
@@ -107,22 +191,37 @@ async fn main() -> anyhow::Result<()> {
} else {
wakey::get_status(query).await?
};
println!("{}", serde_json::to_string_pretty(&status)?);
if as_json {
println!("{}", serde_json::to_string_pretty(&status)?);
} else {
if let Some(name) = &status.name {
println!("name: {name}");
}
println!("{}", render_status_table(&status));
}
}
Command::Leases(args) => {
let leases = wakey::get_leases(wakey_core::LeaseQuery {
include_state: args.include_state,
})
.await?;
println!("{}", serde_json::to_string_pretty(&leases)?);
if args.json {
println!("{}", serde_json::to_string_pretty(&leases)?);
} else {
println!("{}", render_leases_table(&leases));
}
}
Command::Wake(args) => {
let result = wakey::wake_from_query(args.query).await?;
println!("{}", serde_json::to_string_pretty(&result)?);
if args.json {
println!("{}", serde_json::to_string_pretty(&result)?);
} else {
println!("{}", render_wake_table(&result));
}
}
Command::Devs => {
let devs = wakey::list_interfaces().await?;
println!("{}", serde_json::to_string_pretty(&devs)?);
println!("{}", render_devs_table(&devs));
}
}
Ok(())
+1 -2
View File
@@ -5,9 +5,8 @@
// [0xbc, 0x09, 0x1b, 0xec, 0x65, 0xd0],
// ];
/// is it time to lookup host lda.lan for this...
// is it time to lookup host lda.lan for this...
// pub static LDA_MACS_2: LazyLock<[MacAddr; 2]> = LazyLock::new(|| LDA_MACS.map(MacAddr::from));
pub mod wake;
/// generic so you can do "123.45.67.89:22" or "lda.lan:22" as an input
// this is so bad
+48
View File
@@ -0,0 +1,48 @@
pub mod dev {
pub use wakey_linux::devices::devs_sorted;
}
pub mod leases {
pub use wakey_linux::dhcp::enrich_leases_with_nud_state;
}
pub mod parser {
pub use wakey_core::QueryInput as QueryType;
pub async fn parse_query(q: String) -> QueryType {
wakey_linux::devices::classify_query(q).await
}
}
pub use leases::*;
pub use macs::*;
pub mod macs {
use anyhow::Result;
use std::net::IpAddr;
use crate::arpparse::{IpNeighLine, NUDState};
pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>> {
wakey_linux::devices::get_ips(machine_name).await
}
pub async fn get_macs(
machine_names: &[impl AsRef<str>],
ips: &[IpAddr],
devs: &[impl AsRef<str>],
state: &[NUDState],
macs: &[macaddr::MacAddr],
) -> Result<Vec<IpNeighLine>> {
wakey_linux::devices::get_neighbors(machine_names, ips, devs, state, macs).await
}
pub async fn get_mac(
ip: Option<IpAddr>,
dev: Option<&str>,
state: &[NUDState],
) -> Result<Vec<IpNeighLine>> {
let ips: Vec<IpAddr> = ip.into_iter().collect();
let devs: Vec<&str> = dev.into_iter().collect();
get_macs(&[] as &[&str], &ips, &devs, state, &[]).await
}
}
-28
View File
@@ -1,28 +0,0 @@
use anyhow::Result;
use std::net::IpAddr;
use crate::arpparse::{IpNeighLine, NUDState};
pub async fn get_ips(machine_name: &str) -> Result<impl Iterator<Item = IpAddr>> {
wakey_linux::devices::get_ips(machine_name).await
}
pub async fn get_macs(
machine_names: &[impl AsRef<str>],
ips: &[IpAddr],
devs: &[impl AsRef<str>],
state: &[NUDState],
macs: &[macaddr::MacAddr],
) -> Result<Vec<IpNeighLine>> {
wakey_linux::devices::get_neighbors(machine_names, ips, devs, state, macs).await
}
pub async fn get_mac(
ip: Option<IpAddr>,
dev: Option<&str>,
state: &[NUDState],
) -> Result<Vec<IpNeighLine>> {
let ips: Vec<IpAddr> = ip.into_iter().collect();
let devs: Vec<&str> = dev.into_iter().collect();
get_macs(&[] as &[&str], &ips, &devs, state, &[]).await
}
-17
View File
@@ -1,17 +0,0 @@
pub mod dev {
pub use wakey_linux::devices::devs_sorted;
}
pub mod leases {
pub use wakey_linux::dhcp::enrich_leases_with_nud_state;
}
pub mod macs;
pub mod parser {
pub use wakey_core::QueryInput as QueryType;
pub async fn parse_query(q: String) -> QueryType {
wakey_linux::devices::classify_query(q).await
}
}
pub use leases::*;
pub use macs::*;
-6
View File
@@ -1,6 +0,0 @@
pub async fn wake_one(
sock: &tokio::net::UdpSocket,
t: wakey_linux::wake::CompleteWakeTarget,
) -> wakey_core::WakeTargetResult {
wakey_linux::wake::wake_one(sock, t).await
}