diff --git a/radicle-cli/src/commands/follow.rs b/radicle-cli/src/commands/follow.rs index 6fde950b..d2250069 100644 --- a/radicle-cli/src/commands/follow.rs +++ b/radicle-cli/src/commands/follow.rs @@ -166,9 +166,14 @@ pub fn following(profile: &Profile, alias: Option) -> anyhow::Result<()> fn push_policies( t: &mut Table<3, Paint>, aliases: &impl AliasStore, - policies: impl Iterator, + policies: impl Iterator, ) { - for policy::Node { id, alias, policy } in policies { + for policy::FollowPolicy { + nid: id, + alias, + policy, + } in policies + { t.push([ term::format::highlight(Did::from(id).to_string()), match alias { diff --git a/radicle-cli/src/commands/inspect.rs b/radicle-cli/src/commands/inspect.rs index 558e534a..c8721bab 100644 --- a/radicle-cli/src/commands/inspect.rs +++ b/radicle-cli/src/commands/inspect.rs @@ -172,22 +172,24 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { } } Target::Policy => { - let tracking = profile.policies()?; - if let Some(repo) = tracking.seed_policy(&rid)? { - let tracking = match repo.policy { - Policy::Allow => term::format::positive("tracked"), - Policy::Block => term::format::negative("blocked"), - }; - println!( - "Repository {} is {} with scope {}", - term::format::tertiary(&rid), - tracking, - term::format::dim(format!("`{}`", repo.scope)) - ); - } else { - term::print(term::format::italic(format!( - "No tracking policy found for {rid}" - ))); + let policies = profile.policies()?; + let seed = policies.seed_policy(&rid)?; + match seed.policy { + Policy::Allow => { + println!( + "Repository {} is {} with scope {}", + term::format::tertiary(&rid), + term::format::positive("being seeded"), + term::format::dim(format!("`{}`", seed.scope)) + ); + } + Policy::Block => { + println!( + "Repository {} is {}", + term::format::tertiary(&rid), + term::format::negative("not being seeded"), + ); + } } } Target::Delegates => { diff --git a/radicle-cli/src/commands/ls.rs b/radicle-cli/src/commands/ls.rs index 14f66369..ce8797ab 100644 --- a/radicle-cli/src/commands/ls.rs +++ b/radicle-cli/src/commands/ls.rs @@ -106,7 +106,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { if refs.is_none() && !options.all { continue; } - let seeded = policy.is_seeded(&rid)?; + let seeded = policy.is_seeding(&rid)?; if !seeded && !options.all { continue; @@ -120,7 +120,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { if seeded { term::format::visibility(&doc.visibility).into() } else { - term::format::tertiary("local").into() + term::format::dim("local").into() }, term::format::secondary(head), term::format::italic(proj.description().to_owned()), diff --git a/radicle-cli/src/commands/remote/add.rs b/radicle-cli/src/commands/remote/add.rs index 145563e9..198a8d44 100644 --- a/radicle-cli/src/commands/remote/add.rs +++ b/radicle-cli/src/commands/remote/add.rs @@ -25,7 +25,7 @@ pub fn run( if sync { let mut node = radicle::Node::new(profile.socket()); - if !profile.policies()?.is_followed(nid)? { + if !profile.policies()?.is_following(nid)? { let alias = name.as_ref().and_then(|n| Alias::from_str(n.as_str()).ok()); follow::follow(*nid, alias, &mut node, profile)?; diff --git a/radicle-cli/src/commands/seed.rs b/radicle-cli/src/commands/seed.rs index 8f36348f..5fbd2667 100644 --- a/radicle-cli/src/commands/seed.rs +++ b/radicle-cli/src/commands/seed.rs @@ -183,7 +183,12 @@ pub fn seeding(profile: &Profile) -> anyhow::Result<()> { ]); t.divider(); - for policy::Repo { id, scope, policy } in store.seed_policies()? { + for policy::SeedPolicy { + rid: id, + scope, + policy, + } in store.seed_policies()? + { let id = id.to_string(); let scope = scope.to_string(); let policy = policy.to_string(); diff --git a/radicle-cli/src/commands/sync.rs b/radicle-cli/src/commands/sync.rs index b7a5bad9..3fa37434 100644 --- a/radicle-cli/src/commands/sync.rs +++ b/radicle-cli/src/commands/sync.rs @@ -281,7 +281,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { } Operation::Synchronize(SyncMode::Repo { mode, direction }) => { if [SyncDirection::Fetch, SyncDirection::Both].contains(&direction) { - if !profile.policies()?.is_seeded(&rid)? { + if !profile.policies()?.is_seeding(&rid)? { anyhow::bail!("repository {rid} is not seeded"); } let results = fetch(rid, mode.clone(), options.timeout, &mut node)?; diff --git a/radicle-fetch/src/policy.rs b/radicle-fetch/src/policy.rs index 07932f96..5cf7e7d6 100644 --- a/radicle-fetch/src/policy.rs +++ b/radicle-fetch/src/policy.rs @@ -16,7 +16,7 @@ pub enum Allowed { impl Allowed { pub fn from_config(rid: RepoId, config: &Config) -> Result { let entry = config - .repo_policy(&rid) + .seed_policy(&rid) .map_err(|err| error::Policy::FailedPolicy { rid, err })?; match entry.policy { Policy::Block => { @@ -30,7 +30,7 @@ impl Allowed { .follow_policies() .map_err(|err| error::Policy::FailedNodes { rid, err })?; let followed: HashSet<_> = nodes - .filter_map(|node| (node.policy == Policy::Allow).then_some(node.id)) + .filter_map(|node| (node.policy == Policy::Allow).then_some(node.nid)) .collect(); Ok(Allowed::Followed { remotes: followed }) @@ -64,7 +64,7 @@ impl BlockList { pub fn from_config(config: &Config) -> Result { Ok(config .follow_policies()? - .filter_map(|entry| (entry.policy == Policy::Block).then_some(entry.id)) + .filter_map(|entry| (entry.policy == Policy::Block).then_some(entry.nid)) .collect()) } } diff --git a/radicle-httpd/src/api/v1/node.rs b/radicle-httpd/src/api/v1/node.rs index 4f17e877..04a9e6de 100644 --- a/radicle-httpd/src/api/v1/node.rs +++ b/radicle-httpd/src/api/v1/node.rs @@ -58,7 +58,12 @@ async fn node_policies_repos_handler(State(ctx): State) -> impl IntoRes let policies = ctx.profile.policies()?; let mut repos = Vec::new(); - for policy::Repo { id, scope, policy } in policies.seed_policies()? { + for policy::SeedPolicy { + rid: id, + scope, + policy, + } in policies.seed_policies()? + { repos.push(json!({ "id": id, "scope": scope, diff --git a/radicle-node/src/service.rs b/radicle-node/src/service.rs index 97b373cc..8fbcb793 100644 --- a/radicle-node/src/service.rs +++ b/radicle-node/src/service.rs @@ -460,7 +460,7 @@ where self.filter = Filter::new( self.policies .seed_policies()? - .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)), + .filter_map(|t| (t.policy == Policy::Allow).then_some(t.rid)), ); Ok(updated) } @@ -598,7 +598,7 @@ where self.filter = Filter::new( self.policies .seed_policies()? - .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)), + .filter_map(|t| (t.policy == Policy::Allow).then_some(t.rid)), ); // Connect to configured peers. let addrs = self.config.connect.clone(); @@ -1331,7 +1331,7 @@ where } // TODO: Buffer/throttle fetches. - let repo_entry = self.policies.repo_policy(&message.rid).expect( + let repo_entry = self.policies.seed_policy(&message.rid).expect( "Service::handle_announcement: error accessing repo seeding configuration", ); @@ -2029,7 +2029,7 @@ where let missing = self .policies .seed_policies()? - .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)) + .filter_map(|t| (t.policy == Policy::Allow).then_some(t.rid)) .filter(|rid| !inventory.contains(rid)); for rid in missing { diff --git a/radicle-node/src/worker.rs b/radicle-node/src/worker.rs index 43210226..62083d7c 100644 --- a/radicle-node/src/worker.rs +++ b/radicle-node/src/worker.rs @@ -262,7 +262,7 @@ impl Worker { } fn is_authorized(&self, remote: NodeId, rid: RepoId) -> Result<(), UploadError> { - let policy = self.policies.repo_policy(&rid)?.policy; + let policy = self.policies.seed_policy(&rid)?.policy; let repo = self.storage.repository(rid)?; let doc = repo.canonical_identity_doc()?; if !doc.is_visible_to(&remote) || policy == Policy::Block { diff --git a/radicle/src/node/policy.rs b/radicle/src/node/policy.rs index 7156fe1c..22387aab 100644 --- a/radicle/src/node/policy.rs +++ b/radicle/src/node/policy.rs @@ -13,16 +13,16 @@ pub use super::{Alias, NodeId}; /// Repository seeding policy. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Repo { - pub id: RepoId, +pub struct SeedPolicy { + pub rid: RepoId, pub scope: Scope, pub policy: Policy, } /// Node following policy. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Node { - pub id: NodeId, +pub struct FollowPolicy { + pub nid: NodeId, pub alias: Option, pub policy: Policy, } diff --git a/radicle/src/node/policy/config.rs b/radicle/src/node/policy/config.rs index 291e7622..9e690a86 100644 --- a/radicle/src/node/policy/config.rs +++ b/radicle/src/node/policy/config.rs @@ -12,7 +12,7 @@ use crate::storage::{Namespaces, ReadRepository as _, ReadStorage, RepositoryErr pub use crate::node::policy::store; pub use crate::node::policy::store::Error; pub use crate::node::policy::store::Store; -pub use crate::node::policy::{Alias, Node, Policy, Repo, Scope}; +pub use crate::node::policy::{Alias, FollowPolicy, Policy, Scope, SeedPolicy}; #[derive(Debug, Error)] pub enum NamespacesError { @@ -75,32 +75,32 @@ impl Config { } /// Check if a repository is seeded. - pub fn is_seeding(&self, id: &RepoId) -> Result { - self.repo_policy(id) + pub fn is_seeding(&self, rid: &RepoId) -> Result { + self.seed_policy(rid) .map(|entry| entry.policy == Policy::Allow) } /// Check if a node is followed. - pub fn is_following(&self, id: &NodeId) -> Result { - self.node_policy(id) + pub fn is_following(&self, nid: &NodeId) -> Result { + self.follow_policy(nid) .map(|entry| entry.policy == Policy::Allow) } /// Get a node's following information. /// Returns the default policy if the node isn't found. - pub fn node_policy(&self, id: &NodeId) -> Result { - Ok(self.store.follow_policy(id)?.unwrap_or(Node { - id: *id, + pub fn follow_policy(&self, nid: &NodeId) -> Result { + Ok(self.store.follow_policy(nid)?.unwrap_or(FollowPolicy { + nid: *nid, alias: None, policy: self.policy, })) } - /// Get a repository's seediing information. + /// Get a repository's seeding information. /// Returns the default policy if the repo isn't found. - pub fn repo_policy(&self, id: &RepoId) -> Result { - Ok(self.store.seed_policy(id)?.unwrap_or(Repo { - id: *id, + pub fn seed_policy(&self, rid: &RepoId) -> Result { + Ok(self.store.seed_policy(rid)?.unwrap_or(SeedPolicy { + rid: *rid, scope: self.scope, policy: self.policy, })) @@ -117,7 +117,7 @@ impl Config { use NamespacesError::*; let entry = self - .repo_policy(rid) + .seed_policy(rid) .map_err(|err| FailedPolicy { rid: *rid, err })?; match entry.policy { Policy::Block => { @@ -131,7 +131,7 @@ impl Config { .follow_policies() .map_err(|err| FailedNodes { rid: *rid, err })?; let mut followed: HashSet<_> = nodes - .filter_map(|node| (node.policy == Policy::Allow).then_some(node.id)) + .filter_map(|node| (node.policy == Policy::Allow).then_some(node.nid)) .collect(); if let Ok(repo) = storage.repository(*rid) { diff --git a/radicle/src/node/policy/store.rs b/radicle/src/node/policy/store.rs index c5d18083..9a302aaf 100644 --- a/radicle/src/node/policy/store.rs +++ b/radicle/src/node/policy/store.rs @@ -9,7 +9,7 @@ use thiserror::Error; use crate::node::{Alias, AliasStore}; use crate::prelude::{NodeId, RepoId}; -use super::{Node, Policy, Repo, Scope}; +use super::{FollowPolicy, Policy, Scope, SeedPolicy}; /// 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(3); @@ -204,10 +204,10 @@ impl Store { /// `Config` can access these functions as well. impl Store { /// Check if a node is followed. - pub fn is_followed(&self, id: &NodeId) -> Result { + pub fn is_following(&self, id: &NodeId) -> Result { Ok(matches!( self.follow_policy(id)?, - Some(Node { + Some(FollowPolicy { policy: Policy::Allow, .. }) @@ -215,10 +215,10 @@ impl Store { } /// Check if a repository is seeded. - pub fn is_seeded(&self, id: &RepoId) -> Result { + pub fn is_seeding(&self, id: &RepoId) -> Result { Ok(matches!( self.seed_policy(id)?, - Some(Repo { + Some(SeedPolicy { policy: Policy::Allow, .. }) @@ -226,7 +226,7 @@ impl Store { } /// Get a node's follow policy. - pub fn follow_policy(&self, id: &NodeId) -> Result, Error> { + pub fn follow_policy(&self, id: &NodeId) -> Result, Error> { let mut stmt = self .db .prepare("SELECT alias, policy FROM `following` WHERE id = ?")?; @@ -242,8 +242,8 @@ impl Store { .and_then(|s| Alias::from_str(&s).ok()); let policy = row.read::("policy"); - return Ok(Some(Node { - id: *id, + return Ok(Some(FollowPolicy { + nid: *id, alias, policy, })); @@ -252,7 +252,7 @@ impl Store { } /// Get a repository's seeding policy. - pub fn seed_policy(&self, id: &RepoId) -> Result, Error> { + pub fn seed_policy(&self, id: &RepoId) -> Result, Error> { let mut stmt = self .db .prepare("SELECT scope, policy FROM `seeding` WHERE id = ?")?; @@ -260,8 +260,8 @@ impl Store { stmt.bind((1, id))?; if let Some(Ok(row)) = stmt.into_iter().next() { - return Ok(Some(Repo { - id: *id, + return Ok(Some(SeedPolicy { + rid: *id, scope: row.read::("scope"), policy: row.read::("policy"), })); @@ -270,7 +270,7 @@ impl Store { } /// Get node follow policies. - pub fn follow_policies(&self) -> Result>, Error> { + pub fn follow_policies(&self) -> Result>, Error> { let mut stmt = self .db .prepare("SELECT id, alias, policy FROM `following`")? @@ -287,14 +287,18 @@ impl Store { .and_then(|s| Alias::from_str(&s).ok()); let policy = row.read::("policy"); - entries.push(Node { id, alias, policy }); + entries.push(FollowPolicy { + nid: id, + alias, + policy, + }); } Ok(Box::new(entries.into_iter())) } // TODO: see if sql can return iterator directly /// Get repository seed policies. - pub fn seed_policies(&self) -> Result>, Error> { + pub fn seed_policies(&self) -> Result>, Error> { let mut stmt = self .db .prepare("SELECT id, scope, policy FROM `seeding`")? @@ -306,7 +310,11 @@ impl Store { let scope = row.read("scope"); let policy = row.read::("policy"); - entries.push(Repo { id, scope, policy }); + entries.push(SeedPolicy { + rid: id, + scope, + policy, + }); } Ok(Box::new(entries.into_iter())) } @@ -335,10 +343,10 @@ mod test { let mut db = Store::open(":memory:").unwrap(); assert!(db.follow(&id, Some("eve")).unwrap()); - assert!(db.is_followed(&id).unwrap()); + assert!(db.is_following(&id).unwrap()); assert!(!db.follow(&id, Some("eve")).unwrap()); assert!(db.unfollow(&id).unwrap()); - assert!(!db.is_followed(&id).unwrap()); + assert!(!db.is_following(&id).unwrap()); } #[test] @@ -347,10 +355,10 @@ mod test { let mut db = Store::open(":memory:").unwrap(); assert!(db.seed(&id, Scope::All).unwrap()); - assert!(db.is_seeded(&id).unwrap()); + assert!(db.is_seeding(&id).unwrap()); assert!(!db.seed(&id, Scope::All).unwrap()); assert!(db.unseed(&id).unwrap()); - assert!(!db.is_seeded(&id).unwrap()); + assert!(!db.is_seeding(&id).unwrap()); } #[test] @@ -362,9 +370,9 @@ mod test { assert!(db.follow(id, None).unwrap()); } let mut entries = db.follow_policies().unwrap(); - assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[0]); - assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[1]); - assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[2]); + assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[0]); + assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[1]); + assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[2]); } #[test] @@ -376,9 +384,9 @@ mod test { assert!(db.seed(id, Scope::All).unwrap()); } let mut entries = db.seed_policies().unwrap(); - assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[0]); - assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[1]); - assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[2]); + assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[0]); + assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[1]); + assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[2]); } #[test]