Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
node: Add access to routing.db on `profile`
xphoniex committed 2 years ago
commit fd91cf4d28bd370a6c5beb9ca158e4d91432df25
parent 1c9670b90f05ead0285413435e4ac35512581008
7 files changed +69 -4
modified radicle-httpd/src/api.rs
@@ -17,6 +17,7 @@ use tower_http::cors::{self, CorsLayer};
use radicle::cob::issue;
use radicle::cob::patch;
use radicle::identity::Id;
+
use radicle::node::routing::Store;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::Profile;

@@ -52,6 +53,8 @@ impl Context {
        let delegates = doc.delegates;
        let issues = issue::Issues::open(&repo)?.counts()?;
        let patches = patch::Patches::open(&repo)?.counts()?;
+
        let routing = &self.profile.routing()?;
+
        let trackings = routing.count(&id).unwrap_or_default();

        Ok(project::Info {
            payload,
@@ -60,6 +63,7 @@ impl Context {
            issues,
            patches,
            id,
+
            trackings,
        })
    }

@@ -183,5 +187,6 @@ mod project {
        pub patches: cob::patch::PatchCounts,
        pub issues: cob::issue::IssueCounts,
        pub id: Id,
+
        pub trackings: usize,
    }
}
modified radicle-httpd/src/api/error.rs
@@ -73,6 +73,10 @@ pub enum Error {
    /// Tracking store error.
    #[error(transparent)]
    TrackingStore(#[from] radicle::node::tracking::store::Error),
+

+
    /// Routing store error.
+
    #[error(transparent)]
+
    RoutingStore(#[from] radicle::node::routing::Error),
}

impl IntoResponse for Error {
modified radicle-httpd/src/api/v1/delegates.rs
@@ -6,6 +6,7 @@ use axum::{Json, Router};
use radicle::cob::issue::Issues;
use radicle::cob::patch::Patches;
use radicle::identity::Did;
+
use radicle::node::routing::Store;
use radicle::storage::{ReadRepository, ReadStorage};

use crate::api::error::Error;
@@ -34,6 +35,7 @@ async fn delegates_projects_handler(
    let page = page.unwrap_or(0);
    let per_page = per_page.unwrap_or(10);
    let storage = &ctx.profile.storage;
+
    let routing = &ctx.profile.routing()?;
    let projects = storage
        .repositories()?
        .into_iter()
@@ -54,6 +56,8 @@ async fn delegates_projects_handler(
            let Ok(patches) = Patches::open(&repo) else { return None };
            let Ok(patches) = patches.counts() else { return None };

+
            let trackings = routing.count(&id).unwrap_or_default();
+

            Some(Info {
                payload,
                delegates,
@@ -61,6 +65,7 @@ async fn delegates_projects_handler(
                issues,
                patches,
                id,
+
                trackings,
            })
        })
        .skip(page * per_page)
@@ -107,7 +112,8 @@ mod routes {
                  "open": 1,
                  "closed": 0,
                },
-
                "id": RID
+
                "id": RID,
+
                "trackings": 0,
              }
            ])
        );
modified radicle-httpd/src/api/v1/projects.rs
@@ -14,6 +14,7 @@ use tower_http::set_header::SetResponseHeaderLayer;

use radicle::cob::{issue, patch, thread, ActorId, Tag};
use radicle::identity::Id;
+
use radicle::node::routing::Store;
use radicle::node::NodeId;
use radicle::storage::git::paths;
use radicle::storage::{ReadRepository, ReadStorage, WriteRepository};
@@ -77,6 +78,7 @@ async fn project_root_handler(
    let page = page.unwrap_or(0);
    let per_page = per_page.unwrap_or(10);
    let storage = &ctx.profile.storage;
+
    let routing = &ctx.profile.routing()?;
    let projects = storage
        .repositories()?
        .into_iter()
@@ -91,6 +93,7 @@ async fn project_root_handler(
            let Ok(patches) = patch::Patches::open(&repo) else { return None };
            let Ok(patches) = patches.counts() else { return None };
            let delegates = doc.delegates;
+
            let trackings = routing.count(&id).unwrap_or_default();

            Some(Info {
                payload,
@@ -99,6 +102,7 @@ async fn project_root_handler(
                issues,
                patches,
                id,
+
                trackings,
            })
        })
        .skip(page * per_page)
@@ -800,7 +804,8 @@ mod routes {
                  "open": 1,
                  "closed": 0,
                },
-
                "id": RID
+
                "id": RID,
+
                "trackings": 0,
              }
            ])
        );
