mirror of
https://github.com/ruvnet/RuView
synced 2026-08-08 20:11:43 +00:00
f49c722764
The Rust port lived two directories deep (rust-port/wifi-densepose-rs/) without any sibling under rust-port/ that warranted the extra level. Move the whole workspace up to v2/ to match v1/ (Python) at the same depth and shorten every cd / build command across the repo. git mv preserves history for all tracked files. 60 files updated for path references (CI workflows, ADRs, docs, scripts, READMEs, internal .claude-flow state). Two manual fixes for relative-cd paths in CLAUDE.md and ADR-043 that became wrong after the depth change (cd ../.. → cd ..). Validated: - cargo check --workspace --no-default-features → clean (after target/ nuke; the gitignored target/ was carried by the OS rename and had hard-coded old paths in build scripts) - cargo test --workspace --no-default-features → 1,539 passed, 0 failed, 8 ignored (same totals as pre-rename) - ESP32-S3 on COM7 → still streaming live CSI (cb #40300, RSSI -64 dBm) After-merge follow-up: contributors should `rm -rf v2/target` once and let cargo regenerate from the new path.
134 lines
3.1 KiB
Rust
134 lines
3.1 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
/// MAC address value object (e.g., "AA:BB:CC:DD:EE:FF").
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
pub struct MacAddress(pub String);
|
|
|
|
impl MacAddress {
|
|
pub fn new(addr: impl Into<String>) -> Self {
|
|
Self(addr.into())
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for MacAddress {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
/// Node health status.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum HealthStatus {
|
|
Online,
|
|
Offline,
|
|
Degraded,
|
|
}
|
|
|
|
impl Default for HealthStatus {
|
|
fn default() -> Self {
|
|
Self::Offline
|
|
}
|
|
}
|
|
|
|
/// Chip type for ESP32 variants.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum Chip {
|
|
#[default]
|
|
Esp32,
|
|
Esp32s2,
|
|
Esp32s3,
|
|
Esp32c3,
|
|
Esp32c6,
|
|
}
|
|
|
|
/// Node role in the mesh network.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum MeshRole {
|
|
Coordinator,
|
|
#[default]
|
|
Node,
|
|
Aggregator,
|
|
}
|
|
|
|
/// Discovery method used to find the node.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum DiscoveryMethod {
|
|
#[default]
|
|
Mdns,
|
|
UdpProbe,
|
|
HttpSweep,
|
|
Manual,
|
|
}
|
|
|
|
/// Node capabilities.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct NodeCapabilities {
|
|
pub wasm: bool,
|
|
pub ota: bool,
|
|
pub csi: bool,
|
|
}
|
|
|
|
/// A discovered ESP32 CSI node.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct DiscoveredNode {
|
|
pub ip: String,
|
|
pub mac: Option<String>,
|
|
pub hostname: Option<String>,
|
|
pub node_id: u8,
|
|
pub firmware_version: Option<String>,
|
|
pub health: HealthStatus,
|
|
pub last_seen: String,
|
|
// Extended fields
|
|
pub chip: Chip,
|
|
pub mesh_role: MeshRole,
|
|
pub discovery_method: DiscoveryMethod,
|
|
pub tdm_slot: Option<u8>,
|
|
pub tdm_total: Option<u8>,
|
|
pub edge_tier: Option<u8>,
|
|
pub uptime_secs: Option<u64>,
|
|
pub capabilities: Option<NodeCapabilities>,
|
|
pub friendly_name: Option<String>,
|
|
pub notes: Option<String>,
|
|
}
|
|
|
|
/// Aggregate root: maintains the set of all known nodes, keyed by MAC.
|
|
#[derive(Debug, Default)]
|
|
pub struct NodeRegistry {
|
|
nodes: std::collections::HashMap<MacAddress, DiscoveredNode>,
|
|
}
|
|
|
|
impl NodeRegistry {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
/// Insert or update a node. Deduplicates by MAC address.
|
|
pub fn upsert(&mut self, mac: MacAddress, node: DiscoveredNode) {
|
|
self.nodes.insert(mac, node);
|
|
}
|
|
|
|
/// Get a node by MAC address.
|
|
pub fn get(&self, mac: &MacAddress) -> Option<&DiscoveredNode> {
|
|
self.nodes.get(mac)
|
|
}
|
|
|
|
/// List all known nodes.
|
|
pub fn all(&self) -> Vec<&DiscoveredNode> {
|
|
self.nodes.values().collect()
|
|
}
|
|
|
|
/// Number of registered nodes.
|
|
pub fn len(&self) -> usize {
|
|
self.nodes.len()
|
|
}
|
|
|
|
/// Whether the registry is empty.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.nodes.is_empty()
|
|
}
|
|
}
|