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(
t: &mut Table<3, Paint<String>>,
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([
term::format::highlight(Did::from(id).to_string()),
match alias {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ pub enum Allowed {
impl Allowed {
pub fn from_config(rid: RepoId, config: &Config<Read>) -> Result<Self, error::Policy> {
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<Read>) -> Result<BlockList, error::Blocked> {
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())
}
}

View File

@ -58,7 +58,12 @@ async fn node_policies_repos_handler(State(ctx): State<Context>) -> 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,

View File

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

View File

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

View File

@ -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<Alias>,
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::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<T> Config<T> {
}
/// Check if a repository is seeded.
pub fn is_seeding(&self, id: &RepoId) -> Result<bool, Error> {
self.repo_policy(id)
pub fn is_seeding(&self, rid: &RepoId) -> Result<bool, Error> {
self.seed_policy(rid)
.map(|entry| entry.policy == Policy::Allow)
}
/// Check if a node is followed.
pub fn is_following(&self, id: &NodeId) -> Result<bool, Error> {
self.node_policy(id)
pub fn is_following(&self, nid: &NodeId) -> Result<bool, Error> {
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<Node, Error> {
Ok(self.store.follow_policy(id)?.unwrap_or(Node {
id: *id,
pub fn follow_policy(&self, nid: &NodeId) -> Result<FollowPolicy, Error> {
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<Repo, Error> {
Ok(self.store.seed_policy(id)?.unwrap_or(Repo {
id: *id,
pub fn seed_policy(&self, rid: &RepoId) -> Result<SeedPolicy, Error> {
Ok(self.store.seed_policy(rid)?.unwrap_or(SeedPolicy {
rid: *rid,
scope: self.scope,
policy: self.policy,
}))
@ -117,7 +117,7 @@ impl<T> Config<T> {
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<T> Config<T> {
.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) {

View File

@ -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<Write> {
/// `Config<Write>` can access these functions as well.
impl<T> Store<T> {
/// 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!(
self.follow_policy(id)?,
Some(Node {
Some(FollowPolicy {
policy: Policy::Allow,
..
})
@ -215,10 +215,10 @@ impl<T> Store<T> {
}
/// 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!(
self.seed_policy(id)?,
Some(Repo {
Some(SeedPolicy {
policy: Policy::Allow,
..
})
@ -226,7 +226,7 @@ impl<T> Store<T> {
}
/// 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
.db
.prepare("SELECT alias, policy FROM `following` WHERE id = ?")?;
@ -242,8 +242,8 @@ impl<T> Store<T> {
.and_then(|s| Alias::from_str(&s).ok());
let policy = row.read::<Policy, _>("policy");
return Ok(Some(Node {
id: *id,
return Ok(Some(FollowPolicy {
nid: *id,
alias,
policy,
}));
@ -252,7 +252,7 @@ impl<T> Store<T> {
}
/// 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
.db
.prepare("SELECT scope, policy FROM `seeding` WHERE id = ?")?;
@ -260,8 +260,8 @@ impl<T> Store<T> {
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, _>("scope"),
policy: row.read::<Policy, _>("policy"),
}));
@ -270,7 +270,7 @@ impl<T> Store<T> {
}
/// 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
.db
.prepare("SELECT id, alias, policy FROM `following`")?
@ -287,14 +287,18 @@ impl<T> Store<T> {
.and_then(|s| Alias::from_str(&s).ok());
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()))
}
// TODO: see if sql can return iterator directly
/// 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
.db
.prepare("SELECT id, scope, policy FROM `seeding`")?
@ -306,7 +310,11 @@ impl<T> Store<T> {
let scope = row.read("scope");
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()))
}
@ -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]