this shit works yo

This commit is contained in:
lda
2026-04-04 08:22:42 +07:00 Unverified
parent 4bb8fa161d
commit f483a8507a
13 changed files with 482 additions and 186 deletions
Generated
+115
View File
@@ -26,6 +26,56 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anstream"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.100" version = "1.0.100"
@@ -206,6 +256,46 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "clap"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]] [[package]]
name = "color-eyre" name = "color-eyre"
version = "0.6.5" version = "0.6.5"
@@ -233,6 +323,12 @@ dependencies = [
"tracing-error", "tracing-error",
] ]
[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.7" version = "0.8.7"
@@ -603,6 +699,12 @@ dependencies = [
"serde_core", "serde_core",
] ]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.17" version = "1.0.17"
@@ -800,6 +902,12 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]] [[package]]
name = "owo-colors" name = "owo-colors"
version = "4.2.3" version = "4.2.3"
@@ -1369,6 +1477,12 @@ version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.1" version = "0.1.1"
@@ -1382,6 +1496,7 @@ dependencies = [
"anyhow", "anyhow",
"axum", "axum",
"axum-extra", "axum-extra",
"clap",
"color-eyre", "color-eyre",
"futures", "futures",
"lda-ipjs", "lda-ipjs",
+1
View File
@@ -8,6 +8,7 @@ publish = ["gitea"]
anyhow = "1" anyhow = "1"
axum = { version = "0", features = ["macros"] } axum = { version = "0", features = ["macros"] }
axum-extra = { version = "0", features = ["query"] } axum-extra = { version = "0", features = ["query"] }
clap = { version = "4", features = ["derive"] }
color-eyre = "0" color-eyre = "0"
futures = "0" futures = "0"
macaddr = { version = "1", features = ["serde", "serde_std"] } macaddr = { version = "1", features = ["serde", "serde_std"] }
+2
View File
@@ -17,6 +17,8 @@ try { $PSStyle.OutputRendering = 'Host' } catch {}
. "$PSScriptRoot/lib.ps1" . "$PSScriptRoot/lib.ps1"
$Pass = Get-DefaultPassword $Pass
function Get-DeployScript { function Get-DeployScript {
param($DeployPreferred, $DeployTmp, $RemoteTmp, $RemotePath, $RestartFlag) param($DeployPreferred, $DeployTmp, $RemoteTmp, $RemotePath, $RestartFlag)
return @" return @"
+1 -1
View File
@@ -9,7 +9,7 @@ BIN=/root/.bin/wakey
start_service() { start_service() {
procd_open_instance procd_open_instance
procd_set_param command "$BIN" procd_set_param command "$BIN" http --host :: --port 12012
procd_set_param respawn 5 1 0 procd_set_param respawn 5 1 0
procd_set_param stdout 1 procd_set_param stdout 1
procd_set_param stderr 1 procd_set_param stderr 1
+15
View File
@@ -1,5 +1,20 @@
# Shared functions for wakey scripts # Shared functions for wakey scripts
function Get-DefaultPassword {
param([string]$Password)
if ($Password) {
return $Password
}
$pwPath = Join-Path (Split-Path -Parent $PSScriptRoot) 'ar_data/pw'
if (-not (Test-Path $pwPath)) {
throw "Password not provided and default file not found: $pwPath"
}
return (Get-Content -Raw $pwPath).Trim()
}
function Invoke-Ext { function Invoke-Ext {
param($Exe, $Arguments, $Label) param($Exe, $Arguments, $Label)
$displayArgs = $Arguments.Clone() $displayArgs = $Arguments.Clone()
+2
View File
@@ -16,6 +16,8 @@ $ErrorActionPreference = "Stop"
. "$PSScriptRoot/lib.ps1" . "$PSScriptRoot/lib.ps1"
$password = Get-DefaultPassword $password
# Build tests and capture output # Build tests and capture output
Write-Host "Building tests for $Package..." -ForegroundColor Cyan Write-Host "Building tests for $Package..." -ForegroundColor Cyan
+205
View File
@@ -0,0 +1,205 @@
pub mod arpparse;
pub mod dhcpparse;
pub mod route;
pub mod utils;
use std::{io, net::SocketAddr};
use anyhow::{Context, Result};
use axum::Router;
use tokio::net::TcpListener;
use tower_http::services::ServeDir;
use wakey_core::{
DeviceFilters, DeviceQuery, DhcpLease, DhcpLeaseWithState, NeighborEntry, QueryInput, Status,
WakeResult, WakeTarget,
};
pub type StatusResponse = Status<NeighborEntry>;
pub async fn resolve_query(input: impl Into<String>) -> Result<DeviceQuery> {
Ok(match wakey_linux::devices::classify_query(input.into()).await {
QueryInput::Ip(ip_addr) => DeviceQuery {
filter: DeviceFilters {
ips: vec![ip_addr],
..Default::default()
},
..Default::default()
},
QueryInput::Mac(mac_addr) => DeviceQuery {
filter: DeviceFilters {
macs: vec![mac_addr],
..Default::default()
},
..Default::default()
},
QueryInput::Dev(dev) => DeviceQuery {
filter: DeviceFilters {
devs: vec![dev],
..Default::default()
},
..Default::default()
},
QueryInput::Nud(state) => DeviceQuery {
filter: DeviceFilters {
nuds: vec![state],
..Default::default()
},
..Default::default()
},
QueryInput::Name(name) => DeviceQuery {
name: Some(name),
..Default::default()
},
})
}
pub async fn get_status(query: DeviceQuery) -> Result<StatusResponse> {
let table = wakey_linux::devices::query_status(&query).await?;
Ok(Status {
name: query.name,
table,
filters: query.filter,
})
}
pub async fn get_status_for_input(input: impl Into<String>) -> Result<StatusResponse> {
let query = resolve_query(input).await?;
get_status(query).await
}
pub async fn get_leases(include_state: bool) -> Result<Vec<DhcpLeaseWithState>> {
let leases = wakey_linux::dhcp::read_dhcp_leases_with_names()
.await
.context("failed to read DHCP leases")?;
if include_state {
Ok(wakey_linux::dhcp::enrich_leases_with_nud_state(leases).await)
} else {
Ok(leases
.into_iter()
.map(|lease_line| DhcpLeaseWithState {
lease_line,
nud_state: None,
})
.collect())
}
}
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")?;
Ok(WakeResult { result })
}
pub async fn wake_from_query(input: impl Into<String>) -> Result<WakeResult> {
let status = get_status_for_input(input).await?;
let targets = status
.table
.into_iter()
.map(|entry| WakeTarget {
ip: Some(entry.ip),
mac: entry.mac,
})
.collect();
wake_targets(targets).await
}
pub async fn list_interfaces() -> Result<Vec<String>> {
Ok(wakey_linux::devices::devs_sorted().await)
}
pub async fn get_ips(name: impl AsRef<str>) -> Result<Vec<std::net::IpAddr>> {
Ok(wakey_linux::devices::get_ips(name.as_ref())
.await?
.collect())
}
pub fn http_app(static_root: std::path::PathBuf) -> Router {
Router::new()
.nest("/api", route::api_router())
.fallback_service(
axum::routing::get_service(
ServeDir::new(static_root)
.append_index_html_on_directories(true)
.precompressed_br()
.precompressed_deflate()
.precompressed_gzip()
.precompressed_zstd(),
),
)
}
pub async fn serve_http(addr: SocketAddr, static_root: std::path::PathBuf) -> io::Result<()> {
let listener = TcpListener::bind(addr).await?;
axum::serve(listener, http_app(static_root).into_make_service()).await
}
pub async fn serve_http_from_current_exe(addr: SocketAddr) -> io::Result<()> {
let exe = std::env::current_exe()?;
let root = exe
.parent()
.ok_or_else(|| io::Error::other("no parent dir"))?;
serve_http(addr, root.join("static")).await
}
pub fn leases_without_state(leases: Vec<DhcpLease>) -> Vec<DhcpLeaseWithState> {
leases
.into_iter()
.map(|lease_line| DhcpLeaseWithState {
lease_line,
nud_state: None,
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{IpAddr, Ipv4Addr};
use wakey_core::{NeighborState, WakeStatus};
#[tokio::test]
async fn resolve_query_parses_ip() {
let query = resolve_query("192.168.1.10").await.expect("resolve query");
assert_eq!(query.filter.ips, vec![IpAddr::V4(Ipv4Addr::new(192, 168, 1, 10))]);
}
#[tokio::test]
async fn resolve_query_parses_mac() {
let query = resolve_query("aa:bb:cc:dd:ee:ff")
.await
.expect("resolve query");
assert_eq!(query.filter.macs.len(), 1);
}
#[tokio::test]
async fn resolve_query_parses_nud() {
let query = resolve_query("reachable").await.expect("resolve query");
assert_eq!(query.filter.nuds, vec![NeighborState::Reachable]);
}
#[test]
fn leases_without_state_clears_nud_state() {
let leases = vec![DhcpLease {
expires_epoch: 1,
ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
mac: "aa:bb:cc:dd:ee:ff".parse().expect("mac"),
name: Some("pc".into()),
}];
let out = leases_without_state(leases);
assert_eq!(out.len(), 1);
assert!(out[0].nud_state.is_none());
}
#[tokio::test]
async fn wake_targets_marks_incomplete() {
let out = wake_targets(vec![WakeTarget {
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
mac: None,
}])
.await
.expect("wake");
assert_eq!(out.result.len(), 1);
assert_eq!(out.result[0].status, WakeStatus::Incomplete);
}
}
+114 -53
View File
@@ -1,65 +1,126 @@
//! braindead version v0.1.x use std::net::{IpAddr, SocketAddr};
//!
//! # whats next
//!
//! for version 2 i hope to have:
//!
//! 1. idk reworked frontend;
//! 2. incorporate ip -j;
//! 3. small 1-5 second caching;
use axum::Router; use clap::{Args, Parser, Subcommand};
use tokio::net::TcpListener; use wakey_core::{DeviceFilters, DeviceQuery};
mod arpparse;
mod dhcpparse;
mod route;
mod utils;
use std::{env, io};
#[cfg(target_os = "linux")] #[derive(Parser)]
#[tokio::main] #[command(name = "wakey")]
async fn entry() -> io::Result<()> { #[command(version, about = "Wakey service CLI and HTTP adapter")]
use crate::route::api_router; struct Cli {
use axum::routing::get_service; #[command(subcommand)]
use tower_http::services::ServeDir; command: Command,
let exe = env::current_exe()?; }
let root = exe
.parent()
.ok_or_else(|| io::Error::other("no parent dir"))?;
let static_dir = ServeDir::new(root.join("static"))
.append_index_html_on_directories(true)
.precompressed_br()
.precompressed_deflate()
.precompressed_gzip()
.precompressed_zstd();
let app = Router::new()
// .route("/home", get(home))
// .route("/", get(home_2))
// .merge(home_2_route())
// .route("/status", get(get_status_2))
.nest("/api", api_router())
.fallback_service(get_service(static_dir));
let port = TcpListener::bind("[::]:12012").await?; #[derive(Subcommand)]
axum::serve(port, app.into_make_service()).await?; enum Command {
Ok(()) Http(HttpArgs),
Status(StatusArgs),
Leases(LeasesArgs),
Wake(WakeArgs),
Devs,
}
#[derive(Args)]
struct HttpArgs {
#[arg(long, default_value = "::")]
host: IpAddr,
#[arg(long, default_value_t = 12012)]
port: u16,
}
#[derive(Args)]
struct LeasesArgs {
#[arg(long)]
include_state: bool,
}
#[derive(Args)]
struct WakeArgs {
query: String,
}
#[derive(Args)]
struct StatusArgs {
query: Option<String>,
#[arg(long)]
name: Option<String>,
#[arg(long = "ip")]
ips: Vec<std::net::IpAddr>,
#[arg(long = "dev")]
devs: Vec<String>,
#[arg(long = "nud")]
nuds: Vec<wakey_core::NeighborState>,
#[arg(long = "mac")]
macs: Vec<macaddr::MacAddr>,
}
fn status_args_to_query(args: StatusArgs) -> wakey_core::DeviceQuery {
if let Some(query) = args.query.as_ref()
&& args.name.is_none()
&& args.ips.is_empty()
&& args.devs.is_empty()
&& args.nuds.is_empty()
&& args.macs.is_empty()
{
return DeviceQuery {
name: Some(query.clone()),
..Default::default()
};
}
DeviceQuery {
name: args.name.or(args.query),
filter: DeviceFilters {
ips: args.ips,
devs: args.devs,
nuds: args.nuds,
macs: args.macs,
},
}
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn main() -> color_eyre::Result<()> { fn main() -> anyhow::Result<()> {
use std::net::ToSocketAddrs; Err(anyhow::anyhow!(
color_eyre::install()?;
// use crate::arpparse::NUDState;
// println!("{}", NUDState::Reachable.to_string().to_lowercase());
println!("{:?}", "svuhuvshdv:331".to_socket_addrs());
// Err(Os { code: 11001, kind: Uncategorized, message: "No such host is known." })
Err(color_eyre::eyre::eyre!(
"OS not supported! run this on your ahh router!" "OS not supported! run this on your ahh router!"
)) ))
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn main() -> color_eyre::Result<()> { #[tokio::main]
color_eyre::install()?; async fn main() -> anyhow::Result<()> {
Ok(entry()?) let cli = Cli::parse();
match cli.command {
Command::Http(args) => {
let addr = SocketAddr::new(args.host, args.port);
wakey::serve_http_from_current_exe(addr).await?;
}
Command::Status(args) => {
let query = status_args_to_query(args);
let status = if query.name.is_some()
&& query.filter.ips.is_empty()
&& query.filter.devs.is_empty()
&& query.filter.nuds.is_empty()
&& query.filter.macs.is_empty()
{
wakey::get_status_for_input(query.name.clone().unwrap_or_default()).await?
} else {
wakey::get_status(query).await?
};
println!("{}", serde_json::to_string_pretty(&status)?);
}
Command::Leases(args) => {
let leases = wakey::get_leases(args.include_state).await?;
println!("{}", serde_json::to_string_pretty(&leases)?);
}
Command::Wake(args) => {
let result = wakey::wake_from_query(args.query).await?;
println!("{}", serde_json::to_string_pretty(&result)?);
}
Command::Devs => {
let devs = wakey::list_interfaces().await?;
println!("{}", serde_json::to_string_pretty(&devs)?);
}
}
Ok(())
} }
+11 -39
View File
@@ -1,52 +1,24 @@
use crate::route::error::ApiError; use crate::route::error::ApiError;
use crate::utils::query::parser::{QueryType, parse_query};
use axum::Json; use axum::Json;
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::{extract::Path, response::Redirect}; use axum::{extract::Path, response::Redirect};
use wakey_core::{DeviceFilters as Filters, DeviceQuery}; use wakey_core::DeviceQuery;
use crate::route::status::NamePath; use crate::route::status::NamePath;
use crate::utils::query::get_ips;
// Smart redirect: accept IP, MAC, dev, or NUD state and redirect to /api/status accordingly // Smart redirect: accept IP, MAC, dev, or NUD state and redirect to /api/status accordingly
pub async fn status_smart_redirect( pub async fn status_smart_redirect(
Path(q): Path<String>, Path(q): Path<String>,
) -> axum::response::Result<Redirect, impl IntoResponse> { ) -> axum::response::Result<Redirect, impl IntoResponse> {
// no less bullshit let query: DeviceQuery = match crate::resolve_query(q).await {
let query = match parse_query(q).await { Ok(query) => query,
QueryType::Ip(ip_addr) => DeviceQuery { Err(e) => {
filter: Filters { return Err(ApiError {
ips: vec![ip_addr], error: e.to_string(),
..Default::default() code: StatusCode::BAD_GATEWAY,
}, });
..Default::default() }
},
QueryType::Mac(mac_addr) => DeviceQuery {
filter: Filters {
macs: vec![mac_addr],
..Default::default()
},
..Default::default()
},
QueryType::Dev(s) => DeviceQuery {
filter: Filters {
devs: vec![s],
..Default::default()
},
..Default::default()
},
QueryType::Nud(nudstate) => DeviceQuery {
filter: Filters {
nuds: vec![nudstate],
..Default::default()
},
..Default::default()
},
QueryType::Name(n) => DeviceQuery {
name: Some(n),
..Default::default()
},
}; };
match serde_html_form::to_string(query) { match serde_html_form::to_string(query) {
Ok(e) => Ok(Redirect::to(&format!("/api/status?{e}"))), Ok(e) => Ok(Redirect::to(&format!("/api/status?{e}"))),
@@ -65,8 +37,8 @@ pub async fn status_redirect(Path(NamePath { name }): Path<NamePath>) -> Redirec
} }
pub async fn ip(Path(name): Path<String>) -> impl IntoResponse { pub async fn ip(Path(name): Path<String>) -> impl IntoResponse {
get_ips(&name).await.map_or_else( crate::get_ips(&name).await.map_or_else(
|e| ApiError::ise(e.to_string()).into_response(), |e| ApiError::ise(e.to_string()).into_response(),
|ips| Json(ips.collect::<Vec<_>>()).into_response(), |ips| Json(ips).into_response(),
) )
} }
+7 -4
View File
@@ -1,7 +1,10 @@
use crate::utils::query::dev; use crate::route::error::ApiError;
use axum::Json; use axum::{Json, response::IntoResponse};
pub async fn devs_router() -> Json<Vec<String>> { pub async fn devs_router() -> impl IntoResponse {
dev::devs_sorted().await.into() match crate::list_interfaces().await {
Ok(devs) => Json(devs).into_response(),
Err(e) => ApiError::ise(e.to_string()).into_response(),
}
} }
// Device listing endpoints // Device listing endpoints
+3 -13
View File
@@ -1,8 +1,4 @@
use crate::{ use crate::{route::error::ApiError, utils::parse::boolish_str};
dhcpparse::read_dhcp_leases_with_names,
route::error::ApiError,
utils::{parse::boolish_str, query::enrich_leases_with_nud_state},
};
use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse}; use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
// DHCP lease endpoints // DHCP lease endpoints
@@ -16,14 +12,8 @@ pub async fn get_dhcp_leases(
) -> impl IntoResponse { ) -> impl IntoResponse {
let include_state = include_state.as_deref().map(boolish_str).unwrap_or(false); let include_state = include_state.as_deref().map(boolish_str).unwrap_or(false);
match read_dhcp_leases_with_names().await { match crate::get_leases(include_state).await {
Ok(leases_with_names) => { Ok(leases) => (StatusCode::OK, Json(leases)).into_response(),
if !include_state {
return (StatusCode::OK, Json(leases_with_names)).into_response();
}
let out = enrich_leases_with_nud_state(leases_with_names).await;
(StatusCode::OK, Json(out)).into_response()
}
Err(e) => ApiError { Err(e) => ApiError {
error: e.to_string(), error: e.to_string(),
code: StatusCode::BAD_GATEWAY, code: StatusCode::BAD_GATEWAY,
+3 -26
View File
@@ -1,34 +1,11 @@
use crate::route::error::ApiError; use crate::route::error::ApiError;
use crate::utils::query::get_macs;
use axum::{Json, http::StatusCode, response::IntoResponse}; use axum::{Json, http::StatusCode, response::IntoResponse};
use axum_extra::extract::Query; use axum_extra::extract::Query;
pub use wakey_core::{DeviceQuery, NamePath, Status}; pub use wakey_core::{DeviceQuery, NamePath, Status};
pub async fn get_status_json( pub async fn get_status_json(Query(query): Query<DeviceQuery>) -> impl IntoResponse {
Query(DeviceQuery { match crate::get_status(query).await {
name, Ok(status) => (StatusCode::OK, Json(status)).into_response(),
filter: filters,
..
}): Query<DeviceQuery>,
) -> impl IntoResponse {
match get_macs(
name.as_slice(),
&filters.ips,
&filters.devs,
&filters.nuds,
&filters.macs,
)
.await
{
Ok(table) => (
StatusCode::OK,
Json(Status {
name,
table,
filters,
}),
)
.into_response(),
Err(error) => ApiError { Err(error) => ApiError {
code: StatusCode::BAD_GATEWAY, code: StatusCode::BAD_GATEWAY,
error: error error: error
+3 -50
View File
@@ -1,60 +1,13 @@
//! impls are at [`utils::wake::impl`](crate::utils::wake::r#impl) for some reason
use std::io;
/* use crate::arpparse::IpNeighLine;
use crate::route::api::Status; */
use crate::route::error::ApiError; use crate::route::error::ApiError;
use crate::utils::wake::wake_one;
use axum::{extract::Json, http::StatusCode, response::IntoResponse}; use axum::{extract::Json, http::StatusCode, response::IntoResponse};
use futures::TryFutureExt; pub use wakey_core::{WakeResult, WakeTarget};
use tokio::net::UdpSocket;
pub use wakey_core::{WakeResult, WakeTarget, WakeTargetResult};
pub async fn wake_multi(Json(req): Json<Vec<WakeTarget>>) -> impl IntoResponse { pub async fn wake_multi(Json(req): Json<Vec<WakeTarget>>) -> impl IntoResponse {
match wake_multi_split(req).await { match crate::wake_targets(req).await {
Ok(result) => (StatusCode::OK, Json(WakeResult { result })).into_response(), Ok(result) => (StatusCode::OK, Json(result)).into_response(),
Err(error) => { Err(error) => {
let error = format!("Error: {}", error); let error = format!("Error: {}", error);
ApiError::ise(error).into_response() ApiError::ise(error).into_response()
} }
} }
} }
/// this is so bad
pub async fn wake_multi_split(
targets: impl IntoIterator<Item = WakeTarget>,
) -> io::Result<Vec<WakeTargetResult>> {
let sock = UdpSocket::bind("[::]:0")
.or_else(|_| UdpSocket::bind(":0"))
.await?;
sock.set_broadcast(true)?;
let iter = targets.into_iter().map(async |c| {
if !c.is_complete() {
WakeTargetResult::incomplete(c)
} else {
let t = c.try_into().expect("complete struct failed to try_into");
wake_one(&sock, t).await
}
});
Ok(futures::future::join_all(iter).await)
}
/* #[derive(Debug, Serialize)]
pub struct WakeStatusLine {
#[serde(flatten)]
pub status: IpNeighLine, // most powerful find of the century
pub wake_status: WakeTargetStatus,
}
pub type WakeStatus = Status<WakeStatusLine>; */
// /// return status BUT plus a indicator of i sent a wake.
// pub async fn wake_status(
// Query(DeviceQuery {
// name,
// ip,
// dev,
// nud,
// mac,
// ..
// }): Query<DeviceQuery>,
// ) -> impl IntoResponse {
// }