im not sure what im changing

This commit is contained in:
lda
2025-11-02 01:14:28 +07:00 Unverified
parent e2d33a0db6
commit 6405bb5bf7
16 changed files with 128 additions and 95 deletions
Generated
+1
View File
@@ -632,6 +632,7 @@ dependencies = [
"rtnetlink", "rtnetlink",
"serde", "serde",
"serde_json", "serde_json",
"serde_with",
"strum", "strum",
"thiserror 2.0.16", "thiserror 2.0.16",
"tokio", "tokio",
+1
View File
@@ -9,6 +9,7 @@ macaddr = { version = "1.0.1", features = ["serde", "serde_std"] }
strum = { version = "0.27.2", features = ["derive", "strum_macros"] } strum = { version = "0.27.2", features = ["derive", "strum_macros"] }
serde_json = "1.0.143" serde_json = "1.0.143"
serde = { version = "1.0.219", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
serde_with = { version = "3.14.0", features = ["json"] }
thiserror = "2.0.16" thiserror = "2.0.16"
anyhow = "1.0.100" anyhow = "1.0.100"
tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread", "io-util", "macros"] } tokio = { version = "1.47.1", features = ["fs", "process", "rt-multi-thread", "io-util", "macros"] }
+2 -2
View File
@@ -1,13 +1,13 @@
//! low //! low
//! //!
//! # lda-ipj //! # lda-ipjs
//! //!
//! this package will represent all my needs with the all the subcommands of ip -j. //! this package will represent all my needs with the all the subcommands of ip -j.
//! //!
//! ## what i need //! ## what i need
//! //!
//! ```console //! ```console
//! ip -j neigh //! ip -j neigh show
//! ``` //! ```
//! //!
//! i also need to see devices and idk MAYBE maybe not MAYBE UHHHHHH maybe broadcast //! i also need to see devices and idk MAYBE maybe not MAYBE UHHHHHH maybe broadcast
+28
View File
@@ -0,0 +1,28 @@
// ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]
// [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]
// [ label LABEL ] [up] [ vrf NAME ] ]
// fuck is this mean
// do i need all this? do i need anything but `ip -j a show dev br-lan`?
// TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |
// gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan | vti |
// nlmon | can | bond_slave | ipvlan | geneve | bridge_slave |
// hsr | macsec | netdevsim }
// FLAG-LIST := [ FLAG-LIST ] FLAG
// FLAG := [ permanent | dynamic | secondary | primary |
// [-]tentative | [-]deprecated | [-]dadfailed | temporary |
// CONFFLAG-LIST ]
// CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG
// CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]
// prefix seems to be a cidr. both 6 and 4 works. idfk dog
use super::AddrInfo;
pub async fn get() -> Vec<AddrInfo> {
todo!()
}
+21 -22
View File
@@ -4,39 +4,38 @@
//! //!
//! lowk why its free but its indirection and its ass //! lowk why its free but its indirection and its ass
use macaddr::MacAddr6; pub mod json;
use crate::utils::serialize::mac::option_mac;
use macaddr::MacAddr;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// i dont include what i dont know about (almost all ts) /// i dont include what i dont know about (almost all ts)
#[derive(Debug, Serialize, Deserialize)]
struct CommmonOutput {
ifindex: u32,
ifname: String,
/// i imagine UP or DOWN, unknown
operstate: String,
// 6 has a serde and the enum doesnt? why.
address: Option<MacAddr6>,
}
#[derive(Serialize, Debug, Deserialize)] #[derive(Serialize, Debug, Deserialize)]
struct AddrOutput { pub struct AddrOutput {
#[serde(flatten)] pub ifindex: u32,
c: CommmonOutput, pub ifname: String,
addr_info: Vec<AddrInfo>, /// i imagine UP or DOWN, unknown
pub operstate: String,
// 6 has a serde and the enum doesnt? why. (serializing ts is ass although... im not given an array. they string formatted ts)
#[serde(with = "option_mac", default)]
pub address: Option<MacAddr>,
#[serde(default)] // i wish we have intellisense for this... fuck you metaprogramming
pub addr_info: Vec<AddrInfo>,
} }
// i be copying // i be copying
// Raw JSON shape from ip -j -4 address show // Raw JSON shape from ip -j -4 address show
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
struct AddrInfo { pub struct AddrInfo {
family: Option<String>, pub family: Option<String>,
local: Option<String>, pub local: Option<String>,
prefixlen: Option<u8>, pub prefixlen: Option<u8>,
broadcast: Option<String>, pub broadcast: Option<String>,
scope: Option<String>, pub scope: Option<String>,
label: Option<String>, pub label: Option<String>,
// many more exist; we only take what we need // many more exist; we only take what we need
} }
+11 -14
View File
@@ -7,7 +7,7 @@
pub mod json; pub mod json;
pub mod nl; pub mod nl;
use crate::utils::serialize::mac::{des_opm, ser_opm}; use crate::utils::serialize::mac::option_mac;
use std::net::IpAddr; use std::net::IpAddr;
use macaddr::MacAddr; use macaddr::MacAddr;
@@ -17,11 +17,11 @@ use strum::{Display, EnumString};
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct NeighborInput { pub struct NeighborInput {
/// supports only the last item (ignore), `to` keyword is optional /// supports only the last item (ignore), `to` keyword is optional
to: Option<IpAddr>, pub to: Option<IpAddr>,
/// supports only one item (it complains if multiple) /// supports only one item (it complains if multiple)
dev: Option<String>, // im all for simplicity pub dev: Option<String>, // im all for simplicity
/// takes multiple, has to have `nud` before bro or it will think you `to` /// takes multiple, has to have `nud` before bro or it will think you `to`
nud: Vec<NUDState>, pub nud: Vec<NUDState>,
} }
// as input this must be lowercase. as output it is uppercase // as input this must be lowercase. as output it is uppercase
@@ -64,21 +64,18 @@ pub enum NUDState {
/// success, neighbor validation has ultimately /// success, neighbor validation has ultimately
/// failed. /// failed.
Failed, Failed,
Other(u16)
} }
/// everything i see /// everything i see
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
pub struct NeighborItem { pub struct NeighborItem {
#[serde(rename(deserialize = "dst"))] #[serde(rename(deserialize = "dst"))]
ip: IpAddr, pub ip: IpAddr,
dev: String, pub dev: String,
#[serde( #[serde(with = "option_mac", default, rename(deserialize = "lladdr"))]
deserialize_with = "des_opm", pub mac: Option<MacAddr>,
serialize_with = "ser_opm",
default,
rename(deserialize = "lladdr")
)]
mac: Option<MacAddr>,
#[serde(default)] #[serde(default)]
state: Vec<NUDState>, pub state: Vec<NUDState>,
} }
+1 -1
View File
@@ -134,7 +134,7 @@ impl TryFrom<NeighbourState> for NUDState {
NeighbourState::Noarp => Ok(Self::Noarp), NeighbourState::Noarp => Ok(Self::Noarp),
NeighbourState::Permanent => Ok(Self::Permanent), NeighbourState::Permanent => Ok(Self::Permanent),
NeighbourState::None => Ok(Self::None), NeighbourState::None => Ok(Self::None),
NeighbourState::Other(e) => Err(e), NeighbourState::Other(e) => Ok(Self::Other(e)),
_ => Err(u16::MAX), // idk _ => Err(u16::MAX), // idk
} }
} }
+18 -16
View File
@@ -11,7 +11,7 @@ where
} }
/// Serialize a MacAddr as a string /// Serialize a MacAddr as a string
pub fn serialize_mac<S>(mac: &MacAddr, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S>(mac: &MacAddr, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
{ {
@@ -19,7 +19,7 @@ where
} }
/// Deserialize a MacAddr from a string /// Deserialize a MacAddr from a string
pub fn deserialize_mac<'de, D>(deserializer: D) -> Result<MacAddr, D::Error> pub fn deserialize<'de, D>(deserializer: D) -> Result<MacAddr, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@@ -27,18 +27,20 @@ where
s.parse::<MacAddr>().map_err(DeError::custom) s.parse::<MacAddr>().map_err(DeError::custom)
} }
/// serialize an [`Option<MacAddr>`] pub mod option_mac {
pub fn ser_opm<S: Serializer>(bro: &Option<MacAddr>, ser: S) -> Result<S::Ok, S::Error> { use super::*;
Option::<String>::serialize(&bro.as_ref().map(ToString::to_string), ser) /// serialize an [`Option<MacAddr>`]
} pub fn serialize<S: Serializer>(bro: &Option<MacAddr>, ser: S) -> Result<S::Ok, S::Error> {
Option::<String>::serialize(&bro.as_ref().map(ToString::to_string), ser)
/// deserialize an [`Option<MacAddr>`] }
pub fn des_opm<'de, D>(des: D) -> Result<Option<MacAddr>, D::Error> /// deserialize an [`Option<MacAddr>`]
where pub fn deserialize<'de, D>(des: D) -> Result<Option<MacAddr>, D::Error>
D: serde::Deserializer<'de>, where
{ D: serde::Deserializer<'de>,
Option::<&str>::deserialize(des)? {
.map(str::parse) Option::<&str>::deserialize(des)?
.transpose() .map(str::parse)
.map_err(de::Error::custom) .transpose()
.map_err(de::Error::custom)
}
} }
+9 -5
View File
@@ -41,7 +41,7 @@ pub struct IpNeighLine {
// NUDState custom Deserialize now lives in arpparse/impl.rs; use serde_with OneOrMany for Vec // NUDState custom Deserialize now lives in arpparse/impl.rs; use serde_with OneOrMany for Vec
#[derive(Debug, PartialEq, Eq, EnumString, Display, Clone, Copy, Hash, serde::Serialize)] #[derive(Debug, PartialEq, Eq, EnumString, Display, Clone, Copy, Hash, serde::Serialize, Default)]
#[strum(serialize_all = "UPPERCASE", ascii_case_insensitive)] #[strum(serialize_all = "UPPERCASE", ascii_case_insensitive)]
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub enum NUDState { pub enum NUDState {
@@ -63,10 +63,7 @@ pub enum NUDState {
/// neighbour state if it was valid and the /// neighbour state if it was valid and the
/// address is not changed by this command. /// address is not changed by this command.
Stale, Stale,
/// this is a pseudo state used when initially
/// creating a neighbour entry or after trying to
/// remove it before it becomes free to do so.
None,
/// the neighbour entry has not (yet) been /// the neighbour entry has not (yet) been
/// validated/resolved. /// validated/resolved.
@@ -80,6 +77,13 @@ pub enum NUDState {
/// success, neighbor validation has ultimately /// success, neighbor validation has ultimately
/// failed. /// failed.
Failed, Failed,
/// this is a pseudo state used when initially
/// creating a neighbour entry or after trying to
/// remove it before it becomes free to do so.
#[serde(other)]
#[default]
None,
} }
impl NUDState { impl NUDState {
+5 -12
View File
@@ -49,12 +49,10 @@ pub async fn status_smart_redirect(
}; };
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}"))),
Err(e) => Err(( Err(e) => Err(ApiError {
StatusCode::BAD_GATEWAY, error: e.to_string(),
Json(ApiError { code: StatusCode::BAD_GATEWAY,
error: e.to_string(), }),
}),
)),
} }
} }
@@ -67,12 +65,7 @@ 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( get_ips(&name).await.map_or_else(
|e| { |e| ApiError::ise(e.to_string()).into_response(),
ApiError {
error: e.to_string(),
}
.into_response()
},
|ips| Json(ips.collect::<Vec<_>>()).into_response(), |ips| Json(ips.collect::<Vec<_>>()).into_response(),
) )
} }
+5 -7
View File
@@ -26,12 +26,10 @@ pub async fn get_dhcp_leases(Query(raw): Query<DhcpLeasesQueryRaw>) -> impl Into
let out = enrich_leases_with_nud_state(leases_with_names).await; let out = enrich_leases_with_nud_state(leases_with_names).await;
(StatusCode::OK, Json(out)).into_response() (StatusCode::OK, Json(out)).into_response()
} }
Err(e) => ( Err(e) => ApiError {
StatusCode::BAD_GATEWAY, error: e.to_string(),
Json(ApiError { code: StatusCode::BAD_GATEWAY,
error: e.to_string(), }
}), .into_response(),
)
.into_response(),
} }
} }
+13 -1
View File
@@ -7,11 +7,23 @@ use serde::Serialize;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct ApiError { pub struct ApiError {
#[serde(skip_serializing, skip_deserializing)]
pub code: StatusCode,
pub error: String, pub error: String,
} }
impl ApiError {
/// [StatusCode::INTERNAL_SERVER_ERROR]
pub const fn ise(error: String) -> Self {
Self {
code: StatusCode::INTERNAL_SERVER_ERROR,
error,
}
}
}
impl IntoResponse for ApiError { impl IntoResponse for ApiError {
fn into_response(self) -> Response { fn into_response(self) -> Response {
(StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response() (self.code, Json(self)).into_response()
} }
} }
+5 -7
View File
@@ -94,13 +94,11 @@ pub async fn get_status_json(
) )
.into_response() .into_response()
} }
Err(error) => ( Err(error) => ApiError {
StatusCode::BAD_GATEWAY, code: StatusCode::BAD_GATEWAY,
Json(ApiError { error: error.to_string(),
error: error.to_string(), }
}), .into_response(),
)
.into_response(),
} }
} }
// Status endpoints // Status endpoints
+1 -1
View File
@@ -48,7 +48,7 @@ pub async fn get_macs(
let ip_m: HashSet<IpAddr> = futures::future::try_join_all( let ip_m: HashSet<IpAddr> = futures::future::try_join_all(
machine_names machine_names
.iter() .iter()
.map(|c| async { get_ips(c.as_ref()).await }), .map(|c| get_ips(c.as_ref())),
) )
.await? .await?
.into_iter() .into_iter()
+2 -2
View File
@@ -41,13 +41,13 @@ impl From<WakeTargetResult> for RouteWakeResult {
} }
impl RouteWakeTarget { impl RouteWakeTarget {
pub fn to_incomplete(self) -> RouteWakeResult { pub const fn to_incomplete(self) -> RouteWakeResult {
RouteWakeResult { RouteWakeResult {
target: self, target: self,
status: RouteWakeStatus::Incomplete, status: RouteWakeStatus::Incomplete,
} }
} }
pub fn is_incomplete(&self) -> bool { pub const fn is_incomplete(&self) -> bool {
!matches!( !matches!(
self, self,
Self { Self {
+5 -5
View File
@@ -22,21 +22,21 @@ pub enum WakeStatus {
WrongSize, WrongSize,
} }
impl WakeTarget { impl WakeTarget {
fn _new(ip: IpAddr, mac: MacAddr) -> Self { const fn _new(ip: IpAddr, mac: MacAddr) -> Self {
Self { ip, mac } Self { ip, mac }
} }
fn good(self) -> WakeTargetResult { const fn good(self) -> WakeTargetResult {
WakeTargetResult::new(self, WakeStatus::Success) WakeTargetResult::new(self, WakeStatus::Success)
} }
fn bad(self) -> WakeTargetResult { const fn bad(self) -> WakeTargetResult {
WakeTargetResult::new(self, WakeStatus::WrongSize) WakeTargetResult::new(self, WakeStatus::WrongSize)
} }
fn errored(self) -> WakeTargetResult { const fn errored(self) -> WakeTargetResult {
WakeTargetResult::new(self, WakeStatus::NonexistentAddress) WakeTargetResult::new(self, WakeStatus::NonexistentAddress)
} }
} }
impl WakeTargetResult { impl WakeTargetResult {
fn new(target: WakeTarget, status: WakeStatus) -> Self { const fn new(target: WakeTarget, status: WakeStatus) -> Self {
Self { target, status } Self { target, status }
} }
} }