Fix code around default policies

Make the code a little clearer and ensure that we are always calling the
`Config` and not the `Store`, so that we fallback on the default policy.
This commit is contained in:
cloudhead 2024-01-25 12:03:47 +01:00
parent 7a5e5ec865
commit 131103cb53
No known key found for this signature in database
13 changed files with 100 additions and 75 deletions

View File

@ -166,9 +166,14 @@ pub fn following(profile: &Profile, alias: Option<Alias>) -> anyhow::Result<()>
fn push_policies( fn push_policies(
t: &mut Table<3, Paint<String>>, t: &mut Table<3, Paint<String>>,
aliases: &impl AliasStore, aliases: &impl AliasStore,
policies: impl Iterator<Item = policy::Node>, policies: impl Iterator<Item = policy::FollowPolicy>,
) { ) {
for policy::Node { id, alias, policy } in policies { for policy::FollowPolicy {
nid: id,
alias,
policy,
} in policies
{
t.push([ t.push([
term::format::highlight(Did::from(id).to_string()), term::format::highlight(Did::from(id).to_string()),
match alias { match alias {

View File

@ -172,22 +172,24 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
} }
} }
Target::Policy => { Target::Policy => {
let tracking = profile.policies()?; let policies = profile.policies()?;
if let Some(repo) = tracking.seed_policy(&rid)? { let seed = policies.seed_policy(&rid)?;
let tracking = match repo.policy { match seed.policy {
Policy::Allow => term::format::positive("tracked"), Policy::Allow => {
Policy::Block => term::format::negative("blocked"), println!(
}; "Repository {} is {} with scope {}",
println!( term::format::tertiary(&rid),
"Repository {} is {} with scope {}", term::format::positive("being seeded"),
term::format::tertiary(&rid), term::format::dim(format!("`{}`", seed.scope))
tracking, );
term::format::dim(format!("`{}`", repo.scope)) }
); Policy::Block => {
} else { println!(
term::print(term::format::italic(format!( "Repository {} is {}",
"No tracking policy found for {rid}" term::format::tertiary(&rid),
))); term::format::negative("not being seeded"),
);
}
} }
} }
Target::Delegates => { Target::Delegates => {

View File

@ -106,7 +106,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
if refs.is_none() && !options.all { if refs.is_none() && !options.all {
continue; continue;
} }
let seeded = policy.is_seeded(&rid)?; let seeded = policy.is_seeding(&rid)?;
if !seeded && !options.all { if !seeded && !options.all {
continue; continue;
@ -120,7 +120,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
if seeded { if seeded {
term::format::visibility(&doc.visibility).into() term::format::visibility(&doc.visibility).into()
} else { } else {
term::format::tertiary("local").into() term::format::dim("local").into()
}, },
term::format::secondary(head), term::format::secondary(head),
term::format::italic(proj.description().to_owned()), term::format::italic(proj.description().to_owned()),

View File

@ -25,7 +25,7 @@ pub fn run(
if sync { if sync {
let mut node = radicle::Node::new(profile.socket()); 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()); let alias = name.as_ref().and_then(|n| Alias::from_str(n.as_str()).ok());
follow::follow(*nid, alias, &mut node, profile)?; follow::follow(*nid, alias, &mut node, profile)?;

View File

@ -183,7 +183,12 @@ pub fn seeding(profile: &Profile) -> anyhow::Result<()> {
]); ]);
t.divider(); 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 id = id.to_string();
let scope = scope.to_string(); let scope = scope.to_string();
let policy = policy.to_string(); let policy = policy.to_string();

View File

@ -281,7 +281,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
} }
Operation::Synchronize(SyncMode::Repo { mode, direction }) => { Operation::Synchronize(SyncMode::Repo { mode, direction }) => {
if [SyncDirection::Fetch, SyncDirection::Both].contains(&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"); anyhow::bail!("repository {rid} is not seeded");
} }
let results = fetch(rid, mode.clone(), options.timeout, &mut node)?; let results = fetch(rid, mode.clone(), options.timeout, &mut node)?;

View File

@ -16,7 +16,7 @@ pub enum Allowed {
impl Allowed { impl Allowed {
pub fn from_config(rid: RepoId, config: &Config<Read>) -> Result<Self, error::Policy> { pub fn from_config(rid: RepoId, config: &Config<Read>) -> Result<Self, error::Policy> {
let entry = config let entry = config
.repo_policy(&rid) .seed_policy(&rid)
.map_err(|err| error::Policy::FailedPolicy { rid, err })?; .map_err(|err| error::Policy::FailedPolicy { rid, err })?;
match entry.policy { match entry.policy {
Policy::Block => { Policy::Block => {
@ -30,7 +30,7 @@ impl Allowed {
.follow_policies() .follow_policies()
.map_err(|err| error::Policy::FailedNodes { rid, err })?; .map_err(|err| error::Policy::FailedNodes { rid, err })?;
let followed: HashSet<_> = nodes 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(); .collect();
Ok(Allowed::Followed { remotes: followed }) Ok(Allowed::Followed { remotes: followed })
@ -64,7 +64,7 @@ impl BlockList {
pub fn from_config(config: &Config<Read>) -> Result<BlockList, error::Blocked> { pub fn from_config(config: &Config<Read>) -> Result<BlockList, error::Blocked> {
Ok(config Ok(config
.follow_policies()? .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()) .collect())
} }
} }

View File

@ -58,7 +58,12 @@ async fn node_policies_repos_handler(State(ctx): State<Context>) -> impl IntoRes
let policies = ctx.profile.policies()?; let policies = ctx.profile.policies()?;
let mut repos = Vec::new(); 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!({ repos.push(json!({
"id": id, "id": id,
"scope": scope, "scope": scope,

View File

@ -460,7 +460,7 @@ where
self.filter = Filter::new( self.filter = Filter::new(
self.policies self.policies
.seed_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) Ok(updated)
} }
@ -598,7 +598,7 @@ where
self.filter = Filter::new( self.filter = Filter::new(
self.policies self.policies
.seed_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. // Connect to configured peers.
let addrs = self.config.connect.clone(); let addrs = self.config.connect.clone();
@ -1331,7 +1331,7 @@ where
} }
// TODO: Buffer/throttle fetches. // 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", "Service::handle_announcement: error accessing repo seeding configuration",
); );
@ -2029,7 +2029,7 @@ where
let missing = self let missing = self
.policies .policies
.seed_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)); .filter(|rid| !inventory.contains(rid));
for rid in missing { for rid in missing {

View File

@ -262,7 +262,7 @@ impl Worker {
} }
fn is_authorized(&self, remote: NodeId, rid: RepoId) -> Result<(), UploadError> { 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 repo = self.storage.repository(rid)?;
let doc = repo.canonical_identity_doc()?; let doc = repo.canonical_identity_doc()?;
if !doc.is_visible_to(&remote) || policy == Policy::Block { if !doc.is_visible_to(&remote) || policy == Policy::Block {

View File

@ -13,16 +13,16 @@ pub use super::{Alias, NodeId};
/// Repository seeding policy. /// Repository seeding policy.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Repo { pub struct SeedPolicy {
pub id: RepoId, pub rid: RepoId,
pub scope: Scope, pub scope: Scope,
pub policy: Policy, pub policy: Policy,
} }
/// Node following policy. /// Node following policy.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Node { pub struct FollowPolicy {
pub id: NodeId, pub nid: NodeId,
pub alias: Option<Alias>, pub alias: Option<Alias>,
pub policy: Policy, pub policy: Policy,
} }

View File

@ -12,7 +12,7 @@ use crate::storage::{Namespaces, ReadRepository as _, ReadStorage, RepositoryErr
pub use crate::node::policy::store; pub use crate::node::policy::store;
pub use crate::node::policy::store::Error; pub use crate::node::policy::store::Error;
pub use crate::node::policy::store::Store; 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)] #[derive(Debug, Error)]
pub enum NamespacesError { pub enum NamespacesError {
@ -75,32 +75,32 @@ impl<T> Config<T> {
} }
/// Check if a repository is seeded. /// Check if a repository is seeded.
pub fn is_seeding(&self, id: &RepoId) -> Result<bool, Error> { pub fn is_seeding(&self, rid: &RepoId) -> Result<bool, Error> {
self.repo_policy(id) self.seed_policy(rid)
.map(|entry| entry.policy == Policy::Allow) .map(|entry| entry.policy == Policy::Allow)
} }
/// Check if a node is followed. /// Check if a node is followed.
pub fn is_following(&self, id: &NodeId) -> Result<bool, Error> { pub fn is_following(&self, nid: &NodeId) -> Result<bool, Error> {
self.node_policy(id) self.follow_policy(nid)
.map(|entry| entry.policy == Policy::Allow) .map(|entry| entry.policy == Policy::Allow)
} }
/// Get a node's following information. /// Get a node's following information.
/// Returns the default policy if the node isn't found. /// Returns the default policy if the node isn't found.
pub fn node_policy(&self, id: &NodeId) -> Result<Node, Error> { pub fn follow_policy(&self, nid: &NodeId) -> Result<FollowPolicy, Error> {
Ok(self.store.follow_policy(id)?.unwrap_or(Node { Ok(self.store.follow_policy(nid)?.unwrap_or(FollowPolicy {
id: *id, nid: *nid,
alias: None, alias: None,
policy: self.policy, 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. /// Returns the default policy if the repo isn't found.
pub fn repo_policy(&self, id: &RepoId) -> Result<Repo, Error> { pub fn seed_policy(&self, rid: &RepoId) -> Result<SeedPolicy, Error> {
Ok(self.store.seed_policy(id)?.unwrap_or(Repo { Ok(self.store.seed_policy(rid)?.unwrap_or(SeedPolicy {
id: *id, rid: *rid,
scope: self.scope, scope: self.scope,
policy: self.policy, policy: self.policy,
})) }))
@ -117,7 +117,7 @@ impl<T> Config<T> {
use NamespacesError::*; use NamespacesError::*;
let entry = self let entry = self
.repo_policy(rid) .seed_policy(rid)
.map_err(|err| FailedPolicy { rid: *rid, err })?; .map_err(|err| FailedPolicy { rid: *rid, err })?;
match entry.policy { match entry.policy {
Policy::Block => { Policy::Block => {
@ -131,7 +131,7 @@ impl<T> Config<T> {
.follow_policies() .follow_policies()
.map_err(|err| FailedNodes { rid: *rid, err })?; .map_err(|err| FailedNodes { rid: *rid, err })?;
let mut followed: HashSet<_> = nodes 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(); .collect();
if let Ok(repo) = storage.repository(*rid) { if let Ok(repo) = storage.repository(*rid) {

View File

@ -9,7 +9,7 @@ use thiserror::Error;
use crate::node::{Alias, AliasStore}; use crate::node::{Alias, AliasStore};
use crate::prelude::{NodeId, RepoId}; 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. /// 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); const DB_READ_TIMEOUT: time::Duration = time::Duration::from_secs(3);
@ -204,10 +204,10 @@ impl Store<Write> {
/// `Config<Write>` can access these functions as well. /// `Config<Write>` can access these functions as well.
impl<T> Store<T> { impl<T> Store<T> {
/// Check if a node is followed. /// Check if a node is followed.
pub fn is_followed(&self, id: &NodeId) -> Result<bool, Error> { pub fn is_following(&self, id: &NodeId) -> Result<bool, Error> {
Ok(matches!( Ok(matches!(
self.follow_policy(id)?, self.follow_policy(id)?,
Some(Node { Some(FollowPolicy {
policy: Policy::Allow, policy: Policy::Allow,
.. ..
}) })
@ -215,10 +215,10 @@ impl<T> Store<T> {
} }
/// Check if a repository is seeded. /// Check if a repository is seeded.
pub fn is_seeded(&self, id: &RepoId) -> Result<bool, Error> { pub fn is_seeding(&self, id: &RepoId) -> Result<bool, Error> {
Ok(matches!( Ok(matches!(
self.seed_policy(id)?, self.seed_policy(id)?,
Some(Repo { Some(SeedPolicy {
policy: Policy::Allow, policy: Policy::Allow,
.. ..
}) })
@ -226,7 +226,7 @@ impl<T> Store<T> {
} }
/// Get a node's follow policy. /// Get a node's follow policy.
pub fn follow_policy(&self, id: &NodeId) -> Result<Option<Node>, Error> { pub fn follow_policy(&self, id: &NodeId) -> Result<Option<FollowPolicy>, Error> {
let mut stmt = self let mut stmt = self
.db .db
.prepare("SELECT alias, policy FROM `following` WHERE id = ?")?; .prepare("SELECT alias, policy FROM `following` WHERE id = ?")?;
@ -242,8 +242,8 @@ impl<T> Store<T> {
.and_then(|s| Alias::from_str(&s).ok()); .and_then(|s| Alias::from_str(&s).ok());
let policy = row.read::<Policy, _>("policy"); let policy = row.read::<Policy, _>("policy");
return Ok(Some(Node { return Ok(Some(FollowPolicy {
id: *id, nid: *id,
alias, alias,
policy, policy,
})); }));
@ -252,7 +252,7 @@ impl<T> Store<T> {
} }
/// Get a repository's seeding policy. /// Get a repository's seeding policy.
pub fn seed_policy(&self, id: &RepoId) -> Result<Option<Repo>, Error> { pub fn seed_policy(&self, id: &RepoId) -> Result<Option<SeedPolicy>, Error> {
let mut stmt = self let mut stmt = self
.db .db
.prepare("SELECT scope, policy FROM `seeding` WHERE id = ?")?; .prepare("SELECT scope, policy FROM `seeding` WHERE id = ?")?;
@ -260,8 +260,8 @@ impl<T> Store<T> {
stmt.bind((1, id))?; stmt.bind((1, id))?;
if let Some(Ok(row)) = stmt.into_iter().next() { if let Some(Ok(row)) = stmt.into_iter().next() {
return Ok(Some(Repo { return Ok(Some(SeedPolicy {
id: *id, rid: *id,
scope: row.read::<Scope, _>("scope"), scope: row.read::<Scope, _>("scope"),
policy: row.read::<Policy, _>("policy"), policy: row.read::<Policy, _>("policy"),
})); }));
@ -270,7 +270,7 @@ impl<T> Store<T> {
} }
/// Get node follow policies. /// Get node follow policies.
pub fn follow_policies(&self) -> Result<Box<dyn Iterator<Item = Node>>, Error> { pub fn follow_policies(&self) -> Result<Box<dyn Iterator<Item = FollowPolicy>>, Error> {
let mut stmt = self let mut stmt = self
.db .db
.prepare("SELECT id, alias, policy FROM `following`")? .prepare("SELECT id, alias, policy FROM `following`")?
@ -287,14 +287,18 @@ impl<T> Store<T> {
.and_then(|s| Alias::from_str(&s).ok()); .and_then(|s| Alias::from_str(&s).ok());
let policy = row.read::<Policy, _>("policy"); let policy = row.read::<Policy, _>("policy");
entries.push(Node { id, alias, policy }); entries.push(FollowPolicy {
nid: id,
alias,
policy,
});
} }
Ok(Box::new(entries.into_iter())) Ok(Box::new(entries.into_iter()))
} }
// TODO: see if sql can return iterator directly // TODO: see if sql can return iterator directly
/// Get repository seed policies. /// Get repository seed policies.
pub fn seed_policies(&self) -> Result<Box<dyn Iterator<Item = Repo>>, Error> { pub fn seed_policies(&self) -> Result<Box<dyn Iterator<Item = SeedPolicy>>, Error> {
let mut stmt = self let mut stmt = self
.db .db
.prepare("SELECT id, scope, policy FROM `seeding`")? .prepare("SELECT id, scope, policy FROM `seeding`")?
@ -306,7 +310,11 @@ impl<T> Store<T> {
let scope = row.read("scope"); let scope = row.read("scope");
let policy = row.read::<Policy, _>("policy"); let policy = row.read::<Policy, _>("policy");
entries.push(Repo { id, scope, policy }); entries.push(SeedPolicy {
rid: id,
scope,
policy,
});
} }
Ok(Box::new(entries.into_iter())) Ok(Box::new(entries.into_iter()))
} }
@ -335,10 +343,10 @@ mod test {
let mut db = Store::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.follow(&id, Some("eve")).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.follow(&id, Some("eve")).unwrap());
assert!(db.unfollow(&id).unwrap()); assert!(db.unfollow(&id).unwrap());
assert!(!db.is_followed(&id).unwrap()); assert!(!db.is_following(&id).unwrap());
} }
#[test] #[test]
@ -347,10 +355,10 @@ mod test {
let mut db = Store::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.seed(&id, Scope::All).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.seed(&id, Scope::All).unwrap());
assert!(db.unseed(&id).unwrap()); assert!(db.unseed(&id).unwrap());
assert!(!db.is_seeded(&id).unwrap()); assert!(!db.is_seeding(&id).unwrap());
} }
#[test] #[test]
@ -362,9 +370,9 @@ mod test {
assert!(db.follow(id, None).unwrap()); assert!(db.follow(id, None).unwrap());
} }
let mut entries = db.follow_policies().unwrap(); let mut entries = db.follow_policies().unwrap();
assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[0]); assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[0]);
assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[1]); assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[1]);
assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[2]); assert_matches!(entries.next(), Some(FollowPolicy { nid, .. }) if nid == ids[2]);
} }
#[test] #[test]
@ -376,9 +384,9 @@ mod test {
assert!(db.seed(id, Scope::All).unwrap()); assert!(db.seed(id, Scope::All).unwrap());
} }
let mut entries = db.seed_policies().unwrap(); let mut entries = db.seed_policies().unwrap();
assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[0]); assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[0]);
assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[1]); assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[1]);
assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[2]); assert_matches!(entries.next(), Some(SeedPolicy { rid, .. }) if rid == ids[2]);
} }
#[test] #[test]