refactor(explorer+card): independencia jerarquica enforced
Cierra el unico debt estructural detectado en el audit de independencia: nouser-explorer ya no arrastra nouser-core (que aportaba notify/walkdir/sled/blake3 al grafo de compilacion de una UI que solo habla JSON contra un socket). - Cliente movido: engine_socket::client::list_monads (~60 LOC, std + serde_json puros) emigra de nouser_core::engine_socket a nouser_card::query::client. Vive donde viven los wire types, consistente con el principio "un consumer importa el contrato, no el runtime del productor". - Drop dep: nouser-explorer deja de depender de nouser-core. Verificado con cargo tree: notify, sled, blake3 desaparecen del grafo del binario. - Fallback "falla hacia la simplicidad": nueva resolve_socket() en el explorer intenta primero broker discovery; si el broker no responde / no hay init vivo, fallback directo al default_socket_path. El explorer queda funcional contra un daemon huerfano (standalone sin init) — completa "consciente cuando hay ecosistema, soberano cuando esta solo". - socket_source gana tercer estado "default-path" para visibilidad. Audit estructural confirmo que el resto del ecosistema ya respeta el principio. Brahman es pegamento opcional, no chasis obligatorio — y ahora el grafo de Cargo lo enforcea, no solo la convencion. Tests: 4 + 10 + 27 verdes. Cliente movido ejercitado end-to-end por los 3 tests integracion de engine_socket.
This commit is contained in:
@@ -151,6 +151,75 @@ pub mod transport {
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Cliente blocking — vive con los wire types para que un consumer
|
||||
// (UI, CLI, otro módulo) pueda hablar con el daemon importando sólo
|
||||
// `nouser-card`, sin arrastrar `nouser-core` (notify/walkdir/sled/blake3).
|
||||
// =====================================================================
|
||||
|
||||
/// Cliente síncrono para el query socket del daemon. Sólo Unix (el
|
||||
/// resto del ecosistema brahman es Unix-only de facto).
|
||||
#[cfg(unix)]
|
||||
pub mod client {
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::{ErrorResponse, ListMonadsResponse, QueryRequest};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum QueryError {
|
||||
#[error("conectar a {path}: {source}")]
|
||||
Connect {
|
||||
path: std::path::PathBuf,
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("I/O: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("serializacion: {0}")]
|
||||
Serde(#[from] serde_json::Error),
|
||||
#[error("daemon: {0}")]
|
||||
Daemon(String),
|
||||
#[error("response vacía del daemon")]
|
||||
Empty,
|
||||
}
|
||||
|
||||
/// Envía `ListMonads` al daemon en `socket` y devuelve la response.
|
||||
/// `timeout` se aplica tanto al read como al write del stream.
|
||||
pub fn list_monads(
|
||||
socket: &Path,
|
||||
timeout: Duration,
|
||||
) -> Result<ListMonadsResponse, QueryError> {
|
||||
let mut stream = UnixStream::connect(socket).map_err(|e| QueryError::Connect {
|
||||
path: socket.to_path_buf(),
|
||||
source: e,
|
||||
})?;
|
||||
stream.set_read_timeout(Some(timeout))?;
|
||||
stream.set_write_timeout(Some(timeout))?;
|
||||
|
||||
let req = QueryRequest::ListMonads;
|
||||
let line = serde_json::to_string(&req)?;
|
||||
stream.write_all(line.as_bytes())?;
|
||||
stream.write_all(b"\n")?;
|
||||
stream.flush()?;
|
||||
|
||||
let mut reader = BufReader::new(stream);
|
||||
let mut response = String::new();
|
||||
let n = reader.read_line(&mut response)?;
|
||||
if n == 0 {
|
||||
return Err(QueryError::Empty);
|
||||
}
|
||||
|
||||
if let Ok(resp) = serde_json::from_str::<ListMonadsResponse>(response.trim()) {
|
||||
return Ok(resp);
|
||||
}
|
||||
let err: ErrorResponse = serde_json::from_str(response.trim())?;
|
||||
Err(QueryError::Daemon(err.error))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user