@@ -831,7 +836,8 @@ mod routes {
                 "open": 1,
                 "closed": 0,
               },
-
               "id": RID
+
               "id": RID,
+
               "trackings": 0,
            })
        );
    }
modified radicle-httpd/src/test.rs
@@ -16,6 +16,7 @@ use radicle::crypto::ssh::keystore::MemorySigner;
use radicle::crypto::ssh::Keystore;
use radicle::crypto::{KeyPair, Seed, Signer};
use radicle::git::{raw as git2, RefString};
+
use radicle::node::routing as RoutingStore;
use radicle::node::tracking::store as TrackingStore;
use radicle::profile::Home;
use radicle::storage::ReadStorage;
@@ -85,7 +86,9 @@ pub fn contributor(dir: &Path) -> Context {

fn seed_with_signer<G: Signer>(dir: &Path, profile: radicle::Profile, signer: &G) -> Context {
    let tracking_db = dir.join("radicle").join("node").join("tracking.db");
+
    let routing_db = dir.join("radicle").join("node").join("routing.db");
    TrackingStore::Config::open(tracking_db).unwrap();
+
    RoutingStore::Table::open(routing_db).unwrap();

    let workdir = dir.join("hello-world");

modified radicle/src/node/routing.rs
@@ -104,6 +104,8 @@ pub trait Store {
    fn len(&self) -> Result<usize, Error>;
    /// Prune entries older than the given timestamp.
    fn prune(&mut self, oldest: Timestamp, limit: Option<usize>) -> Result<usize, Error>;
+
    /// Count the number of routes for a specific repo RID.
+
    fn count(&self, id: &Id) -> Result<usize, Error>;
}

impl Store for Table {
@@ -236,6 +238,24 @@ impl Store for Table {

        Ok(self.db.change_count())
    }
+

+
    fn count(&self, id: &Id) -> Result<usize, Error> {
+
        let mut stmt = self
+
            .db
+
            .prepare("SELECT COUNT(*) FROM routing WHERE resource = ?")?;
+

+
        stmt.bind((1, id))?;
+

+
        let count: i64 = stmt
+
            .into_iter()
+
            .next()
+
            .expect("COUNT will always return a single row")?
+
            .read(0);
+

+
        let count: usize = count.try_into().map_err(|_| Error::UnitOverflow)?;
+

+
        Ok(count)
+
    }
}

#[cfg(test)]
@@ -408,4 +428,17 @@ mod test {
            }
        }
    }
+

+
    #[test]
+
    fn test_count() {
+
        let id = arbitrary::gen::<Id>(1);
+
        let nodes = arbitrary::set::<NodeId>(5..10);
+
        let mut db = Table::open(":memory:").unwrap();
+

+
        for node in &nodes {
+
            db.insert(id, *node, 0).unwrap();
+
        }
+

+
        assert_eq!(db.count(&id).unwrap(), nodes.len());
+
    }
}
modified radicle/src/profile.rs
@@ -18,7 +18,7 @@ use thiserror::Error;
use crate::crypto::ssh::agent::Agent;
use crate::crypto::ssh::{keystore, Keystore, Passphrase};
use crate::crypto::{PublicKey, Signer};
-
use crate::node::{self, tracking};
+
use crate::node::{self, routing, tracking};
use crate::prelude::Did;
use crate::storage::git::transport;
use crate::storage::git::Storage;
@@ -135,6 +135,14 @@ impl Profile {
        Ok(config)
    }

+
    /// Return a read-only handle to the routing database of the node.
+
    pub fn routing(&self) -> Result<routing::Table, routing::Error> {
+
        let path = self.home.node().join(node::ROUTING_DB_FILE);
+
        let router = routing::Table::reader(path)?;
+

+
        Ok(router)
+
    }
+

    /// Return the path to the keys folder.
    pub fn keys(&self) -> PathBuf {
        self.home.keys()