27603c906d
brahman-net corre un único Kademlia para todo el ecosistema. brahman-dht le pone arriba un esquema de claves namespaced para que distintos dominios coexistan sin colisión en la misma malla. - key — RecordKind (Code/Card/Persona/Service/Custom) + DhtKey. Wire: [kind_tag] ++ blake3(id) = 33 bytes longitud fija. Custom(n) usa 0x80|n: nunca choca con los kinds estándar. - Dht — wrapper sobre BrahmanNet: announce/withdraw/find (modelo de provider records). Consumidores: minga (Code), brahman-card-discovery (Card), agorapura (Persona). 5 tests verdes (incl. smoke async sobre un nodo libp2p real). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
73 lines
2.2 KiB
Rust
73 lines
2.2 KiB
Rust
//! `brahman-dht` — capa de discovery typed sobre el Kademlia compartido.
|
|
//!
|
|
//! `brahman-net` corre un único Kademlia para todo el ecosistema. Este
|
|
//! crate le pone arriba un esquema de claves namespaced ([`DhtKey`]):
|
|
//! `minga` publica bloques de código, `brahman-card-discovery` publica
|
|
//! Cards, `agorapura` publica Personas — todo sobre la misma malla sin
|
|
//! colisión, porque cada clave lleva un byte de `kind`.
|
|
//!
|
|
//! El modelo es de **provider records**: un nodo `announce`-a que provee
|
|
//! una clave; otros `find`-an quién la provee y abren un stream directo.
|
|
|
|
#![forbid(unsafe_code)]
|
|
|
|
pub mod key;
|
|
|
|
pub use key::{DhtKey, RecordKind, DHT_KEY_LEN};
|
|
|
|
use brahman_net::BrahmanNet;
|
|
use libp2p::PeerId;
|
|
use std::sync::Arc;
|
|
|
|
/// Discovery typed sobre `brahman-net`.
|
|
#[derive(Clone)]
|
|
pub struct Dht {
|
|
net: Arc<BrahmanNet>,
|
|
}
|
|
|
|
impl Dht {
|
|
/// Crea la capa DHT sobre un nodo `brahman-net` ya inicializado.
|
|
pub fn new(net: Arc<BrahmanNet>) -> Self {
|
|
Self { net }
|
|
}
|
|
|
|
/// Anuncia que este nodo provee `key`. El registro de provider se
|
|
/// renueva solo mientras el nodo siga vivo en la malla.
|
|
pub fn announce(&self, key: &DhtKey) {
|
|
self.net.start_providing(&key.to_bytes());
|
|
}
|
|
|
|
/// Retira el anuncio de `key`.
|
|
pub fn withdraw(&self, key: &DhtKey) {
|
|
self.net.stop_providing(&key.to_bytes());
|
|
}
|
|
|
|
/// Busca los peers que proveen `key`.
|
|
pub async fn find(&self, key: &DhtKey) -> Vec<PeerId> {
|
|
self.net.find_providers(&key.to_bytes()).await
|
|
}
|
|
|
|
/// El nodo `brahman-net` subyacente (para abrir streams a un provider).
|
|
pub fn net(&self) -> &Arc<BrahmanNet> {
|
|
&self.net
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn announce_find_withdraw_on_a_live_node() {
|
|
// Smoke: un nodo solo. `find` de una clave que nadie provee
|
|
// devuelve vacío; announce/withdraw no panickean.
|
|
let net = Arc::new(BrahmanNet::new().expect("nodo libp2p"));
|
|
let dht = Dht::new(net);
|
|
let key = DhtKey::card("modulo-inexistente");
|
|
dht.announce(&key);
|
|
dht.withdraw(&key);
|
|
let found = dht.find(&DhtKey::card("nadie-lo-provee")).await;
|
|
assert!(found.is_empty());
|
|
}
|
|
}
|