Files
arje/crates/ente-zero/src/graph/devices.rs
T
Sergio d6b8f18b43 Pausa: 11 crates del fractal Ente #0 con cerebro completo
PID 1 boot + bus interno autenticado + cerebro KCL/Rust:
- 6 lib crates de infra (card, bus, cas, kernel, soma, wasm, snapshot)
- ente-brain: motor de reglas O(1), observer Shannon, cristalización,
  audit hash-chain, persistencia rules.k, Prometheus /metrics
- KCL schemas card.k + rule.k como gramática autoritativa
- compat-logind D-Bus, ente-echo demo provider, ente-zero PID 1
- 22 tests OK, ~3.8k LOC Rust + ~300 LOC KCL

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 22:57:44 +00:00

61 lines
2.5 KiB
Rust

//! Device registry: mantiene el índice de dispositivos del kernel presentes,
//! traduce uevents en cambios de `Capability::Device { class }`.
use super::EnteGraph;
use crate::events::GraphEvent;
use ente_card::{Capability, DeviceClass};
use ente_kernel::{UAction, UEvent};
use tokio::sync::mpsc;
use tracing::{debug, info, warn};
impl EnteGraph {
pub async fn on_uevent(&mut self, evt: UEvent, _tx: &mpsc::Sender<GraphEvent>) {
let class = match &evt.device_class {
Some(c) => c.clone(),
None => return, // subsystems sin DeviceClass mapeada — ignoramos.
};
match evt.action {
UAction::Add | UAction::Bind | UAction::Online => {
let was_first = self.devices_of_class(&class) == 0;
self.devices.insert(evt.devpath.clone(), evt.clone());
if was_first {
// Primera instancia de la clase → la registramos como
// capacidad disponible. El "proveedor" virtual es el
// Ente #0 (kernel surface).
let cap = Capability::Device { class: class.clone() };
self.providers.entry(cap).or_default().insert(self.seed.id);
info!(?class, devpath = %evt.devpath, "device capability disponible");
}
}
UAction::Remove | UAction::Unbind | UAction::Offline => {
self.devices.remove(&evt.devpath);
if self.devices_of_class(&class) == 0 {
let cap = Capability::Device { class: class.clone() };
if let Some(set) = self.providers.get_mut(&cap) {
set.remove(&self.seed.id);
}
let revoked: Vec<u64> = self.grants.iter()
.filter(|(_, g)| g.cap == cap)
.map(|(t, _)| *t)
.collect();
for t in revoked {
self.grants.remove(&t);
}
warn!(?class, "última instancia removida — capacidad revocada");
}
}
UAction::Change | UAction::Move => {
self.devices.insert(evt.devpath.clone(), evt);
debug!(?class, "device modified");
}
UAction::Unknown => {}
}
}
fn devices_of_class(&self, class: &DeviceClass) -> usize {
self.devices.values()
.filter(|e| e.device_class.as_ref() == Some(class))
.count()
}
}