mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 08:14:42 +00:00
Add Unix domain control socket for runtime observability
Add a Unix domain socket interface for querying node state at runtime. A spawned tokio task accepts connections and communicates with the main event loop via mpsc/oneshot channels, keeping all Node access single-threaded. Includes: - src/control/ module with socket lifecycle, JSON protocol, and 11 query handlers (status, peers, links, tree, sessions, bloom, mmp, cache, connections, transports, routing) - Separate fipsctl binary for CLI queries (fipsctl show <command>) - ControlConfig in node configuration (enabled, socket_path) - Integration into the main select! event loop
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
//! RX event loop and packet dispatch.
|
||||
|
||||
use crate::control::ControlSocket;
|
||||
use crate::control::queries;
|
||||
use crate::node::{Node, NodeError};
|
||||
use crate::transport::ReceivedPacket;
|
||||
use crate::node::wire::{CommonPrefix, PHASE_ESTABLISHED, PHASE_MSG1, PHASE_MSG2, FMP_VERSION, COMMON_PREFIX_SIZE};
|
||||
use std::time::Duration;
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
impl Node {
|
||||
/// Run the receive event loop.
|
||||
@@ -53,6 +55,28 @@ impl Node {
|
||||
|
||||
let mut tick = tokio::time::interval(Duration::from_secs(self.config.node.tick_interval_secs));
|
||||
|
||||
// Set up control socket channel
|
||||
let (control_tx, mut control_rx) = tokio::sync::mpsc::channel::<
|
||||
crate::control::ControlMessage,
|
||||
>(32);
|
||||
|
||||
if self.config.node.control.enabled {
|
||||
let config = self.config.node.control.clone();
|
||||
let tx = control_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
match ControlSocket::bind(&config) {
|
||||
Ok(socket) => {
|
||||
socket.accept_loop(tx).await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(error = %e, "Failed to bind control socket");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Drop unused sender to avoid keeping channel open if control is disabled
|
||||
drop(control_tx);
|
||||
|
||||
info!("RX event loop started");
|
||||
|
||||
loop {
|
||||
@@ -73,6 +97,10 @@ impl Node {
|
||||
);
|
||||
self.register_identity(identity.node_addr, identity.pubkey);
|
||||
}
|
||||
Some((request, response_tx)) = control_rx.recv() => {
|
||||
let response = queries::dispatch(self, &request.command);
|
||||
let _ = response_tx.send(response);
|
||||
}
|
||||
_ = tick.tick() => {
|
||||
self.check_timeouts();
|
||||
let now_ms = std::time::SystemTime::now()
|
||||
|
||||
@@ -919,6 +919,11 @@ impl Node {
|
||||
self.sessions.len()
|
||||
}
|
||||
|
||||
/// Iterate over all session entries (for control queries).
|
||||
pub(crate) fn session_entries(&self) -> impl Iterator<Item = (&NodeAddr, &SessionEntry)> {
|
||||
self.sessions.iter()
|
||||
}
|
||||
|
||||
// === Identity Cache ===
|
||||
|
||||
/// Register a node in the identity cache for FipsAddress → NodeAddr lookup.
|
||||
@@ -952,6 +957,16 @@ impl Node {
|
||||
self.identity_cache.len()
|
||||
}
|
||||
|
||||
/// Number of pending discovery lookups.
|
||||
pub fn pending_lookup_count(&self) -> usize {
|
||||
self.pending_lookups.len()
|
||||
}
|
||||
|
||||
/// Number of recent discovery requests tracked.
|
||||
pub fn recent_request_count(&self) -> usize {
|
||||
self.recent_requests.len()
|
||||
}
|
||||
|
||||
// === Routing ===
|
||||
|
||||
/// Find next hop for a destination node address.
|
||||
|
||||
Reference in New Issue
Block a user