lets GOOOOOOOO
This commit is contained in:
@@ -16,11 +16,14 @@ cw = "c --target=x86_64-pc-windows-msvc"
|
|||||||
bw = "b --target=x86_64-pc-windows-msvc"
|
bw = "b --target=x86_64-pc-windows-msvc"
|
||||||
tw = "t --target=x86_64-pc-windows-msvc"
|
tw = "t --target=x86_64-pc-windows-msvc"
|
||||||
|
|
||||||
|
|
||||||
check-all = "check --workspace --all-features --all-targets"
|
check-all = "check --workspace --all-features --all-targets"
|
||||||
clippy-all = "clippy --workspace --all-features --all-targets"
|
clippy-all = "clippy --workspace --all-features --all-targets"
|
||||||
|
test-all = "test --workspace --all-features --all-targets"
|
||||||
fmt-all = "fmt --all"
|
fmt-all = "fmt --all"
|
||||||
|
|
||||||
# idk below
|
# idk below
|
||||||
|
ldar = "r -qrp"
|
||||||
ldabr = "b -r --target=armv7-unknown-linux-musleabihf"
|
ldabr = "b -r --target=armv7-unknown-linux-musleabihf"
|
||||||
t = "test -- --nocapture --test-threads=1"
|
t = "test -- --nocapture --test-threads=1"
|
||||||
tdebug = "test -- --nocapture --test-threads=1 --show-output"
|
tdebug = "test -- --nocapture --test-threads=1 --show-output"
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ pub struct Cli {
|
|||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Show merged device inventory rows.
|
/// Show merged device inventory rows.
|
||||||
#[command(visible_alias = "status")]
|
#[command(visible_alias = "status", alias = "inv")]
|
||||||
Inventory(InventoryArgs),
|
Inventory(InventoryArgs),
|
||||||
/// Show DHCP leases, optionally enriched with current neighbor state.
|
/// Show DHCP leases, optionally enriched with current neighbor state.
|
||||||
Leases(LeasesArgs),
|
Leases(LeasesArgs),
|
||||||
|
|||||||
+3
-2
@@ -7,8 +7,9 @@ pub use wakey_linux;
|
|||||||
|
|
||||||
pub use service::{
|
pub use service::{
|
||||||
broadcast_wake_targets, get_interface_summaries, get_interface_summary, get_ips, get_leases,
|
broadcast_wake_targets, get_interface_summaries, get_interface_summary, get_ips, get_leases,
|
||||||
inventory, leases_without_state, merge_devices, resolve_devices, resolve_query,
|
inventory, leases_without_state, local_observation_to_fact, merge_devices,
|
||||||
resolve_selector, resolve_wake_targets, wake_explicit, wake_from_query, wake_targets,
|
merge_devices_with_observations, resolve_devices, resolve_query, resolve_selector,
|
||||||
|
resolve_wake_targets, wake_explicit, wake_from_query, wake_targets,
|
||||||
};
|
};
|
||||||
pub use wakey_linux::dhcp::{list_local_observations, observe_dhcp_event, observe_neighbor_event};
|
pub use wakey_linux::dhcp::{list_local_observations, observe_dhcp_event, observe_neighbor_event};
|
||||||
|
|
||||||
|
|||||||
+140
-10
@@ -1,7 +1,8 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use tracing::{debug, warn};
|
||||||
use wakey_core::{
|
use wakey_core::{
|
||||||
Device, DeviceInventory, DhcpLease, DhcpLeaseWithState, InventoryQuery, NeighborEntry,
|
Device, DeviceInventory, DeviceObservationFact, DhcpLease, DhcpLeaseWithState, InventoryQuery,
|
||||||
Presence, Query,
|
NeighborEntry, Presence, Query,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::service::leases::get_leases;
|
use crate::service::leases::get_leases;
|
||||||
@@ -24,9 +25,25 @@ pub async fn inventory(query: InventoryQuery) -> Result<DeviceInventory> {
|
|||||||
include_state: false,
|
include_state: false,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
Ok(DeviceInventory {
|
let observations = match wakey_linux::dhcp::list_local_observations().await {
|
||||||
devices: merge_devices(neighbors, leases, &query),
|
Ok(observations) => observations
|
||||||
})
|
.into_iter()
|
||||||
|
.filter_map(local_observation_to_fact)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(error = %err, "failed reading local hook observations for inventory");
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!(
|
||||||
|
neighbors = neighbors.len(),
|
||||||
|
leases = leases.len(),
|
||||||
|
observations = observations.len(),
|
||||||
|
"building device inventory"
|
||||||
|
);
|
||||||
|
let devices = merge_devices_with_observations(neighbors, leases, observations, &query);
|
||||||
|
debug!(devices = devices.len(), "merged device inventory");
|
||||||
|
Ok(DeviceInventory { devices })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge raw neighbor entries and DHCP leases into device aggregates.
|
/// Merge raw neighbor entries and DHCP leases into device aggregates.
|
||||||
@@ -37,26 +54,53 @@ pub fn merge_devices(
|
|||||||
neighbors: Vec<NeighborEntry>,
|
neighbors: Vec<NeighborEntry>,
|
||||||
leases: Vec<DhcpLeaseWithState>,
|
leases: Vec<DhcpLeaseWithState>,
|
||||||
query: &InventoryQuery,
|
query: &InventoryQuery,
|
||||||
|
) -> Vec<Device> {
|
||||||
|
merge_devices_with_observations(neighbors, leases, Vec::new(), query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge raw neighbor entries, DHCP leases, and hook observations into device
|
||||||
|
/// aggregates.
|
||||||
|
pub fn merge_devices_with_observations(
|
||||||
|
neighbors: Vec<NeighborEntry>,
|
||||||
|
leases: Vec<DhcpLeaseWithState>,
|
||||||
|
observations: Vec<DeviceObservationFact>,
|
||||||
|
query: &InventoryQuery,
|
||||||
) -> Vec<Device> {
|
) -> Vec<Device> {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
let mut by_mac: BTreeMap<String, (Vec<NeighborEntry>, Vec<DhcpLease>)> = BTreeMap::new();
|
type DeviceParts = (
|
||||||
|
Vec<NeighborEntry>,
|
||||||
|
Vec<DhcpLease>,
|
||||||
|
Vec<DeviceObservationFact>,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut by_key: BTreeMap<String, DeviceParts> = BTreeMap::new();
|
||||||
|
|
||||||
for row in neighbors {
|
for row in neighbors {
|
||||||
let key = row
|
let key = row
|
||||||
.mac
|
.mac
|
||||||
.map(|m| m.to_string())
|
.map(|m| m.to_string())
|
||||||
.unwrap_or_else(|| format!("ip:{}", row.ip));
|
.unwrap_or_else(|| format!("ip:{}", row.ip));
|
||||||
by_mac.entry(key).or_default().0.push(row);
|
by_key.entry(key).or_default().0.push(row);
|
||||||
}
|
}
|
||||||
for lease in leases {
|
for lease in leases {
|
||||||
let key = lease.lease_line.mac.to_string();
|
let key = lease.lease_line.mac.to_string();
|
||||||
by_mac.entry(key).or_default().1.push(lease.lease_line);
|
by_key.entry(key).or_default().1.push(lease.lease_line);
|
||||||
|
}
|
||||||
|
for observation in observations {
|
||||||
|
let key = observation
|
||||||
|
.mac
|
||||||
|
.map(|mac| mac.to_string())
|
||||||
|
.or_else(|| observation.ip.map(|ip| format!("ip:{ip}")))
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
by_key.entry(key).or_default().2.push(observation);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut devices: Vec<Device> = by_mac
|
let mut devices: Vec<Device> = by_key
|
||||||
.into_values()
|
.into_values()
|
||||||
.map(|(neighbors, leases)| Device::from_parts(neighbors, leases))
|
.map(|(neighbors, leases, observations)| {
|
||||||
|
Device::from_parts_with_observations(neighbors, leases, observations)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut texts = Vec::new();
|
let mut texts = Vec::new();
|
||||||
@@ -90,6 +134,42 @@ pub fn merge_devices(
|
|||||||
devices
|
devices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn local_observation_to_fact(
|
||||||
|
observation: wakey_linux::dhcp::LocalDeviceObservation,
|
||||||
|
) -> Option<DeviceObservationFact> {
|
||||||
|
let mac = match observation.mac.as_deref() {
|
||||||
|
Some(raw) => match raw.parse() {
|
||||||
|
Ok(mac) => Some(mac),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
mac = raw,
|
||||||
|
error = %err,
|
||||||
|
"ignoring invalid observed mac in inventory"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
if mac.is_none() && observation.ip.is_none() {
|
||||||
|
warn!(
|
||||||
|
kind = %observation.kind,
|
||||||
|
action = %observation.action,
|
||||||
|
"ignoring hook observation without mac or ip"
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(DeviceObservationFact {
|
||||||
|
kind: observation.kind,
|
||||||
|
action: observation.action,
|
||||||
|
mac,
|
||||||
|
ip: observation.ip,
|
||||||
|
hostname: observation.hostname,
|
||||||
|
first_seen_unix: Some(observation.first_seen_unix),
|
||||||
|
last_seen_unix: Some(observation.last_seen_unix),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const fn presence_rank(presence: Presence) -> u8 {
|
const fn presence_rank(presence: Presence) -> u8 {
|
||||||
match presence {
|
match presence {
|
||||||
Presence::Online => 3,
|
Presence::Online => 3,
|
||||||
@@ -175,4 +255,54 @@ mod tests {
|
|||||||
Some(DeviceId::Ip(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 20))))
|
Some(DeviceId::Ip(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 20))))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_devices_preserves_hook_observation_facts() {
|
||||||
|
let query = InventoryQueryBuilder::new().build();
|
||||||
|
let out = merge_devices_with_observations(
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
vec![DeviceObservationFact {
|
||||||
|
kind: "dhcp".into(),
|
||||||
|
action: "update".into(),
|
||||||
|
mac: Some("aa:bb:cc:dd:ee:ff".parse().expect("mac")),
|
||||||
|
ip: Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 30))),
|
||||||
|
hostname: Some("lda".into()),
|
||||||
|
first_seen_unix: Some(10),
|
||||||
|
last_seen_unix: Some(20),
|
||||||
|
}],
|
||||||
|
&query,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(out.len(), 1);
|
||||||
|
assert_eq!(out[0].names, vec!["lda".to_string()]);
|
||||||
|
assert_eq!(
|
||||||
|
out[0].id,
|
||||||
|
Some(DeviceId::Mac("aa:bb:cc:dd:ee:ff".parse().expect("mac")))
|
||||||
|
);
|
||||||
|
assert_eq!(out[0].observations.len(), 1);
|
||||||
|
assert_eq!(out[0].presence, Presence::Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn merge_devices_marks_remove_only_observation_offline() {
|
||||||
|
let query = InventoryQueryBuilder::new().build();
|
||||||
|
let out = merge_devices_with_observations(
|
||||||
|
Vec::new(),
|
||||||
|
Vec::new(),
|
||||||
|
vec![DeviceObservationFact {
|
||||||
|
kind: "neigh".into(),
|
||||||
|
action: "remove".into(),
|
||||||
|
mac: Some("aa:bb:cc:dd:ee:ff".parse().expect("mac")),
|
||||||
|
ip: Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 30))),
|
||||||
|
hostname: None,
|
||||||
|
first_seen_unix: Some(10),
|
||||||
|
last_seen_unix: Some(20),
|
||||||
|
}],
|
||||||
|
&query,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(out.len(), 1);
|
||||||
|
assert_eq!(out[0].presence, Presence::Offline);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -5,7 +5,10 @@ pub mod query;
|
|||||||
pub mod wake;
|
pub mod wake;
|
||||||
|
|
||||||
pub use interfaces::{get_interface_summaries, get_interface_summary, get_ips};
|
pub use interfaces::{get_interface_summaries, get_interface_summary, get_ips};
|
||||||
pub use inventory::{inventory, merge_devices, resolve_devices};
|
pub use inventory::{
|
||||||
|
inventory, local_observation_to_fact, merge_devices, merge_devices_with_observations,
|
||||||
|
resolve_devices,
|
||||||
|
};
|
||||||
pub use leases::{get_leases, leases_without_state};
|
pub use leases::{get_leases, leases_without_state};
|
||||||
pub use query::{resolve_query, resolve_selector};
|
pub use query::{resolve_query, resolve_selector};
|
||||||
pub use wake::{
|
pub use wake::{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tracing::{debug, info, instrument};
|
use tracing::{debug, info, instrument, warn};
|
||||||
|
|
||||||
use crate::config::AgentConfig;
|
use crate::config::AgentConfig;
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
@@ -70,8 +70,33 @@ async fn dispatch_inventory(req: InventoryRequest, config: &AgentConfig) -> Resu
|
|||||||
&config.mac_name_cache_path,
|
&config.mac_name_cache_path,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
let observations = match wakey::wakey_linux::dhcp::list_local_observations_from_path(
|
||||||
|
&config.observation_store_path,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(observations) => observations
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(wakey::local_observation_to_fact)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(error = %err, "failed reading local hook observations for inventory command");
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!(
|
||||||
|
neighbors = neighbors.len(),
|
||||||
|
leases = leases.len(),
|
||||||
|
observations = observations.len(),
|
||||||
|
"dispatching inventory with merged sources"
|
||||||
|
);
|
||||||
let inventory = wakey_core::DeviceInventory {
|
let inventory = wakey_core::DeviceInventory {
|
||||||
devices: wakey::merge_devices(neighbors, wakey::leases_without_state(leases), &query),
|
devices: wakey::merge_devices_with_observations(
|
||||||
|
neighbors,
|
||||||
|
wakey::leases_without_state(leases),
|
||||||
|
observations,
|
||||||
|
&query,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
debug!(
|
debug!(
|
||||||
rows = inventory.devices.len(),
|
rows = inventory.devices.len(),
|
||||||
|
|||||||
@@ -44,6 +44,24 @@ pub enum DeviceId {
|
|||||||
Ip(IpAddr),
|
Ip(IpAddr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// One raw source fact used while building a device aggregate.
|
||||||
|
///
|
||||||
|
/// These are intentionally source-shaped and non-durable. They preserve details
|
||||||
|
/// from hooks and live inventory so higher layers can explain why a device looks
|
||||||
|
/// online, stale, or unknown without reverse-engineering flattened fields.
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize)]
|
||||||
|
pub struct DeviceObservationFact {
|
||||||
|
pub kind: String,
|
||||||
|
pub action: String,
|
||||||
|
#[serde(with = "mac::option_mac")]
|
||||||
|
pub mac: Option<MacAddr>,
|
||||||
|
pub ip: Option<IpAddr>,
|
||||||
|
pub hostname: Option<String>,
|
||||||
|
pub first_seen_unix: Option<u64>,
|
||||||
|
pub last_seen_unix: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Merged view of one discovered network identity.
|
/// Merged view of one discovered network identity.
|
||||||
///
|
///
|
||||||
/// This aggregates facts from DHCP leases and neighbor-table rows into a more
|
/// This aggregates facts from DHCP leases and neighbor-table rows into a more
|
||||||
@@ -59,12 +77,22 @@ pub struct Device {
|
|||||||
pub interfaces: Vec<String>,
|
pub interfaces: Vec<String>,
|
||||||
pub neighbors: Vec<NeighborEntry>,
|
pub neighbors: Vec<NeighborEntry>,
|
||||||
pub leases: Vec<DhcpLease>,
|
pub leases: Vec<DhcpLease>,
|
||||||
|
pub observations: Vec<DeviceObservationFact>,
|
||||||
pub presence: Presence,
|
pub presence: Presence,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
/// Merge raw neighbor and DHCP facts into one device aggregate.
|
/// Merge raw neighbor and DHCP facts into one device aggregate.
|
||||||
pub fn from_parts(neighbors: Vec<NeighborEntry>, leases: Vec<DhcpLease>) -> Self {
|
pub fn from_parts(neighbors: Vec<NeighborEntry>, leases: Vec<DhcpLease>) -> Self {
|
||||||
|
Self::from_parts_with_observations(neighbors, leases, Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge raw neighbor, DHCP, and hook observation facts into one aggregate.
|
||||||
|
pub fn from_parts_with_observations(
|
||||||
|
neighbors: Vec<NeighborEntry>,
|
||||||
|
leases: Vec<DhcpLease>,
|
||||||
|
observations: Vec<DeviceObservationFact>,
|
||||||
|
) -> Self {
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
let mut names = BTreeSet::new();
|
let mut names = BTreeSet::new();
|
||||||
@@ -94,6 +122,34 @@ impl Device {
|
|||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
let mut observed_non_remove = false;
|
||||||
|
for observation in &observations {
|
||||||
|
if let Some(name) = observation.hostname.as_deref() {
|
||||||
|
names.insert(name);
|
||||||
|
}
|
||||||
|
if let Some(ip) = observation.ip {
|
||||||
|
ips.insert(ip);
|
||||||
|
}
|
||||||
|
if let Some(mac) = observation.mac {
|
||||||
|
macs.insert(mac);
|
||||||
|
}
|
||||||
|
if observation.action != "remove" {
|
||||||
|
observed_non_remove = true;
|
||||||
|
}
|
||||||
|
presence = std::cmp::max(
|
||||||
|
presence_rank(presence),
|
||||||
|
presence_rank(observation_presence(observation)),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
if neighbors.is_empty()
|
||||||
|
&& leases.is_empty()
|
||||||
|
&& !observed_non_remove
|
||||||
|
&& !observations.is_empty()
|
||||||
|
{
|
||||||
|
presence = Presence::Offline;
|
||||||
|
}
|
||||||
|
|
||||||
let macs: Vec<MacAddr> = macs.into_iter().collect();
|
let macs: Vec<MacAddr> = macs.into_iter().collect();
|
||||||
let ips: Vec<IpAddr> = ips.into_iter().collect();
|
let ips: Vec<IpAddr> = ips.into_iter().collect();
|
||||||
@@ -110,11 +166,20 @@ impl Device {
|
|||||||
interfaces: interfaces.into_iter().map(|d| d.to_owned()).collect(),
|
interfaces: interfaces.into_iter().map(|d| d.to_owned()).collect(),
|
||||||
neighbors,
|
neighbors,
|
||||||
leases,
|
leases,
|
||||||
|
observations,
|
||||||
presence,
|
presence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn observation_presence(observation: &DeviceObservationFact) -> Presence {
|
||||||
|
match (observation.kind.as_str(), observation.action.as_str()) {
|
||||||
|
(_, "remove") => Presence::Offline,
|
||||||
|
("neigh", "add" | "update" | "old") => Presence::LikelyOnline,
|
||||||
|
_ => Presence::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fn presence_rank(presence: Presence) -> u8 {
|
const fn presence_rank(presence: Presence) -> u8 {
|
||||||
match presence {
|
match presence {
|
||||||
Presence::Online => 3,
|
Presence::Online => 3,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ mod neighbor;
|
|||||||
mod query;
|
mod query;
|
||||||
mod wake;
|
mod wake;
|
||||||
|
|
||||||
pub use device::{Device, DeviceId, DeviceInventory, Presence};
|
pub use device::{Device, DeviceId, DeviceInventory, DeviceObservationFact, Presence};
|
||||||
pub use dhcp::{DhcpLease, DhcpLeaseWithState, LeaseQuery};
|
pub use dhcp::{DhcpLease, DhcpLeaseWithState, LeaseQuery};
|
||||||
pub use interface::{InterfaceAddr, InterfaceSummary};
|
pub use interface::{InterfaceAddr, InterfaceSummary};
|
||||||
pub use neighbor::{NeighborEntry, NeighborParseError, NeighborState, parse_neighbor_line};
|
pub use neighbor::{NeighborEntry, NeighborParseError, NeighborState, parse_neighbor_line};
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ mod observations;
|
|||||||
|
|
||||||
pub use leases::{
|
pub use leases::{
|
||||||
enrich_leases_with_nud_state, parse_dhcp_lease_line, read_dhcp_leases,
|
enrich_leases_with_nud_state, parse_dhcp_lease_line, read_dhcp_leases,
|
||||||
read_dhcp_leases_from_path, read_dhcp_leases_with_names, read_dhcp_leases_with_names_from_paths,
|
read_dhcp_leases_from_path, read_dhcp_leases_with_names,
|
||||||
|
read_dhcp_leases_with_names_from_paths,
|
||||||
};
|
};
|
||||||
pub use observations::{
|
pub use observations::{
|
||||||
LocalDeviceObservation, LocalObservationStore, ObservedDhcpClient, ObservedNeighbor,
|
LocalDeviceObservation, LocalObservationStore, ObservedDhcpClient, ObservedNeighbor,
|
||||||
@@ -22,7 +23,6 @@ const DHCP_LEASES_ENV: &str = "WAKEY_DHCP_LEASES";
|
|||||||
const MAC_NAME_CACHE_ENV: &str = "WAKEY_MAC_NAME_CACHE";
|
const MAC_NAME_CACHE_ENV: &str = "WAKEY_MAC_NAME_CACHE";
|
||||||
const OBSERVATION_STORE_ENV: &str = "WAKEY_OBSERVATION_STORE";
|
const OBSERVATION_STORE_ENV: &str = "WAKEY_OBSERVATION_STORE";
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn now_unix() -> u64 {
|
pub(crate) fn now_unix() -> u64 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
|||||||
@@ -99,19 +99,19 @@ async fn save_observation_store(store: &LocalObservationStore) -> io::Result<()>
|
|||||||
|
|
||||||
pub async fn list_local_observations() -> io::Result<Vec<LocalDeviceObservation>> {
|
pub async fn list_local_observations() -> io::Result<Vec<LocalDeviceObservation>> {
|
||||||
let store = load_observation_store().await?;
|
let store = load_observation_store().await?;
|
||||||
list_local_observations_from_store(store)
|
Ok(list_local_observations_from_store(store))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_local_observations_from_path(
|
pub async fn list_local_observations_from_path(
|
||||||
path: impl AsRef<std::path::Path>,
|
path: impl AsRef<std::path::Path>,
|
||||||
) -> io::Result<Vec<LocalDeviceObservation>> {
|
) -> io::Result<Vec<LocalDeviceObservation>> {
|
||||||
let store = load_observation_store_from_path(path).await?;
|
let store = load_observation_store_from_path(path).await?;
|
||||||
list_local_observations_from_store(store)
|
Ok(list_local_observations_from_store(store))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_local_observations_from_store(
|
fn list_local_observations_from_store(
|
||||||
store: LocalObservationStore,
|
store: LocalObservationStore,
|
||||||
) -> io::Result<Vec<LocalDeviceObservation>> {
|
) -> Vec<LocalDeviceObservation> {
|
||||||
let mut out = Vec::with_capacity(store.dhcp_clients.len() + store.neighbors.len());
|
let mut out = Vec::with_capacity(store.dhcp_clients.len() + store.neighbors.len());
|
||||||
out.extend(
|
out.extend(
|
||||||
store
|
store
|
||||||
@@ -148,7 +148,7 @@ fn list_local_observations_from_store(
|
|||||||
.then(a.mac.cmp(&b.mac))
|
.then(a.mac.cmp(&b.mac))
|
||||||
.then(a.ip.cmp(&b.ip))
|
.then(a.ip.cmp(&b.ip))
|
||||||
});
|
});
|
||||||
Ok(out)
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Observe a DHCP hotplug event and update the local MAC-to-name cache.
|
/// Observe a DHCP hotplug event and update the local MAC-to-name cache.
|
||||||
|
|||||||
Reference in New Issue
Block a user