node: Add access to routing.db on `profile`

httpd: Use routing.db to return `trackings` of an RID

Signed-off-by: xphoniex <dj.2dixx@gmail.com>
This commit is contained in:
xphoniex 2023-06-01 12:26:27 +00:00 committed by Alexis Sellier
parent 1c9670b90f
commit fd91cf4d28
No known key found for this signature in database
7 changed files with 69 additions and 4 deletions

View File

@ -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,
}
}

View File

@ -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 {

View File

@ -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,
}
])
);

View File

@ -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,
})
);
}

View File

@ -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");

View File

@ -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());
}
}

View File

@ -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()