ts some minor update HOPEFULLY wont make it run 16k times worse HOPEFULLY

This commit is contained in:
lda
2026-04-15 03:26:26 +07:00 Unverified
parent 5fbe4b9d61
commit f59fd7a846
13 changed files with 96 additions and 77 deletions
+31
View File
@@ -15,6 +15,7 @@
# WAKEY_CC_VERSION Bundle version label (default: v0.0.0-local-<short_sha>)
# WAKEY_CC_NO_RESTART If set, skip systemd restart
# WAKEY_CC_KEEP_TMP If set, keep temp checkout/build dir for debugging
# SUDO Privilege escalation command/path (default: sudo when needed)
#
# Requires: git, cargo, tar, pnpm, systemctl (optional for restart)
@@ -45,12 +46,31 @@ require_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
sudo_cmd() {
if [ "$(id -u)" -eq 0 ]; then
return 0
fi
if [ -n "${SUDO:-}" ]; then
printf '%s' "$SUDO"
return 0
fi
if command -v sudo >/dev/null 2>&1; then
printf '%s' sudo
return 0
fi
fail 'root privileges are required for install/restart steps; set SUDO or run as root'
}
main() {
REPO_URL="${WAKEY_CC_REPO_URL:-https://git.ldlda.com/lda/wakey.git}"
REF="${WAKEY_CC_REF:-main}"
TARGET="${WAKEY_CC_TARGET:-$(default_target)}"
ROOT="${WAKEY_CC_ROOT:-$PWD}"
SERVICE="${WAKEY_CC_SERVICE:-wakey-cc.service}"
SUDO_BIN=$(sudo_cmd)
require_cmd git
require_cmd cargo
@@ -104,15 +124,26 @@ main() {
[ -f "$STAGING/bin/wakey-control-plane" ] || fail 'bundle missing bin/wakey-control-plane'
[ -f "$STAGING/ui/dist/index.html" ] || fail 'bundle missing ui/dist/index.html'
if [ "$(id -u)" -ne 0 ] && [ -n "$SUDO_BIN" ]; then
$SUDO_BIN mkdir -p "$ROOT"
$SUDO_BIN cp -a "$STAGING/." "$ROOT/"
else
mkdir -p "$ROOT"
cp -a "$STAGING/." "$ROOT/"
fi
if [ -z "${WAKEY_CC_NO_RESTART:-}" ] && command -v systemctl >/dev/null 2>&1; then
if systemctl list-unit-files "$SERVICE" >/dev/null 2>&1; then
log "restarting $SERVICE"
if [ "$(id -u)" -ne 0 ] && [ -n "$SUDO_BIN" ]; then
$SUDO_BIN systemctl daemon-reload
$SUDO_BIN systemctl restart "$SERVICE"
$SUDO_BIN systemctl --no-pager --full status "$SERVICE" | sed -n '1,16p'
else
systemctl daemon-reload
systemctl restart "$SERVICE"
systemctl --no-pager --full status "$SERVICE" | sed -n '1,16p'
fi
else
log "service $SERVICE not installed; skipped restart"
fi
+2 -3
View File
@@ -3,9 +3,8 @@ pub mod utils;
pub use service::{
broadcast_wake_targets, get_interface_summaries, get_interface_summary, get_ips, get_leases,
inventory, leases_without_state, merge_devices, query_to_inventory_query, resolve_devices,
resolve_query, resolve_selector, resolve_wake_targets, wake_explicit, wake_from_query,
wake_targets,
inventory, leases_without_state, merge_devices, resolve_devices, resolve_query,
resolve_selector, resolve_wake_targets, wake_explicit, wake_from_query, wake_targets,
};
#[cfg(test)]
+18 -35
View File
@@ -1,3 +1,5 @@
use std::collections::HashSet;
use anyhow::Result;
use wakey_core::{
Device, DeviceInventory, DhcpLease, DhcpLeaseWithState, InventoryQuery, NeighborEntry,
@@ -59,48 +61,29 @@ pub fn merge_devices(
.map(|(neighbors, leases)| Device::from_parts(neighbors, leases))
.collect();
let mut texts: Vec<&str> = Vec::new();
let mut devs: Vec<&str> = Vec::new();
let mut ips = Vec::new();
let mut macs = Vec::new();
let mut nuds = Vec::new();
let mut texts = HashSet::new();
let mut devs = HashSet::new();
let mut ips = HashSet::new();
let mut macs = HashSet::new();
let mut nuds = HashSet::new();
for term in query {
match term {
Query::Text(v) => texts.push(v.as_str()),
Query::Interface(v) => devs.push(v.as_str()),
Query::Ip(v) => ips.push(*v),
Query::Mac(v) => macs.push(*v),
Query::NeighborState(v) => nuds.push(*v),
}
Query::Text(v) => texts.insert(v.as_str()),
Query::Interface(v) => devs.insert(v.as_str()),
Query::Ip(v) => ips.insert(*v),
Query::Mac(v) => macs.insert(*v),
Query::NeighborState(v) => nuds.insert(*v),
};
}
if !texts.is_empty() {
devices.retain(|device| device.names.iter().any(|n| texts.iter().any(|t| n == t)));
}
if !devs.is_empty() {
devices.retain(|device| {
device
.interfaces
.iter()
.any(|iface| devs.iter().any(|d| iface == d))
(texts.is_empty() || device.names.iter().any(|n| texts.contains(n.as_str())))
&& (devs.is_empty() || device.interfaces.iter().any(|i| devs.contains(i.as_str())))
&& (ips.is_empty() || device.ips.iter().any(|ip| ips.contains(ip)))
&& (macs.is_empty() || device.macs.iter().any(|mac| macs.contains(mac)))
&& (nuds.is_empty() || device.neighbors.iter().any(|n| nuds.contains(&n.state)))
});
}
if !ips.is_empty() {
devices.retain(|device| device.ips.iter().any(|ip| ips.contains(ip)));
}
if !macs.is_empty() {
devices.retain(|device| device.macs.iter().any(|mac| macs.contains(mac)));
}
if !nuds.is_empty() {
devices.retain(|device| {
device
.neighbors
.iter()
.any(|neighbor| nuds.contains(&neighbor.state))
});
}
devices.sort_by(|a, b| {
presence_rank(b.presence)
.cmp(&presence_rank(a.presence))
+1 -1
View File
@@ -7,7 +7,7 @@ pub mod wake;
pub use interfaces::{get_interface_summaries, get_interface_summary, get_ips};
pub use inventory::{inventory, merge_devices, resolve_devices};
pub use leases::{get_leases, leases_without_state};
pub use query::{query_to_inventory_query, resolve_query, resolve_selector};
pub use query::{resolve_query, resolve_selector};
pub use wake::{
broadcast_wake_targets, resolve_wake_targets, wake_explicit, wake_from_query, wake_targets,
};
+1 -12
View File
@@ -2,11 +2,8 @@ use anyhow::Result;
use wakey_core::{InventoryQuery, Query, QueryInput};
/// Resolve free-form user input into an `InventoryQuery` filter shape.
///
/// This is the compatibility entrypoint used by CLI and HTTP paths that still
/// speak in terms of query/filter payloads.
pub async fn resolve_query(input: impl Into<String>) -> Result<InventoryQuery> {
query_to_inventory_query(resolve_selector(input).await?)
Ok(vec![resolve_selector(input).await?])
}
/// Classify one piece of free-form user input into a typed selector.
@@ -24,11 +21,3 @@ pub async fn resolve_selector(input: impl Into<String>) -> Result<Query> {
},
)
}
/// Convert the newer selector-oriented `Query` model into an `InventoryQuery`.
///
/// This keeps the old filter-based service and HTTP surfaces working while the
/// internals migrate toward selector- and device-oriented APIs.
pub fn query_to_inventory_query(query: Query) -> Result<InventoryQuery> {
Ok(vec![query])
}
+9 -7
View File
@@ -6,6 +6,7 @@ use wakey_core::{InterfaceSummary, WakeResult, WakeTarget};
use crate::service::interfaces::get_interface_summaries;
use crate::service::inventory::resolve_devices;
use crate::utils::product;
/// Send Wake-on-LAN packets for already-concrete wake targets.
#[instrument(skip_all, fields(targets = targets.len()))]
@@ -50,14 +51,15 @@ pub async fn wake_explicit(mac: MacAddr, ip: Option<IpAddr>) -> Result<WakeResul
#[instrument(skip_all)]
pub async fn resolve_wake_targets(input: impl Into<String>) -> Result<Vec<WakeTarget>> {
let devices = resolve_devices(input).await?;
let targets: Vec<WakeTarget> = devices
.into_iter()
.flat_map(|device| {
let mac = device.macs.first().copied();
device
.ips
.into_iter()
.map(move |ip| WakeTarget { ip: Some(ip), mac })
// TRY EVERYTHING some has to work
product(device.ips, device.macs).map(|(i, m)| WakeTarget {
ip: Some(i),
mac: Some(m),
})
})
.collect();
debug!(targets = targets.len(), "resolved wake targets");
@@ -79,8 +81,8 @@ fn broadcast_wake_targets_from_interfaces(
.iter()
.flat_map(|iface| iface.addrs.iter())
.filter_map(|addr| addr.broadcast)
.map(|ip| WakeTarget {
ip: Some(IpAddr::V4(ip)),
.map(|br| WakeTarget {
ip: Some(IpAddr::V4(br)), // some will hit eventually AHHH logic
mac: Some(mac),
})
.collect();
+15 -1
View File
@@ -1 +1,15 @@
// Intentionally left empty.
//! rare fns that belong nowhere
/// absolute dih cheese
/// took some inspo from itertools
pub fn product<A, B, T1, T2>(i1: T1, i2: T2) -> impl Iterator<Item = (A, B)>
where
A: Clone,
T1: IntoIterator<Item = A>,
T2: IntoIterator<Item = B>,
T2::IntoIter: Clone,
{
let i2 = i2.into_iter();
i1.into_iter()
.flat_map(move |i1i| i2.clone().map(move |i2i| (i1i.clone(), i2i)))
}
+1 -1
View File
@@ -109,7 +109,7 @@ fn init_config(args: InitConfigArgs) -> Result<()> {
let cfg = config::AgentConfig {
server_url: args
.server_url
.unwrap_or_else(|| "https://control-plane.example.com".to_string()),
.unwrap_or_else(|| "https://wakey.ldlda.com".to_string()),
agent_id: args
.agent_id
.unwrap_or_else(|| "REPLACE_ME_AGENT_ID".to_string()),
+1 -1
View File
@@ -36,7 +36,7 @@ async fn run_once(config: &AgentConfig) -> Result<()> {
.unwrap_or_default()
);
let span = info_span!("agent_session", session_id = %session_id, agent_id = %config.agent_id);
let _span_guard = span.enter();
let _span_guard = span.enter(); // the ENTIRETY of below is agent_session.
let ws_url = websocket_url(&config.server_url)?;
info!(%ws_url, agent_id = %config.agent_id, "connecting agent websocket");
+1 -1
View File
@@ -18,7 +18,7 @@ pub struct Store {
agent_meta: sled::Tree,
audit_events: sled::Tree,
active_alerts: sled::Tree,
alert_transitions: sled::Tree,
alert_transitions: sled::Tree, // Where are them Types!
}
const SCHEMA_VERSION_KEY: &[u8] = b"schema_version";
+6 -6
View File
@@ -71,8 +71,8 @@ impl Device {
for lease in &leases {
ips.insert(lease.ip);
macs.insert(lease.mac);
if let Some(name) = &lease.name {
names.insert(name.clone());
if let Some(name) = lease.name.as_deref() {
names.insert(name);
}
}
for neighbor in &neighbors {
@@ -80,8 +80,8 @@ impl Device {
if let Some(mac) = neighbor.mac {
macs.insert(mac);
}
if let Some(dev) = &neighbor.dev {
interfaces.insert(dev.clone());
if let Some(dev) = neighbor.dev.as_deref() {
interfaces.insert(dev);
}
presence = std::cmp::max(
presence_rank(presence),
@@ -93,10 +93,10 @@ impl Device {
let macs: Vec<MacAddr> = macs.into_iter().collect();
Self {
id: macs.first().copied().map(|mac| DeviceId { mac }),
names: names.into_iter().collect(),
names: names.into_iter().map(|n| n.to_owned()).collect(),
ips: ips.into_iter().collect(),
macs,
interfaces: interfaces.into_iter().collect(),
interfaces: interfaces.into_iter().map(|d| d.to_owned()).collect(),
neighbors,
leases,
presence,
+1 -1
View File
@@ -50,7 +50,7 @@ pub struct WakeTargetResult {
#[serde(rename_all = "snake_case")]
pub enum WakeStatus {
Succeed,
NonexistentAddress,
NonexistentAddress, // how do i know this isnt some other errors? what!
WrongSize,
Incomplete,
}
+2 -1
View File
@@ -13,7 +13,7 @@ use wakey_core::{InterfaceAddr, InterfaceSummary};
/// Loopback is intentionally excluded.
pub async fn list_interface_summaries() -> Result<Vec<InterfaceSummary>> {
#[cfg(unix)]
let rows = address::nl::get(None)
let rows = address::nl::get(None) // <- why not do filtering here
.await
.context("rtnetlink address query failed")?;
@@ -22,6 +22,7 @@ pub async fn list_interface_summaries() -> Result<Vec<InterfaceSummary>> {
.await
.context("ip -j address show failed")?;
// convert semi raw [AddrOutput] into Almost the same [InterfaceSummary]
let mut out: Vec<InterfaceSummary> = rows
.into_iter()
.filter(|row| row.ifname != "lo")