Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: Remove `Routing` command
Alexis Sellier committed 3 years ago
commit caaa7581e69534dd7137269f0d24ef718f450156
parent 40c58b45ed5b41b7776d1ecf920309f3a3aa1c39
8 files changed +35 -58
modified radicle-cli/src/commands/node.rs
@@ -1,7 +1,7 @@
use std::ffi::OsString;

use anyhow::anyhow;
-
use radicle::node::{Address, Node, NodeId, TRACKING_DB_FILE};
+
use radicle::node::{Address, Node, NodeId, ROUTING_DB_FILE, TRACKING_DB_FILE};

use crate::terminal as term;
use crate::terminal::args::{Args, Error, Help};
@@ -139,8 +139,9 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
            control::connect(&mut node, nid, addr)?
        }
        Operation::Routing => {
-
            let node = Node::new(profile.socket());
-
            routing::run(&node)?;
+
            let store =
+
                radicle::node::routing::Table::reader(profile.home.node().join(ROUTING_DB_FILE))?;
+
            routing::run(&store)?;
        }
        Operation::Start => control::start()?,
        Operation::Status => {
modified radicle-cli/src/commands/node/routing.rs
@@ -1,12 +1,12 @@
-
use radicle::{node::Handle as _, Node};
+
use radicle::node;

use crate::terminal as term;

-
pub fn run(node: &Node) -> anyhow::Result<()> {
+
pub fn run<S: node::routing::Store>(routing: &S) -> anyhow::Result<()> {
    let mut t = term::Table::new(term::table::TableOptions::default());
    t.push(["RID", "NID"]);
    t.push(["---", "---"]);
-
    for (id, node) in node.routing()? {
+
    for (id, node) in routing.entries()? {
        t.push([
            term::format::highlight(id).to_string(),
            term::format::node(&node),
modified radicle-node/src/control.rs
@@ -187,14 +187,6 @@ fn command<H: Handle<Error = runtime::HandleError>>(
        CommandName::Status => {
            CommandResult::ok().to_writer(writer).ok();
        }
-
        CommandName::Routing => match handle.routing() {
-
            Ok(c) => {
-
                for route in c.into_iter() {
-
                    serde_json::to_writer(&mut writer, &route)?;
-
                }
-
            }
-
            Err(e) => return Err(CommandError::Runtime(e)),
-
        },
        CommandName::Inventory => match handle.inventory() {
            Ok(c) => {
                for id in c.iter() {
modified radicle-node/src/runtime/handle.rs
@@ -109,7 +109,6 @@ impl<G: Signer + Ecdh + 'static> Handle<G> {
impl<G: Signer + Ecdh + 'static> radicle::node::Handle for Handle<G> {
    type Sessions = Sessions;
    type Error = Error;
-
    type Routing = chan::Receiver<(Id, NodeId)>;

    fn is_running(&self) -> bool {
        true
@@ -171,23 +170,6 @@ impl<G: Signer + Ecdh + 'static> radicle::node::Handle for Handle<G> {
        receiver.recv().map_err(Error::from)
    }

-
    fn routing(&self) -> Result<Self::Routing, Error> {
-
        let (sender, receiver) = chan::unbounded();
-
        let query: Arc<QueryState> = Arc::new(move |state| {
-
            for (id, node) in state.routing().entries()? {
-
                if sender.send((id, node)).is_err() {
-
                    break;
-
                }
-
            }
-
            Ok(())
-
        });
-
        let (err_sender, err_receiver) = chan::bounded(1);
-
        self.command(service::Command::QueryState(query, err_sender))?;
-
        err_receiver.recv()??;
-

-
        Ok(receiver)
-
    }
-

    fn sessions(&self) -> Result<Self::Sessions, Error> {
        let (sender, receiver) = chan::unbounded();
        let query: Arc<QueryState> = Arc::new(move |state| {
modified radicle-node/src/test/environment.rs
@@ -17,6 +17,7 @@ use radicle::crypto::{KeyPair, Seed, Signer};
use radicle::git;
use radicle::git::refname;
use radicle::identity::Id;
+
use radicle::node::routing::Store;
use radicle::node::Handle as _;
use radicle::profile::Home;
use radicle::profile::Profile;
@@ -156,6 +157,14 @@ impl<G: Signer + cyphernet::Ecdh> NodeHandle<G> {
        self
    }

+
    /// Get routing table entries.
+
    pub fn routing(&self) -> impl Iterator<Item = (Id, NodeId)> {
+
        radicle::node::routing::Table::reader(self.home.node().join(radicle::node::ROUTING_DB_FILE))
+
            .unwrap()
+
            .entries()
+
            .unwrap()
+
    }
+

    /// Wait until this node's routing table matches the remotes.
    pub fn converge<'a>(
        &'a self,
@@ -176,7 +185,7 @@ impl<G: Signer + cyphernet::Ecdh> NodeHandle<G> {

            let mut remaining: BTreeSet<_> = routes.iter().collect();

-
            for (rid, nid) in self.handle.routing().unwrap() {
+
            for (rid, nid) in self.routing() {
                if !remaining.remove(&(rid, nid)) {
                    panic!(
                        "Node::routes_to: unexpected route for {}: ({rid}, {nid})",
@@ -347,7 +356,7 @@ pub fn converge<'a, G: Signer + cyphernet::Ecdh + 'static>(
    // First build the set of all routes.
    for node in &nodes {
        // Routes from the routing table.
-
        for (rid, seed_id) in node.handle.routing().unwrap() {
+
        for (rid, seed_id) in node.routing() {
            all_routes.insert((rid, seed_id));
        }
        // Routes from the local inventory.
@@ -360,8 +369,8 @@ pub fn converge<'a, G: Signer + cyphernet::Ecdh + 'static>(
    // its routing table has all routes. If so, remove it from the remaining nodes.
    while !remaining.is_empty() {
        remaining.retain(|_, node| {
-
            let routing = node.handle.routing().unwrap();
-
            let routes = BTreeSet::from_iter(routing.try_iter());
+
            let routing = node.routing();
+
            let routes = BTreeSet::from_iter(routing);

            if routes == all_routes {
                log::debug!(target: "test", "Node {} has converged", node.id);
modified radicle-node/src/test/handle.rs
@@ -20,7 +20,6 @@ pub struct Handle {
impl radicle::node::Handle for Handle {
    type Error = HandleError;
    type Sessions = service::Sessions;
-
    type Routing = Vec<(Id, NodeId)>;

    fn is_running(&self) -> bool {
        true
@@ -68,10 +67,6 @@ impl radicle::node::Handle for Handle {
        unimplemented!()
    }

-
    fn routing(&self) -> Result<Self::Routing, Self::Error> {
-
        unimplemented!();
-
    }
-

    fn sessions(&self) -> Result<Self::Sessions, Self::Error> {
        unimplemented!();
    }
modified radicle/src/node.rs
@@ -141,8 +141,6 @@ pub enum CommandName {
    UntrackNode,
    /// Get the node's inventory.
    Inventory,
-
    /// Get the node's routing table.
-
    Routing,
    /// Get the node's status.
    Status,
    /// Shutdown the node.
@@ -385,8 +383,6 @@ pub trait Handle {
    /// The error returned by all methods.
    type Error: std::error::Error + Send + Sync + 'static;

-
    type Routing: IntoIterator<Item = (Id, NodeId)>;
-

    /// Check if the node is running. to a peer.
    fn is_running(&self) -> bool;
    /// Connect to a peer.
@@ -412,8 +408,6 @@ pub trait Handle {
    fn sync_inventory(&mut self) -> Result<bool, Self::Error>;
    /// Ask the service to shutdown.
    fn shutdown(self) -> Result<(), Self::Error>;
-
    /// Query the routing table entries.
-
    fn routing(&self) -> Result<Self::Routing, Self::Error>;
    /// Query the peer session state.
    fn sessions(&self) -> Result<Self::Sessions, Self::Error>;
    /// Query the inventory.
@@ -464,7 +458,6 @@ impl Node {
impl Handle for Node {
    type Sessions = ();
    type Error = Error;
-
    type Routing = Vec<(Id, NodeId)>;

    fn is_running(&self) -> bool {
        let Ok(mut lines) = self.call::<&str, CommandResult>(CommandName::Status, []) else {
@@ -573,15 +566,6 @@ impl Handle for Node {
        response.into()
    }

-
    fn routing(&self) -> Result<Self::Routing, Error> {
-
        let mut routes = Vec::new();
-
        for result in self.call::<&str, _>(CommandName::Routing, [])? {
-
            let route = result?;
-
            routes.push(route);
-
        }
-
        Ok(routes)
-
    }
-

    fn sessions(&self) -> Result<Self::Sessions, Error> {
        todo!();
    }
modified radicle/src/node/routing.rs
@@ -1,6 +1,6 @@
use std::collections::HashSet;
-
use std::fmt;
use std::path::Path;
+
use std::{fmt, time};

use sqlite as sql;
use thiserror::Error;
@@ -10,6 +10,9 @@ use crate::{
    prelude::{Id, NodeId},
};

+
/// How long to wait for the database lock to be released before failing a read.
+
const DB_READ_TIMEOUT: time::Duration = time::Duration::from_secs(1);
+

/// An error occuring in peer-to-peer networking code.
#[derive(Error, Debug)]
pub enum Error {
@@ -44,6 +47,17 @@ impl Table {
        Ok(Self { db })
    }

+
    /// Same as [`Self::open`], but in read-only mode. This is useful to have multiple
+
    /// open databases, as no locking is required.
+
    pub fn reader<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
+
        let mut db =
+
            sql::Connection::open_with_flags(path, sqlite::OpenFlags::new().set_read_only())?;
+
        db.set_busy_timeout(DB_READ_TIMEOUT.as_millis() as usize)?;
+
        db.execute(Self::SCHEMA)?;
+

+
        Ok(Self { db })
+
    }
+

    /// Create a new in-memory routing table.
    pub fn memory() -> Result<Self, Error> {
        let db = sql::Connection::open(":memory:")?;