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:
parent
1c9670b90f
commit
fd91cf4d28
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
])
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Reference in New Issue