diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index 41487f1e..bb97dedc 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -324,7 +324,7 @@ async fn remotes_handler(State(ctx): State, Path(project): Path) -> let storage = &ctx.profile.storage; let repo = storage.repository(project)?; let delegates = repo.delegates()?; - let tracking_store = &ctx.profile.tracking()?; + let aliases = &ctx.profile.aliases()?; let remotes = repo .remotes()? .filter_map(|r| r.map(|r| r.1).ok()) @@ -339,7 +339,7 @@ async fn remotes_handler(State(ctx): State, Path(project): Path) -> }) .collect::>(); - match tracking_store.alias(&remote.id) { + match aliases.alias(&remote.id) { Some(alias) => json!({ "id": remote.id, "alias": alias, @@ -454,10 +454,10 @@ async fn issues_handler( .collect::>(); issues.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp())); - let tracking_store = &ctx.profile.tracking()?; + let aliases = &ctx.profile.aliases()?; let issues = issues .into_iter() - .map(|(id, issue, _)| api::json::issue(id, issue, &tracking_store)) + .map(|(id, issue, _)| api::json::issue(id, issue, &aliases)) .skip(page * per_page) .take(per_page) .collect::>(); @@ -574,13 +574,9 @@ async fn issue_handler( let issue = issue::Issues::open(&repo)? .get(&issue_id.into())? .ok_or(Error::NotFound)?; - let tracking_store = &ctx.profile.tracking()?; + let aliases = &ctx.profile.aliases()?; - Ok::<_, Error>(Json(api::json::issue( - issue_id.into(), - issue, - &tracking_store, - ))) + Ok::<_, Error>(Json(api::json::issue(issue_id.into(), issue, &aliases))) } #[derive(Deserialize, Serialize)] @@ -738,10 +734,10 @@ async fn patches_handler( }) .collect::>(); patches.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp())); - let tracking_store = &ctx.profile.tracking()?; + let aliases = &ctx.profile.aliases()?; let patches = patches .into_iter() - .map(|(id, patch, _)| api::json::patch(id, patch, &repo, &tracking_store)) + .map(|(id, patch, _)| api::json::patch(id, patch, &repo, &aliases)) .skip(page * per_page) .take(per_page) .collect::>(); @@ -760,13 +756,13 @@ async fn patch_handler( let patch = patch::Patches::open(&repo)? .get(&patch_id.into())? .ok_or(Error::NotFound)?; - let tracking_store = &ctx.profile.tracking()?; + let aliases = &ctx.profile.aliases()?; Ok::<_, Error>(Json(api::json::patch( patch_id.into(), patch, &repo, - &tracking_store, + &aliases, ))) } diff --git a/radicle-httpd/src/test.rs b/radicle-httpd/src/test.rs index 14a922bc..aad3054d 100644 --- a/radicle-httpd/src/test.rs +++ b/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::address as AddressStore; use radicle::node::routing as RoutingStore; use radicle::node::tracking::store as TrackingStore; use radicle::profile::Home; @@ -87,8 +88,11 @@ pub fn contributor(dir: &Path) -> Context { fn seed_with_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"); + let addresses_db = dir.join("radicle").join("node").join("addresses.db"); + TrackingStore::Config::open(tracking_db).unwrap(); RoutingStore::Table::open(routing_db).unwrap(); + AddressStore::Book::open(addresses_db).unwrap(); let workdir = dir.join("hello-world"); diff --git a/radicle/src/node/address.rs b/radicle/src/node/address.rs index a491c9fd..e6e6e350 100644 --- a/radicle/src/node/address.rs +++ b/radicle/src/node/address.rs @@ -4,10 +4,12 @@ mod types; pub use store::*; pub use types::*; -use crate::node::Address; -use cyphernet::addr::HostName; use std::net; +use cyphernet::addr::HostName; + +use crate::node::Address; + /// Address type. #[repr(u8)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/radicle/src/node/address/store.rs b/radicle/src/node/address/store.rs index 06c077b2..efcf91a0 100644 --- a/radicle/src/node/address/store.rs +++ b/radicle/src/node/address/store.rs @@ -251,7 +251,7 @@ impl Store for Book { } } -impl AliasStore for &Book { +impl AliasStore for Book { /// Retrieve `alias` of given node. /// Calls `Self::get` under the hood. fn alias(&self, nid: &NodeId) -> Option { diff --git a/radicle/src/profile.rs b/radicle/src/profile.rs index 04c6b06a..4dddee9f 100644 --- a/radicle/src/profile.rs +++ b/radicle/src/profile.rs @@ -19,8 +19,9 @@ use crate::crypto::ssh::agent::Agent; use crate::crypto::ssh::{keystore, Keystore, Passphrase}; use crate::crypto::{PublicKey, Signer}; use crate::node; -use crate::node::{address, routing, tracking}; +use crate::node::{address, routing, tracking, AliasStore}; use crate::prelude::Did; +use crate::prelude::NodeId; use crate::storage::git::transport; use crate::storage::git::Storage; @@ -57,6 +58,10 @@ pub enum Error { Agent(#[from] crate::crypto::ssh::agent::Error), #[error("profile key `{0}` is not registered with ssh-agent")] KeyNotRegistered(PublicKey), + #[error(transparent)] + TrackingStore(#[from] node::tracking::store::Error), + #[error(transparent)] + AddressStore(#[from] node::address::Error), } #[derive(Debug, Clone)] @@ -152,6 +157,17 @@ impl Profile { Ok(addresses) } + /// Return a multi-source store for aliases. + pub fn aliases(&self) -> Result { + let tracking = self.tracking()?; + let addresses = self.addresses()?; + + Ok(Aliases { + tracking, + addresses, + }) + } + /// Return the path to the keys folder. pub fn keys(&self) -> PathBuf { self.home.keys() @@ -168,6 +184,23 @@ impl Profile { } } +/// Holds multiple alias stores, and will try +/// them one by one when asking for an alias. +pub struct Aliases { + tracking: tracking::store::Config, + addresses: address::Book, +} + +impl AliasStore for &Aliases { + /// Retrieve `alias` of given node. + /// First looks in `tracking.db` and then `address.db`, + fn alias(&self, nid: &NodeId) -> Option { + (&&self.tracking as &dyn AliasStore) + .alias(nid) + .or_else(|| (&self.addresses as &dyn AliasStore).alias(nid)) + } +} + /// Get the path to the radicle home folder. pub fn home() -> Result { if let Some(home) = env::var_os(env::RAD_HOME) {