node: Expose listen addresses

This commit is contained in:
cloudhead 2024-02-26 12:35:20 +01:00
parent d86d99e002
commit 9c9bbbe7bb
No known key found for this signature in database
9 changed files with 83 additions and 18 deletions

View File

@ -15,7 +15,7 @@ node status` command (or just `rad node` for short):
``` ```
$ rad node status $ rad node status
✓ Node is running. ✓ Node is running and listening on [..].
``` ```
The node also allows us to query data that it has access to such as The node also allows us to query data that it has access to such as

View File

@ -189,7 +189,21 @@ pub fn connect(
pub fn status(node: &Node, profile: &Profile) -> anyhow::Result<()> { pub fn status(node: &Node, profile: &Profile) -> anyhow::Result<()> {
if node.is_running() { if node.is_running() {
term::success!("Node is {}.", term::format::positive("running")); let listen = node
.listen_addrs()?
.into_iter()
.map(|addr| addr.to_string())
.collect::<Vec<_>>();
if listen.is_empty() {
term::success!("Node is {}.", term::format::positive("running"));
} else {
term::success!(
"Node is {} and listening on {}.",
term::format::positive("running"),
listen.join(", ")
);
}
} else { } else {
term::info!("Node is {}.", term::format::negative("stopped")); term::info!("Node is {}.", term::format::negative("stopped"));
term::info!( term::info!(

View File

@ -110,6 +110,11 @@ where
CommandResult::Okay(config).to_writer(writer)?; CommandResult::Okay(config).to_writer(writer)?;
} }
Command::ListenAddrs => {
let addrs = handle.listen_addrs()?;
CommandResult::Okay(addrs).to_writer(writer)?;
}
Command::Seeds { rid } => { Command::Seeds { rid } => {
let seeds = handle.seeds(rid)?; let seeds = handle.seeds(rid)?;

View File

@ -244,8 +244,6 @@ impl Runtime {
local_addrs.push(local_addr); local_addrs.push(local_addr);
wire.listen(listener); wire.listen(listener);
log::info!(target: "node", "Listening on {local_addr}..");
} }
let reactor = Reactor::named(wire, popol::Poller::new(), thread::name(&id, "service"))?; let reactor = Reactor::named(wire, popol::Poller::new(), thread::name(&id, "service"))?;
let handle = Handle::new(home.clone(), reactor.controller(), emitter); let handle = Handle::new(home.clone(), reactor.controller(), emitter);

View File

@ -1,3 +1,4 @@
use std::net;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -190,6 +191,12 @@ impl radicle::node::Handle for Handle {
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
fn listen_addrs(&self) -> Result<Vec<net::SocketAddr>, Self::Error> {
let (sender, receiver) = chan::bounded(1);
self.command(service::Command::ListenAddrs(sender))?;
receiver.recv().map_err(Error::from)
}
fn fetch( fn fetch(
&mut self, &mut self,
id: RepoId, id: RepoId,

View File

@ -13,7 +13,7 @@ use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::Arc; use std::sync::Arc;
use std::{fmt, time}; use std::{fmt, net, time};
use crossbeam_channel as chan; use crossbeam_channel as chan;
use fastrand::Rng; use fastrand::Rng;
@ -179,6 +179,8 @@ pub enum Command {
Disconnect(NodeId), Disconnect(NodeId),
/// Get the node configuration. /// Get the node configuration.
Config(chan::Sender<Config>), Config(chan::Sender<Config>),
/// Get the node's listen addresses.
ListenAddrs(chan::Sender<Vec<std::net::SocketAddr>>),
/// Lookup seeds for the given repository in the routing table. /// Lookup seeds for the given repository in the routing table.
Seeds(RepoId, chan::Sender<Seeds>), Seeds(RepoId, chan::Sender<Seeds>),
/// Fetch the given repository from the network. /// Fetch the given repository from the network.
@ -204,6 +206,7 @@ impl fmt::Debug for Command {
Self::Connect(id, addr, opts) => write!(f, "Connect({id}, {addr}, {opts:?})"), Self::Connect(id, addr, opts) => write!(f, "Connect({id}, {addr}, {opts:?})"),
Self::Disconnect(id) => write!(f, "Disconnect({id})"), Self::Disconnect(id) => write!(f, "Disconnect({id})"),
Self::Config(_) => write!(f, "Config"), Self::Config(_) => write!(f, "Config"),
Self::ListenAddrs(_) => write!(f, "ListenAddrs"),
Self::Seeds(id, _) => write!(f, "Seeds({id})"), Self::Seeds(id, _) => write!(f, "Seeds({id})"),
Self::Fetch(id, node, _, _) => write!(f, "Fetch({id}, {node})"), Self::Fetch(id, node, _, _) => write!(f, "Fetch({id}, {node})"),
Self::Seed(id, scope, _) => write!(f, "Seed({id}, {scope})"), Self::Seed(id, scope, _) => write!(f, "Seed({id}, {scope})"),
@ -370,6 +373,8 @@ pub struct Service<D, S, G> {
started_at: Option<LocalTime>, started_at: Option<LocalTime>,
/// Publishes events to subscribers. /// Publishes events to subscribers.
emitter: Emitter<Event>, emitter: Emitter<Event>,
/// Local listening addresses.
listening: Vec<net::SocketAddr>,
} }
impl<D, S, G> Service<D, S, G> impl<D, S, G> Service<D, S, G>
@ -427,6 +432,7 @@ where
last_announce: LocalTime::default(), last_announce: LocalTime::default(),
started_at: None, started_at: None,
emitter, emitter,
listening: vec![],
} }
} }
@ -705,6 +711,9 @@ where
Command::Config(resp) => { Command::Config(resp) => {
resp.send(self.config.clone()).ok(); resp.send(self.config.clone()).ok();
} }
Command::ListenAddrs(resp) => {
resp.send(self.listening.clone()).ok();
}
Command::Seeds(rid, resp) => match self.seeds(&rid) { Command::Seeds(rid, resp) => match self.seeds(&rid) {
Ok(seeds) => { Ok(seeds) => {
let (connected, disconnected) = seeds.partition(); let (connected, disconnected) = seeds.partition();
@ -1077,6 +1086,12 @@ where
} }
} }
pub fn listening(&mut self, local_addr: net::SocketAddr) {
log::info!(target: "node", "Listening on {local_addr}..");
self.listening.push(local_addr);
}
pub fn connected(&mut self, remote: NodeId, addr: Address, link: Link) { pub fn connected(&mut self, remote: NodeId, addr: Address, link: Link) {
info!(target: "service", "Connected to {} ({:?})", remote, link); info!(target: "service", "Connected to {} ({:?})", remote, link);
self.emitter.emit(Event::PeerConnected { nid: remote }); self.emitter.emit(Event::PeerConnected { nid: remote });

View File

@ -31,6 +31,10 @@ impl radicle::node::Handle for Handle {
true true
} }
fn listen_addrs(&self) -> Result<Vec<std::net::SocketAddr>, Self::Error> {
Ok(vec![])
}
fn config(&self) -> Result<Config, Self::Error> { fn config(&self) -> Result<Config, Self::Error> {
Ok(Config::new(Alias::new("acme"))) Ok(Config::new(Alias::new("acme")))
} }

View File

@ -292,6 +292,8 @@ pub struct Wire<D, S, G: Signer + Ecdh> {
outbound: RandomMap<RawFd, Outbound>, outbound: RandomMap<RawFd, Outbound>,
/// Inbound peers without a session. /// Inbound peers without a session.
inbound: RandomMap<RawFd, Inbound>, inbound: RandomMap<RawFd, Inbound>,
/// Listening addresses that are not yet registered.
listening: RandomMap<RawFd, net::SocketAddr>,
/// Peer (established) sessions. /// Peer (established) sessions.
peers: Peers, peers: Peers,
/// SOCKS5 proxy address. /// SOCKS5 proxy address.
@ -320,11 +322,14 @@ where
actions: VecDeque::new(), actions: VecDeque::new(),
inbound: RandomMap::default(), inbound: RandomMap::default(),
outbound: RandomMap::default(), outbound: RandomMap::default(),
listening: RandomMap::default(),
peers: Peers(RandomMap::default()), peers: Peers(RandomMap::default()),
} }
} }
pub fn listen(&mut self, socket: NetAccept<WireSession<G>>) { pub fn listen(&mut self, socket: NetAccept<WireSession<G>>) {
self.listening
.insert(socket.as_raw_fd(), socket.local_addr());
self.actions.push_back(Action::RegisterListener(socket)); self.actions.push_back(Action::RegisterListener(socket));
} }
@ -495,18 +500,23 @@ where
} }
fn handle_registered(&mut self, fd: RawFd, id: ResourceId, typ: ResourceType) { fn handle_registered(&mut self, fd: RawFd, id: ResourceId, typ: ResourceType) {
if typ == ResourceType::Listener { match typ {
// Not interested in listener resource registration. ResourceType::Listener => {
return; if let Some(local_addr) = self.listening.remove(&fd) {
} self.service.listening(local_addr);
if let Some(outbound) = self.outbound.get_mut(&fd) { }
log::debug!(target: "wire", "Outbound peer resource registered for {} with id={id} (fd={fd})", outbound.nid); }
outbound.id = Some(id); ResourceType::Transport => {
} else if let Some(inbound) = self.inbound.get_mut(&fd) { if let Some(outbound) = self.outbound.get_mut(&fd) {
log::debug!(target: "wire", "Inbound peer resource registered with id={id} (fd={fd})"); log::debug!(target: "wire", "Outbound peer resource registered for {} with id={id} (fd={fd})", outbound.nid);
inbound.id = Some(id); outbound.id = Some(id);
} else { } else if let Some(inbound) = self.inbound.get_mut(&fd) {
log::warn!(target: "wire", "Unknown peer registered with fd={fd} and id={id}"); log::debug!(target: "wire", "Inbound peer resource registered with id={id} (fd={fd})");
inbound.id = Some(id);
} else {
log::warn!(target: "wire", "Unknown peer registered with fd={fd} and id={id}");
}
}
} }
} }

View File

@ -435,6 +435,9 @@ pub enum Command {
/// Get the current node condiguration. /// Get the current node condiguration.
Config, Config,
/// Get the node's listen addresses.
ListenAddrs,
/// Connect to node with the given address. /// Connect to node with the given address.
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
Connect { Connect {
@ -808,8 +811,10 @@ pub trait Handle: Clone + Sync + Send {
/// Get the local Node ID. /// Get the local Node ID.
fn nid(&self) -> Result<NodeId, Self::Error>; fn nid(&self) -> Result<NodeId, Self::Error>;
/// Check if the node is running. to a peer. /// Check if the node is running.
fn is_running(&self) -> bool; fn is_running(&self) -> bool;
/// Get the node's bound listen addresses.
fn listen_addrs(&self) -> Result<Vec<net::SocketAddr>, Self::Error>;
/// Get the current node configuration. /// Get the current node configuration.
fn config(&self) -> Result<config::Config, Self::Error>; fn config(&self) -> Result<config::Config, Self::Error>;
/// Connect to a peer. /// Connect to a peer.
@ -970,6 +975,13 @@ impl Handle for Node {
.map_err(Error::from) .map_err(Error::from)
} }
fn listen_addrs(&self) -> Result<Vec<net::SocketAddr>, Error> {
self.call::<Vec<net::SocketAddr>>(Command::ListenAddrs, DEFAULT_TIMEOUT)?
.next()
.ok_or(Error::EmptyResponse)?
.map_err(Error::from)
}
fn is_running(&self) -> bool { fn is_running(&self) -> bool {
let Ok(mut lines) = self.call::<Success>(Command::Status, DEFAULT_TIMEOUT) else { let Ok(mut lines) = self.call::<Success>(Command::Status, DEFAULT_TIMEOUT) else {
return false; return false;