radicle: Rename many more methods using new naming

This commit is contained in:
cloudhead 2023-12-01 13:56:04 +01:00
parent 1b026ae0ee
commit 6ca7da2768
No known key found for this signature in database
41 changed files with 383 additions and 400 deletions

View File

@ -1,12 +1,13 @@
To configure our node's tracking policy, we can use the `rad track` command. To configure our node's seeding and follow policy, we can use the `rad seed`
For example, let's track a remote node we know about, and alias it to "eve": and `rad follow` commands.
For example, let's follow a remote node we know about, and alias it to "eve":
``` ```
$ rad follow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias eve $ rad follow did:key:z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk --alias eve
✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (eve) ✓ Follow policy updated for z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk (eve)
``` ```
Now let's track one of Eve's repositories: Now let's seed one of Eve's repositories:
``` ```
$ rad seed rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope followed --no-fetch $ rad seed rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji --scope followed --no-fetch

View File

@ -22,7 +22,7 @@ Usage
local operator or a delegate of the repository. local operator or a delegate of the repository.
Note that remotes will still be fetched as long as they are Note that remotes will still be fetched as long as they are
tracked and/or the tracking scope is "all". followed and/or the follow scope is "all".
Options Options

View File

@ -100,8 +100,8 @@ pub fn follow(
let followed = match node.follow(nid, alias.clone()) { let followed = match node.follow(nid, alias.clone()) {
Ok(updated) => updated, Ok(updated) => updated,
Err(e) if e.is_connection_err() => { Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?; let mut config = profile.policies_mut()?;
config.track_node(&nid, alias.as_deref())? config.follow(&nid, alias.as_deref())?
} }
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };

View File

@ -60,7 +60,7 @@ pub struct Options {
pub scope: Scope, pub scope: Scope,
pub set_upstream: bool, pub set_upstream: bool,
pub verbose: bool, pub verbose: bool,
pub track: bool, pub seed: bool,
} }
impl Args for Options { impl Args for Options {
@ -77,7 +77,7 @@ impl Args for Options {
let mut set_upstream = false; let mut set_upstream = false;
let mut setup_signing = false; let mut setup_signing = false;
let mut scope = Scope::All; let mut scope = Scope::All;
let mut track = true; let mut seed = true;
let mut verbose = false; let mut verbose = false;
let mut visibility = None; let mut visibility = None;
@ -129,8 +129,8 @@ impl Args for Options {
Long("no-confirm") => { Long("no-confirm") => {
interactive = Interactive::No; interactive = Interactive::No;
} }
Long("no-track") => { Long("no-seed") => {
track = false; seed = false;
} }
Long("private") => { Long("private") => {
visibility = Some(Visibility::private([])); visibility = Some(Visibility::private([]));
@ -161,7 +161,7 @@ impl Args for Options {
interactive, interactive,
set_upstream, set_upstream,
setup_signing, setup_signing,
track, seed,
visibility, visibility,
verbose, verbose,
}, },
@ -279,10 +279,10 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
term::blob(json::to_string_pretty(&proj)?); term::blob(json::to_string_pretty(&proj)?);
} }
// It's important to track our own repositories to make sure that our node signals // It's important to seed our own repositories to make sure that our node signals
// interest for them. This ensures that messages relating to them are relayed to us. // interest for them. This ensures that messages relating to them are relayed to us.
if options.track { if options.seed {
cli::project::track(id, options.scope, &mut node, profile)?; cli::project::seed(id, options.scope, &mut node, profile)?;
} }
if options.set_upstream || git::branch_remote(&repo, proj.default_branch()).is_err() { if options.set_upstream || git::branch_remote(&repo, proj.default_branch()).is_err() {

View File

@ -173,8 +173,8 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
} }
} }
Target::Policy => { Target::Policy => {
let tracking = profile.tracking()?; let tracking = profile.policies()?;
if let Some(repo) = tracking.repo_policy(&rid)? { if let Some(repo) = tracking.seed_policy(&rid)? {
let tracking = match repo.policy { let tracking = match repo.policy {
Policy::Allow => term::format::positive("tracked"), Policy::Allow => term::format::positive("tracked"),
Policy::Block => term::format::negative("blocked"), Policy::Block => term::format::negative("blocked"),

View File

@ -17,7 +17,7 @@ Usage
rad ls [<option>...] rad ls [<option>...]
By default, this command shows you all repositories that you have forked or initialized. By default, this command shows you all repositories that you have forked or initialized.
If you wish to see all tracked repositories, use the `--all` option. If you wish to see all seeded repositories, use the `--all` option.
Options Options

View File

@ -7,7 +7,7 @@ use crate::terminal as term;
use term::Element; use term::Element;
pub fn seeding(profile: &Profile) -> anyhow::Result<()> { pub fn seeding(profile: &Profile) -> anyhow::Result<()> {
let store = profile.tracking()?; let store = profile.policies()?;
let mut t = term::Table::new(term::table::TableOptions::bordered()); let mut t = term::Table::new(term::table::TableOptions::bordered());
t.push([ t.push([
term::format::default(String::from("RID")), term::format::default(String::from("RID")),
@ -16,7 +16,7 @@ pub fn seeding(profile: &Profile) -> anyhow::Result<()> {
]); ]);
t.divider(); t.divider();
for policy::Repo { id, scope, policy } in store.repo_policies()? { for policy::Repo { 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();
@ -33,7 +33,7 @@ pub fn seeding(profile: &Profile) -> anyhow::Result<()> {
} }
pub fn following(profile: &Profile) -> anyhow::Result<()> { pub fn following(profile: &Profile) -> anyhow::Result<()> {
let store = profile.tracking()?; let store = profile.policies()?;
let aliases = profile.aliases(); let aliases = profile.aliases();
let mut t = term::Table::new(term::table::TableOptions::bordered()); let mut t = term::Table::new(term::table::TableOptions::bordered());
t.push([ t.push([
@ -43,7 +43,7 @@ pub fn following(profile: &Profile) -> anyhow::Result<()> {
]); ]);
t.divider(); t.divider();
for policy::Node { id, alias, policy } in store.node_policies()? { for policy::Node { id, alias, policy } in store.follow_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

@ -23,7 +23,7 @@ fn get_branch(git_ref: git::Qualified) -> git::RefString {
std::iter::once(head).chain(tail).collect() std::iter::once(head).chain(tail).collect()
} }
/// Determine the merge target for this patch. This can be any tracked remote's "default" branch, /// Determine the merge target for this patch. This can be any followed remote's "default" branch,
/// as well as your own (eg. `rad/master`). /// as well as your own (eg. `rad/master`).
pub fn get_merge_target( pub fn get_merge_target(
storage: &Repository, storage: &Repository,

View File

@ -131,7 +131,7 @@ pub fn update(
node: &mut Node, node: &mut Node,
profile: &Profile, profile: &Profile,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let updated = project::track(rid, scope, node, profile)?; let updated = project::seed(rid, scope, node, profile)?;
let outcome = if updated { "updated" } else { "exists" }; let outcome = if updated { "updated" } else { "exists" };
term::success!( term::success!(
@ -143,7 +143,7 @@ pub fn update(
} }
pub fn delete(rid: Id, node: &mut Node, profile: &Profile) -> anyhow::Result<()> { pub fn delete(rid: Id, node: &mut Node, profile: &Profile) -> anyhow::Result<()> {
if project::untrack(rid, node, profile)? { if project::unseed(rid, node, profile)? {
term::success!("Seeding policy for {} removed", term::format::tertiary(rid)); term::success!("Seeding policy for {} removed", term::format::tertiary(rid));
} }
Ok(()) Ok(())

View File

@ -279,8 +279,8 @@ 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.tracking()?.is_repo_tracked(&rid)? { if !profile.policies()?.is_repo_seeded(&rid)? {
anyhow::bail!("repository {rid} is not tracked"); 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)?;
let success = results.success().count(); let success = results.success().count();

View File

@ -79,8 +79,8 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
let unfollowed = match node.unfollow(nid) { let unfollowed = match node.unfollow(nid) {
Ok(updated) => updated, Ok(updated) => updated,
Err(e) if e.is_connection_err() => { Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?; let mut config = profile.policies_mut()?;
config.untrack_node(&nid)? config.unfollow(&nid)?
} }
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };

View File

@ -52,9 +52,9 @@ impl<'a> SetupRemote<'a> {
} }
} }
/// Track a repository by first trying to track through the node, and if the node isn't running, /// Seed a repository by first trying to seed through the node, and if the node isn't running,
/// by updating the tracking database directly. /// by updating the policy database directly.
pub fn track( pub fn seed(
rid: Id, rid: Id,
scope: Scope, scope: Scope,
node: &mut Node, node: &mut Node,
@ -63,21 +63,21 @@ pub fn track(
match node.seed(rid, scope) { match node.seed(rid, scope) {
Ok(updated) => Ok(updated), Ok(updated) => Ok(updated),
Err(e) if e.is_connection_err() => { Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?; let mut config = profile.policies_mut()?;
config.track_repo(&rid, scope).map_err(|e| e.into()) config.seed(&rid, scope).map_err(|e| e.into())
} }
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
} }
} }
/// Untrack a repository by first trying to untrack through the node, and if the node isn't running, /// Unseed a repository by first trying to unseed through the node, and if the node isn't running,
/// by updating the tracking database directly. /// by updating the policy database directly.
pub fn untrack(rid: Id, node: &mut Node, profile: &Profile) -> Result<bool, anyhow::Error> { pub fn unseed(rid: Id, node: &mut Node, profile: &Profile) -> Result<bool, anyhow::Error> {
match node.unseed(rid) { match node.unseed(rid) {
Ok(updated) => Ok(updated), Ok(updated) => Ok(updated),
Err(e) if e.is_connection_err() => { Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?; let mut config = profile.policies_mut()?;
config.untrack_repo(&rid).map_err(|e| e.into()) config.unseed(&rid).map_err(|e| e.into())
} }
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
} }

View File

@ -741,14 +741,14 @@ fn rad_clean() {
} }
#[test] #[test]
fn rad_track() { fn rad_seed_and_follow() {
let mut environment = Environment::new(); let mut environment = Environment::new();
let alice = environment.node(Config::test(Alias::new("alice"))); let alice = environment.node(Config::test(Alias::new("alice")));
let working = tempfile::tempdir().unwrap(); let working = tempfile::tempdir().unwrap();
let alice = alice.spawn(); let alice = alice.spawn();
test( test(
"examples/rad-track.md", "examples/rad-seed-and-follow.md",
working.path(), working.path(),
Some(&alice.home), Some(&alice.home),
[], [],
@ -897,7 +897,7 @@ fn rad_sync_without_node() {
let mut eve = environment.node(Config::test(Alias::new("eve"))); let mut eve = environment.node(Config::test(Alias::new("eve")));
let rid = Id::from_urn("rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5").unwrap(); let rid = Id::from_urn("rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5").unwrap();
eve.tracking.track_repo(&rid, Scope::All).unwrap(); eve.policies.seed(&rid, Scope::All).unwrap();
formula(&environment.tmp(), "examples/rad-sync-without-node.md") formula(&environment.tmp(), "examples/rad-sync-without-node.md")
.unwrap() .unwrap()

View File

@ -9,14 +9,14 @@ use radicle::prelude::Doc;
use radicle::storage::git::Repository; use radicle::storage::git::Repository;
use radicle::storage::ReadRepository; use radicle::storage::ReadRepository;
use crate::tracking::{BlockList, Tracked}; use crate::policy::{Allowed, BlockList};
use crate::transport::{ConnectionStream, Transport}; use crate::transport::{ConnectionStream, Transport};
/// The handle used for pulling or cloning changes from a remote peer. /// The handle used for pulling or cloning changes from a remote peer.
pub struct Handle<S> { pub struct Handle<S> {
pub(crate) local: PublicKey, pub(crate) local: PublicKey,
pub(crate) repo: Repository, pub(crate) repo: Repository,
pub(crate) tracked: Tracked, pub(crate) allowed: Allowed,
pub(crate) transport: Transport<S>, pub(crate) transport: Transport<S>,
/// The set of keys we will ignore when fetching from a /// The set of keys we will ignore when fetching from a
/// remote. This set can be constructed using the tracking /// remote. This set can be constructed using the tracking
@ -34,7 +34,7 @@ impl<S> Handle<S> {
pub fn new( pub fn new(
local: PublicKey, local: PublicKey,
repo: Repository, repo: Repository,
tracked: Tracked, follow: Allowed,
blocked: BlockList, blocked: BlockList,
connection: S, connection: S,
) -> Result<Self, error::Init> ) -> Result<Self, error::Init>
@ -47,7 +47,7 @@ impl<S> Handle<S> {
Ok(Self { Ok(Self {
local, local,
repo, repo,
tracked, allowed: follow,
transport, transport,
blocked, blocked,
interrupt: Arc::new(AtomicBool::new(false)), interrupt: Arc::new(AtomicBool::new(false)),
@ -78,8 +78,8 @@ impl<S> Handle<S> {
Ok(self.repo.identity_doc_at(head)?.doc) Ok(self.repo.identity_doc_at(head)?.doc)
} }
pub fn tracked(&self) -> Tracked { pub fn allowed(&self) -> Allowed {
self.tracked.clone() self.allowed.clone()
} }
} }
@ -101,13 +101,13 @@ pub mod error {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Tracking { pub enum Tracking {
#[error("failed to find tracking policy for {rid}")] #[error("failed to find policy for {rid}")]
FailedPolicy { FailedPolicy {
rid: Id, rid: Id,
#[source] #[source]
err: policy::store::Error, err: policy::store::Error,
}, },
#[error("cannot fetch {rid} as it is not tracked")] #[error("cannot fetch {rid} as it is not seeded")]
BlockedPolicy { rid: Id }, BlockedPolicy { rid: Id },
#[error("failed to get tracking nodes for {rid}")] #[error("failed to get tracking nodes for {rid}")]
FailedNodes { FailedNodes {

View File

@ -1,6 +1,6 @@
pub mod git; pub mod git;
pub mod handle; pub mod handle;
pub mod tracking; pub mod policy;
pub mod transport; pub mod transport;
pub(crate) mod sigrefs; pub(crate) mod sigrefs;
@ -10,8 +10,8 @@ mod stage;
mod state; mod state;
pub use handle::Handle; pub use handle::Handle;
pub use policy::{Allowed, BlockList, Scope};
pub use state::{FetchLimit, FetchResult}; pub use state::{FetchLimit, FetchResult};
pub use tracking::{BlockList, Scope, Tracked};
pub use transport::Transport; pub use transport::Transport;
use std::io; use std::io;

View File

@ -8,32 +8,32 @@ use radicle::prelude::Id;
pub use radicle::node::policy::{Policy, Scope}; pub use radicle::node::policy::{Policy, Scope};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Tracked { pub enum Allowed {
All, All,
Followed { remotes: HashSet<PublicKey> }, Followed { remotes: HashSet<PublicKey> },
} }
impl Tracked { impl Allowed {
pub fn from_config(rid: Id, config: &Config<Read>) -> Result<Self, error::Tracking> { pub fn from_config(rid: Id, config: &Config<Read>) -> Result<Self, error::Policy> {
let entry = config let entry = config
.repo_policy(&rid) .repo_policy(&rid)
.map_err(|err| error::Tracking::FailedPolicy { rid, err })?; .map_err(|err| error::Policy::FailedPolicy { rid, err })?;
match entry.policy { match entry.policy {
Policy::Block => { Policy::Block => {
log::error!(target: "fetch", "Attempted to fetch untracked repo {rid}"); log::error!(target: "fetch", "Attempted to fetch non-seeded repo {rid}");
Err(error::Tracking::BlockedPolicy { rid }) Err(error::Policy::BlockedPolicy { rid })
} }
Policy::Allow => match entry.scope { Policy::Allow => match entry.scope {
Scope::All => Ok(Self::All), Scope::All => Ok(Self::All),
Scope::Followed => { Scope::Followed => {
let nodes = config let nodes = config
.node_policies() .follow_policies()
.map_err(|err| error::Tracking::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.id))
.collect(); .collect();
Ok(Tracked::Followed { remotes: followed }) Ok(Allowed::Followed { remotes: followed })
} }
}, },
} }
@ -63,7 +63,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
.node_policies()? .follow_policies()?
.filter_map(|entry| (entry.policy == Policy::Block).then_some(entry.id)) .filter_map(|entry| (entry.policy == Policy::Block).then_some(entry.id))
.collect()) .collect())
} }
@ -80,16 +80,16 @@ pub mod error {
pub struct Blocked(#[from] policy::config::Error); pub struct Blocked(#[from] policy::config::Error);
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Tracking { pub enum Policy {
#[error("failed to find tracking policy for {rid}")] #[error("failed to find policy for {rid}")]
FailedPolicy { FailedPolicy {
rid: Id, rid: Id,
#[source] #[source]
err: policy::store::Error, err: policy::store::Error,
}, },
#[error("cannot fetch {rid} as it is not tracked")] #[error("cannot fetch {rid} as it is not seeded")]
BlockedPolicy { rid: Id }, BlockedPolicy { rid: Id },
#[error("failed to get tracking nodes for {rid}")] #[error("failed to get followed nodes for {rid}")]
FailedNodes { FailedNodes {
rid: Id, rid: Id,
#[source] #[source]

View File

@ -12,7 +12,7 @@
//! as an anchor for the rest of the fetch, i.e. provides initial //! as an anchor for the rest of the fetch, i.e. provides initial
//! delegate data for the repository. //! delegate data for the repository.
//! 2. [`SpecialRefs`]: fetches the special references, `rad/id` and //! 2. [`SpecialRefs`]: fetches the special references, `rad/id` and
//! `rad/sigrefs`, for each configured namespace, i.e. tracked //! `rad/sigrefs`, for each configured namespace, i.e. followed
//! and delegate peers if the scope is "followed" and all peers is the //! and delegate peers if the scope is "followed" and all peers is the
//! scope is all. //! scope is all.
//! 3. [`DataRefs`]: fetches the `Oid`s for each reference listed in //! 3. [`DataRefs`]: fetches the `Oid`s for each reference listed in
@ -40,12 +40,12 @@ use radicle::storage::refs::{RefsAt, Special};
use radicle::storage::ReadRepository; use radicle::storage::ReadRepository;
use crate::git::refs::{Policy, Update, Updates}; use crate::git::refs::{Policy, Update, Updates};
use crate::policy::BlockList;
use crate::refs::{ReceivedRef, ReceivedRefname}; use crate::refs::{ReceivedRef, ReceivedRefname};
use crate::sigrefs; use crate::sigrefs;
use crate::state::FetchState; use crate::state::FetchState;
use crate::tracking::BlockList;
use crate::transport::WantsHaves; use crate::transport::WantsHaves;
use crate::{refs, tracking}; use crate::{policy, refs};
pub mod error { pub mod error {
use radicle::crypto::PublicKey; use radicle::crypto::PublicKey;
@ -214,12 +214,11 @@ impl ProtocolStage for CanonicalId {
} }
/// The [`ProtocolStage`] for fetching special refs from the set of /// The [`ProtocolStage`] for fetching special refs from the set of
/// remotes in `tracked` and `delegates`. /// remotes in `followed` and `delegates`.
/// ///
/// This step asks for all tracked and delegate remote's `rad/id` and /// This step asks for all followed and delegate remote's `rad/id` and
/// `rad/sigrefs`, iff the scope is /// `rad/sigrefs`, iff the scope is [`policy::Scope::Followed`].
/// [`tracking::Scope::Trusted`]. Otherwise, it asks for all /// Otherwise, it asks for all namespaces.
/// namespaces.
/// ///
/// It ensures that all delegate refs were fetched. /// It ensures that all delegate refs were fetched.
#[derive(Debug)] #[derive(Debug)]
@ -229,7 +228,7 @@ pub struct SpecialRefs {
/// The node that is being fetched from. /// The node that is being fetched from.
pub remote: PublicKey, pub remote: PublicKey,
/// The set of nodes to be fetched. /// The set of nodes to be fetched.
pub tracked: tracking::Tracked, pub followed: policy::Allowed,
/// The set of delegates to be fetched, with the local node /// The set of delegates to be fetched, with the local node
/// removed in the case of a `pull`. /// removed in the case of a `pull`.
pub delegates: BTreeSet<PublicKey>, pub delegates: BTreeSet<PublicKey>,
@ -239,9 +238,9 @@ pub struct SpecialRefs {
impl ProtocolStage for SpecialRefs { impl ProtocolStage for SpecialRefs {
fn ls_refs(&self) -> Option<NonEmpty<BString>> { fn ls_refs(&self) -> Option<NonEmpty<BString>> {
match &self.tracked { match &self.followed {
tracking::Tracked::All => Some(NonEmpty::new("refs/namespaces".into())), policy::Allowed::All => Some(NonEmpty::new("refs/namespaces".into())),
tracking::Tracked::Followed { remotes } => NonEmpty::collect( policy::Allowed::Followed { remotes } => NonEmpty::collect(
remotes remotes
.iter() .iter()
.chain(self.delegates.iter()) .chain(self.delegates.iter())

View File

@ -323,13 +323,13 @@ impl FetchState {
Ok(signed_refs) Ok(signed_refs)
} }
None => { None => {
let tracked = handle.tracked(); let followed = handle.allowed();
log::trace!(target: "fetch", "Tracked nodes {:?}", tracked); log::trace!(target: "fetch", "Followed nodes {:?}", followed);
let special_refs = stage::SpecialRefs { let special_refs = stage::SpecialRefs {
blocked: handle.blocked.clone(), blocked: handle.blocked.clone(),
remote, remote,
delegates: delegates.clone(), delegates: delegates.clone(),
tracked, followed,
limit: limit.special, limit: limit.special,
}; };
log::trace!(target: "fetch", "{special_refs:?}"); log::trace!(target: "fetch", "{special_refs:?}");

View File

@ -64,7 +64,7 @@ impl Context {
let issues = issue::Issues::open(&repo)?.counts()?; let issues = issue::Issues::open(&repo)?.counts()?;
let patches = patch::Patches::open(&repo)?.counts()?; let patches = patch::Patches::open(&repo)?.counts()?;
let db = &self.profile.database()?; let db = &self.profile.database()?;
let trackings = db.count(&id).unwrap_or_default(); let seeding = db.count(&id).unwrap_or_default();
Ok(project::Info { Ok(project::Info {
payload, payload,
@ -74,7 +74,7 @@ impl Context {
issues, issues,
patches, patches,
id, id,
trackings, seeding,
}) })
} }
@ -213,7 +213,7 @@ mod project {
pub patches: cob::patch::PatchCounts, pub patches: cob::patch::PatchCounts,
pub issues: cob::issue::IssueCounts, pub issues: cob::issue::IssueCounts,
pub id: Id, pub id: Id,
pub trackings: usize, pub seeding: usize,
} }
} }

View File

@ -78,7 +78,7 @@ async fn delegates_projects_handler(
}; };
let delegates = id.doc.delegates; let delegates = id.doc.delegates;
let trackings = db.count(&id.rid).unwrap_or_default(); let seeding = db.count(&id.rid).unwrap_or_default();
Some(Info { Some(Info {
payload, payload,
@ -88,7 +88,7 @@ async fn delegates_projects_handler(
issues, issues,
patches, patches,
id: id.rid, id: id.rid,
trackings, seeding,
}) })
}) })
.skip(page * per_page) .skip(page * per_page)
@ -146,7 +146,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK", "id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK",
"trackings": 0, "seeding": 0,
}, },
{ {
"name": "hello-world", "name": "hello-world",
@ -168,7 +168,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": RID, "id": RID,
"trackings": 0, "seeding": 0,
}, },
]) ])
); );
@ -207,7 +207,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": RID, "id": RID,
"trackings": 0, "seeding": 0,
} }
]) ])
); );

View File

@ -51,13 +51,13 @@ async fn node_handler(State(ctx): State<Context>) -> impl IntoResponse {
Ok::<_, Error>(Json(response)) Ok::<_, Error>(Json(response))
} }
/// Return local tracking repos information. /// Return local repo policies information.
/// `GET /node/policies/repos` /// `GET /node/policies/repos`
async fn node_policies_repos_handler(State(ctx): State<Context>) -> impl IntoResponse { async fn node_policies_repos_handler(State(ctx): State<Context>) -> impl IntoResponse {
let tracking = ctx.profile.tracking()?; let policies = ctx.profile.policies()?;
let mut repos = Vec::new(); let mut repos = Vec::new();
for policy::Repo { id, scope, policy } in tracking.repo_policies()? { for policy::Repo { id, scope, policy } in policies.seed_policies()? {
repos.push(json!({ repos.push(json!({
"id": id, "id": id,
"scope": scope, "scope": scope,
@ -68,7 +68,7 @@ async fn node_policies_repos_handler(State(ctx): State<Context>) -> impl IntoRes
Ok::<_, Error>(Json(repos)) Ok::<_, Error>(Json(repos))
} }
/// Track a new repo. /// Seed a new repo.
/// `PUT /node/policies/repos/:rid` /// `PUT /node/policies/repos/:rid`
async fn node_policies_seed_handler( async fn node_policies_seed_handler(
State(ctx): State<Context>, State(ctx): State<Context>,
@ -90,7 +90,7 @@ async fn node_policies_seed_handler(
Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true })))) Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true }))))
} }
/// Untrack a repo. /// Unseed a repo.
/// `DELETE /node/policies/repos/:rid` /// `DELETE /node/policies/repos/:rid`
async fn node_policies_unseed_handler( async fn node_policies_unseed_handler(
State(ctx): State<Context>, State(ctx): State<Context>,

View File

@ -119,7 +119,7 @@ async fn project_root_handler(
return None; return None;
}; };
let delegates = id.doc.delegates; let delegates = id.doc.delegates;
let trackings = db.count(&id.rid).unwrap_or_default(); let seeding = db.count(&id.rid).unwrap_or_default();
Some(Info { Some(Info {
payload, payload,
@ -129,7 +129,7 @@ async fn project_root_handler(
issues, issues,
patches, patches,
id: id.rid, id: id.rid,
trackings, seeding,
}) })
}) })
.skip(page * per_page) .skip(page * per_page)
@ -994,7 +994,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK", "id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK",
"trackings": 0, "seeding": 0,
}, },
{ {
"name": "hello-world", "name": "hello-world",
@ -1016,7 +1016,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": RID, "id": RID,
"trackings": 0, "seeding": 0,
}, },
]) ])
); );
@ -1051,7 +1051,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": RID, "id": RID,
"trackings": 0, "seeding": 0,
} }
]) ])
); );
@ -1086,7 +1086,7 @@ mod routes {
"closed": 0, "closed": 0,
}, },
"id": RID, "id": RID,
"trackings": 0, "seeding": 0,
}) })
); );
} }

View File

@ -96,7 +96,7 @@ fn seed_with_signer<G: Signer>(dir: &Path, profile: radicle::Profile, signer: &G
crate::logger::init().ok(); crate::logger::init().ok();
profile.tracking_mut().unwrap(); profile.policies_mut().unwrap();
profile.database_mut().unwrap(); // Create the database. profile.database_mut().unwrap(); // Create the database.
let workdir = dir.join("hello-world-private"); let workdir = dir.join("hello-world-private");

View File

@ -280,7 +280,7 @@ mod tests {
} }
#[test] #[test]
fn test_track_untrack() { fn test_seed_unseed() {
let tmp = tempfile::tempdir().unwrap(); let tmp = tempfile::tempdir().unwrap();
let socket = tmp.path().join("node.sock"); let socket = tmp.path().join("node.sock");
let proj = test::arbitrary::gen::<Id>(1); let proj = test::arbitrary::gen::<Id>(1);

View File

@ -44,9 +44,9 @@ pub enum Error {
/// A node database error. /// A node database error.
#[error("node database error: {0}")] #[error("node database error: {0}")]
Database(#[from] node::db::Error), Database(#[from] node::db::Error),
/// A tracking database error. /// A policies database error.
#[error("tracking database error: {0}")] #[error("policies database error: {0}")]
Tracking(#[from] policy::Error), Policy(#[from] policy::Error),
/// A gossip database error. /// A gossip database error.
#[error("gossip database error: {0}")] #[error("gossip database error: {0}")]
Gossip(#[from] gossip::Error), Gossip(#[from] gossip::Error),
@ -145,11 +145,11 @@ impl Runtime {
log::info!(target: "node", "Opening node database.."); log::info!(target: "node", "Opening node database..");
let mut db: service::Stores<_> = home.database_mut()?.into(); let mut db: service::Stores<_> = home.database_mut()?.into();
log::info!(target: "node", "Opening tracking policy configuration.."); log::info!(target: "node", "Opening policy database..");
let tracking = home.tracking_mut()?; let policies = home.policies_mut()?;
let tracking = policy::Config::new(policy, scope, tracking); let policies = policy::Config::new(policy, scope, policies);
log::info!(target: "node", "Default tracking policy set to '{}'", &policy); log::info!(target: "node", "Default seeding policy set to '{}'", &policy);
log::info!(target: "node", "Initializing service ({:?})..", network); log::info!(target: "node", "Initializing service ({:?})..", network);
let announcement = if let Some(ann) = fs::read(node_dir.join(node::NODE_ANNOUNCEMENT_FILE)) let announcement = if let Some(ann) = fs::read(node_dir.join(node::NODE_ANNOUNCEMENT_FILE))
@ -202,7 +202,7 @@ impl Runtime {
clock, clock,
db, db,
storage.clone(), storage.clone(),
tracking, policies,
signer.clone(), signer.clone(),
rng, rng,
announcement, announcement,
@ -237,7 +237,7 @@ impl Runtime {
let fetch = worker::FetchConfig { let fetch = worker::FetchConfig {
policy, policy,
scope, scope,
tracking_db: home.node().join(node::TRACKING_DB_FILE), policies_db: home.node().join(node::POLICIES_DB_FILE),
limit: FetchLimit::default(), limit: FetchLimit::default(),
local: nid, local: nid,
expiry: worker::garbage::Expiry::default(), expiry: worker::garbage::Expiry::default(),

View File

@ -203,25 +203,25 @@ impl radicle::node::Handle for Handle {
fn follow(&mut self, id: NodeId, alias: Option<Alias>) -> Result<bool, Error> { fn follow(&mut self, id: NodeId, alias: Option<Alias>) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.command(service::Command::TrackNode(id, alias, sender))?; self.command(service::Command::Follow(id, alias, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
fn unfollow(&mut self, id: NodeId) -> Result<bool, Error> { fn unfollow(&mut self, id: NodeId) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.command(service::Command::UntrackNode(id, sender))?; self.command(service::Command::Unfollow(id, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
fn seed(&mut self, id: Id, scope: policy::Scope) -> Result<bool, Error> { fn seed(&mut self, id: Id, scope: policy::Scope) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.command(service::Command::TrackRepo(id, scope, sender))?; self.command(service::Command::Seed(id, scope, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }
fn unseed(&mut self, id: Id) -> Result<bool, Error> { fn unseed(&mut self, id: Id) -> Result<bool, Error> {
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
self.command(service::Command::UntrackRepo(id, sender))?; self.command(service::Command::Unseed(id, sender))?;
receiver.recv().map_err(Error::from) receiver.recv().map_err(Error::from)
} }

View File

@ -140,7 +140,7 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
Seeds(#[from] seed::Error), Seeds(#[from] seed::Error),
#[error(transparent)] #[error(transparent)]
Tracking(#[from] policy::Error), Policy(#[from] policy::Error),
#[error(transparent)] #[error(transparent)]
Repository(#[from] radicle::storage::RepositoryError), Repository(#[from] radicle::storage::RepositoryError),
#[error("namespaces error: {0}")] #[error("namespaces error: {0}")]
@ -173,14 +173,14 @@ pub enum Command {
Seeds(Id, chan::Sender<Seeds>), Seeds(Id, chan::Sender<Seeds>),
/// Fetch the given repository from the network. /// Fetch the given repository from the network.
Fetch(Id, NodeId, time::Duration, chan::Sender<FetchResult>), Fetch(Id, NodeId, time::Duration, chan::Sender<FetchResult>),
/// Track the given repository. /// Seed the given repository.
TrackRepo(Id, Scope, chan::Sender<bool>), Seed(Id, Scope, chan::Sender<bool>),
/// Untrack the given repository. /// Unseed the given repository.
UntrackRepo(Id, chan::Sender<bool>), Unseed(Id, chan::Sender<bool>),
/// Track the given node. /// Follow the given node.
TrackNode(NodeId, Option<Alias>, chan::Sender<bool>), Follow(NodeId, Option<Alias>, chan::Sender<bool>),
/// Untrack the given node. /// Unfollow the given node.
UntrackNode(NodeId, chan::Sender<bool>), Unfollow(NodeId, chan::Sender<bool>),
/// Query the internal service state. /// Query the internal service state.
QueryState(Arc<QueryState>, chan::Sender<Result<(), CommandError>>), QueryState(Arc<QueryState>, chan::Sender<Result<(), CommandError>>),
} }
@ -196,10 +196,10 @@ impl fmt::Debug for Command {
Self::Config(_) => write!(f, "Config"), Self::Config(_) => write!(f, "Config"),
Self::Seeds(id, _) => write!(f, "Seeds({id})"), Self::Seeds(id, _) => write!(f, "Seeds({id})"),
Self::Fetch(id, node, _, _) => write!(f, "Fetch({id}, {node})"), Self::Fetch(id, node, _, _) => write!(f, "Fetch({id}, {node})"),
Self::TrackRepo(id, scope, _) => write!(f, "TrackRepo({id}, {scope})"), Self::Seed(id, scope, _) => write!(f, "Seed({id}, {scope})"),
Self::UntrackRepo(id, _) => write!(f, "UntrackRepo({id})"), Self::Unseed(id, _) => write!(f, "Unseed({id})"),
Self::TrackNode(id, _, _) => write!(f, "TrackNode({id})"), Self::Follow(id, _, _) => write!(f, "Follow({id})"),
Self::UntrackNode(id, _) => write!(f, "UntrackNode({id})"), Self::Unfollow(id, _) => write!(f, "Unfollow({id})"),
Self::QueryState { .. } => write!(f, "QueryState(..)"), Self::QueryState { .. } => write!(f, "QueryState(..)"),
} }
} }
@ -213,7 +213,7 @@ pub enum CommandError {
#[error(transparent)] #[error(transparent)]
Routing(#[from] routing::Error), Routing(#[from] routing::Error),
#[error(transparent)] #[error(transparent)]
Tracking(#[from] policy::Error), Policy(#[from] policy::Error),
} }
/// Error returned by [`Service::try_fetch`]. /// Error returned by [`Service::try_fetch`].
@ -304,8 +304,8 @@ pub struct Service<D, S, G> {
storage: S, storage: S,
/// Node database. /// Node database.
db: Stores<D>, db: Stores<D>,
/// Tracking policy configuration. /// Policy configuration.
tracking: policy::Config<Write>, policies: policy::Config<Write>,
/// Peer sessions, currently or recently connected. /// Peer sessions, currently or recently connected.
sessions: Sessions, sessions: Sessions,
/// Clock. Tells the time. /// Clock. Tells the time.
@ -322,7 +322,7 @@ pub struct Service<D, S, G> {
queue: VecDeque<(Id, NodeId)>, queue: VecDeque<(Id, NodeId)>,
/// Request/connection rate limitter. /// Request/connection rate limitter.
limiter: RateLimiter, limiter: RateLimiter,
/// Current tracked repository bloom filter. /// Current seeded repositories bloom filter.
filter: Filter, filter: Filter,
/// Last time the service was idle. /// Last time the service was idle.
last_idle: LocalTime, last_idle: LocalTime,
@ -364,7 +364,7 @@ where
clock: LocalTime, clock: LocalTime,
db: Stores<D>, db: Stores<D>,
storage: S, storage: S,
tracking: policy::Config<Write>, policies: policy::Config<Write>,
signer: G, signer: G,
rng: Rng, rng: Rng,
node: NodeAnnouncement, node: NodeAnnouncement,
@ -375,7 +375,7 @@ where
Self { Self {
config, config,
storage, storage,
tracking, policies,
signer, signer,
rng, rng,
node, node,
@ -402,42 +402,37 @@ where
self.outbox.next() self.outbox.next()
} }
/// Track a repository. /// Seed a repository.
/// Returns whether or not the tracking policy was updated. /// Returns whether or not the repo policy was updated.
pub fn track_repo(&mut self, id: &Id, scope: Scope) -> Result<bool, policy::Error> { pub fn seed(&mut self, id: &Id, scope: Scope) -> Result<bool, policy::Error> {
let updated = self.tracking.track_repo(id, scope)?; let updated = self.policies.seed(id, scope)?;
self.filter.insert(id); self.filter.insert(id);
Ok(updated) Ok(updated)
} }
/// Untrack a repository. /// Unseed a repository.
/// Returns whether or not the tracking policy was updated. /// Returns whether or not the repo policy was updated.
/// Note that when untracking, we don't announce anything to the network. This is because by /// Note that when unseeding, we don't announce anything to the network. This is because by
/// simply not announcing it anymore, it will eventually be pruned by nodes. /// simply not announcing it anymore, it will eventually be pruned by nodes.
pub fn untrack_repo(&mut self, id: &Id) -> Result<bool, policy::Error> { pub fn unseed(&mut self, id: &Id) -> Result<bool, policy::Error> {
let updated = self.tracking.untrack_repo(id)?; let updated = self.policies.unseed(id)?;
// Nb. This is potentially slow if we have lots of projects. We should probably // Nb. This is potentially slow if we have lots of repos. We should probably
// only re-compute the filter when we've untracked a certain amount of projects // only re-compute the filter when we've unseeded a certain amount of repos
// and the filter is really out of date. // and the filter is really out of date.
// //
// TODO: Share this code with initialization code. // TODO: Share this code with initialization code.
self.filter = Filter::new( self.filter = Filter::new(
self.tracking self.policies
.repo_policies()? .seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)), .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)),
); );
Ok(updated) Ok(updated)
} }
/// Check whether we are tracking a certain repository. /// Find the closest `n` peers by proximity in seeding graphs.
pub fn is_tracking(&self, id: &Id) -> Result<bool, policy::Error> {
self.tracking.is_repo_tracked(id)
}
/// Find the closest `n` peers by proximity in tracking graphs.
/// Returns a sorted list from the closest peer to the furthest. /// Returns a sorted list from the closest peer to the furthest.
/// Peers with more trackings in common score score higher. /// Peers with more seedings in common score score higher.
#[allow(unused)] #[allow(unused)]
pub fn closest_peers(&self, n: usize) -> Vec<NodeId> { pub fn closest_peers(&self, n: usize) -> Vec<NodeId> {
todo!() todo!()
@ -463,9 +458,9 @@ where
&mut self.storage &mut self.storage
} }
/// Get the tracking policy. /// Get the node policies.
pub fn tracking(&self) -> &policy::Config<Write> { pub fn policies(&self) -> &policy::Config<Write> {
&self.tracking &self.policies
} }
/// Get the local signer. /// Get the local signer.
@ -520,8 +515,8 @@ where
for (id, addr) in addrs.into_iter().map(|ca| ca.into()) { for (id, addr) in addrs.into_iter().map(|ca| ca.into()) {
self.connect(id, addr); self.connect(id, addr);
} }
// Ensure that our inventory is recorded in our routing table, and we are tracking // Ensure that our inventory is recorded in our routing table, and we are seeding
// all of it. It can happen that inventory is not properly tracked if for eg. the // all of it. It can happen that inventory is not properly seeded if for eg. the
// user creates a new repository while the node is stopped. // user creates a new repository while the node is stopped.
let rids = self.storage.inventory()?; let rids = self.storage.inventory()?;
self.db.routing_mut().insert(&rids, nid, time.as_millis())?; self.db.routing_mut().insert(&rids, nid, time.as_millis())?;
@ -534,8 +529,8 @@ where
for rid in rids { for rid in rids {
let repo = self.storage.repository(rid)?; let repo = self.storage.repository(rid)?;
if !self.is_tracking(&rid)? { if !self.policies.is_seeding(&rid)? {
warn!(target: "service", "Local repository {rid} is not tracked"); warn!(target: "service", "Local repository {rid} is not seeded");
} }
// If we have no owned refs for this repo, then there's nothing to announce. // If we have no owned refs for this repo, then there's nothing to announce.
let Ok(updated_at) = SyncedAt::load(&repo, nid) else { let Ok(updated_at) = SyncedAt::load(&repo, nid) else {
@ -566,10 +561,10 @@ where
} }
} }
// Setup subscription filter for tracked repos. // Setup subscription filter for seeded repos.
self.filter = Filter::new( self.filter = Filter::new(
self.tracking self.policies
.repo_policies()? .seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)), .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)),
); );
// Try to establish some connections. // Try to establish some connections.
@ -677,12 +672,12 @@ where
Command::Fetch(rid, seed, timeout, resp) => { Command::Fetch(rid, seed, timeout, resp) => {
self.fetch(rid, &seed, timeout, Some(resp)); self.fetch(rid, &seed, timeout, Some(resp));
} }
Command::TrackRepo(rid, scope, resp) => { Command::Seed(rid, scope, resp) => {
// Update our tracking policy. // Update our seeding policy.
let tracked = self let seeded = self
.track_repo(&rid, scope) .seed(&rid, scope)
.expect("Service::command: error tracking repository"); .expect("Service::command: error seeding repository");
resp.send(tracked).ok(); resp.send(seeded).ok();
// Let all our peers know that we're interested in this repo from now on. // Let all our peers know that we're interested in this repo from now on.
self.outbox.broadcast( self.outbox.broadcast(
@ -690,25 +685,25 @@ where
self.sessions.connected().map(|(_, s)| s), self.sessions.connected().map(|(_, s)| s),
); );
} }
Command::UntrackRepo(id, resp) => { Command::Unseed(id, resp) => {
let untracked = self let updated = self
.untrack_repo(&id) .unseed(&id)
.expect("Service::command: error untracking repository"); .expect("Service::command: error unseeding repository");
resp.send(untracked).ok(); resp.send(updated).ok();
} }
Command::TrackNode(id, alias, resp) => { Command::Follow(id, alias, resp) => {
let tracked = self let seeded = self
.tracking .policies
.track_node(&id, alias.as_deref()) .follow(&id, alias.as_deref())
.expect("Service::command: error tracking node"); .expect("Service::command: error following node");
resp.send(tracked).ok(); resp.send(seeded).ok();
} }
Command::UntrackNode(id, resp) => { Command::Unfollow(id, resp) => {
let untracked = self let updated = self
.tracking .policies
.untrack_node(&id) .unfollow(&id)
.expect("Service::command: error untracking node"); .expect("Service::command: error unfollowing node");
resp.send(untracked).ok(); resp.send(updated).ok();
} }
Command::AnnounceRefs(id, resp) => match self.announce_refs(id, [self.node_id()]) { Command::AnnounceRefs(id, resp) => match self.announce_refs(id, [self.node_id()]) {
Ok(refs) => match refs.as_slice() { Ok(refs) => match refs.as_slice() {
@ -833,7 +828,7 @@ where
from, from,
subscribers: vec![], subscribers: vec![],
}); });
let namespaces = self.tracking.namespaces_for(&self.storage, &rid)?; let namespaces = self.policies.namespaces_for(&self.storage, &rid)?;
self.outbox self.outbox
.fetch(session, rid, namespaces, refs_at, timeout); .fetch(session, rid, namespaces, refs_at, timeout);
@ -1190,10 +1185,10 @@ where
sub.filter.insert(id); sub.filter.insert(id);
} }
// If we're tracking and connected to the announcer, and we don't have // If we're seeding and connected to the announcer, and we don't have
// the inventory, fetch it from the announcer. // the inventory, fetch it from the announcer.
if self.tracking.is_repo_tracked(id).expect( if self.policies.is_seeding(id).expect(
"Service::handle_announcement: error accessing tracking configuration", "Service::handle_announcement: error accessing seeding configuration",
) { ) {
// Only if we do not have the repository locally do we fetch here. // Only if we do not have the repository locally do we fetch here.
// If we do have it, only fetch after receiving a ref announcement. // If we do have it, only fetch after receiving a ref announcement.
@ -1202,7 +1197,7 @@ where
// Do nothing. // Do nothing.
} }
Ok(false) => { Ok(false) => {
debug!(target: "service", "Missing tracked inventory {id}; initiating fetch.."); debug!(target: "service", "Missing seeded inventory {id}; initiating fetch..");
self.fetch(*id, announcer, FETCH_TIMEOUT, None); self.fetch(*id, announcer, FETCH_TIMEOUT, None);
} }
Err(e) => { Err(e) => {
@ -1262,8 +1257,8 @@ where
} }
// TODO: Buffer/throttle fetches. // TODO: Buffer/throttle fetches.
let repo_entry = self.tracking.repo_policy(&message.rid).expect( let repo_entry = self.policies.repo_policy(&message.rid).expect(
"Service::handle_announcement: error accessing repo tracking configuration", "Service::handle_announcement: error accessing repo seeding configuration",
); );
if repo_entry.policy == Policy::Allow { if repo_entry.policy == Policy::Allow {
@ -1336,7 +1331,7 @@ where
} else { } else {
debug!( debug!(
target: "service", target: "service",
"Ignoring refs announcement from {announcer}: repository {} isn't tracked", "Ignoring refs announcement from {announcer}: repository {} isn't seeded",
message.rid message.rid
); );
} }
@ -1425,7 +1420,7 @@ where
match scope { match scope {
policy::Scope::All => Ok(refs), policy::Scope::All => Ok(refs),
policy::Scope::Followed => { policy::Scope::Followed => {
match self.tracking.namespaces_for(&self.storage, &message.rid) { match self.policies.namespaces_for(&self.storage, &message.rid) {
Ok(Namespaces::All) => Ok(refs), Ok(Namespaces::All) => Ok(refs),
Ok(Namespaces::Followed(mut followed)) => { Ok(Namespaces::Followed(mut followed)) => {
// Get the set of followed nodes except self. // Get the set of followed nodes except self.
@ -1618,9 +1613,11 @@ where
info!(target: "service", "Routing table updated for {rid} with seed {from}"); info!(target: "service", "Routing table updated for {rid} with seed {from}");
self.emitter.emit(Event::SeedDiscovered { rid, nid: from }); self.emitter.emit(Event::SeedDiscovered { rid, nid: from });
if self.tracking.is_repo_tracked(&rid).expect( if self
"Service::process_inventory: error accessing tracking configuration", .policies
) { .is_seeding(&rid)
.expect("Service::process_inventory: error accessing seeding configuration")
{
// TODO: We should fetch here if we're already connected, case this seed has // TODO: We should fetch here if we're already connected, case this seed has
// refs we don't have. // refs we don't have.
} }
@ -1797,7 +1794,7 @@ where
} }
// Then, add peers we know about but have no information about the sync status. // Then, add peers we know about but have no information about the sync status.
// These peers have announced that they track the repository via an inventory // These peers have announced that they seed the repository via an inventory
// announcement, but we haven't received any ref announcements from them. // announcement, but we haven't received any ref announcements from them.
for nid in self.db.routing().get(rid)? { for nid in self.db.routing().get(rid)? {
if nid == self.node_id() { if nid == self.node_id() {
@ -1815,7 +1812,7 @@ where
Ok(seeds) Ok(seeds)
} }
/// Return a new filter object, based on our tracking policy. /// Return a new filter object, based on our seeding policy.
fn filter(&self) -> Filter { fn filter(&self) -> Filter {
if self.config.policy == Policy::Allow { if self.config.policy == Policy::Allow {
// TODO: Remove bits for blocked repos. // TODO: Remove bits for blocked repos.
@ -1914,12 +1911,12 @@ where
} }
} }
/// Fetch all repositories that are tracked but missing from our inventory. /// Fetch all repositories that are seeded but missing from our inventory.
fn fetch_missing_inventory(&mut self) -> Result<(), Error> { fn fetch_missing_inventory(&mut self) -> Result<(), Error> {
let inventory = self.storage().inventory()?; let inventory = self.storage().inventory()?;
let missing = self let missing = self
.tracking .policies
.repo_policies()? .seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)) .filter_map(|t| (t.policy == Policy::Allow).then_some(t.id))
.filter(|rid| !inventory.contains(rid)); .filter(|rid| !inventory.contains(rid));
@ -1938,7 +1935,7 @@ where
// Another way to handle this would be to update our database, saying // Another way to handle this would be to update our database, saying
// that we're trying to fetch a certain repo. We would then just // that we're trying to fetch a certain repo. We would then just
// iterate over those entries in the above circumstances. This is // iterate over those entries in the above circumstances. This is
// merely an optimization though, we can also iterate over all tracked // merely an optimization though, we can also iterate over all seeded
// repos and check which ones are not in our inventory. // repos and check which ones are not in our inventory.
debug!(target: "service", "No connected seeds found for {rid}.."); debug!(target: "service", "No connected seeds found for {rid}..");
} }

View File

@ -21,7 +21,7 @@ use radicle::identity::{Id, Visibility};
use radicle::node::policy::store as policy; use radicle::node::policy::store as policy;
use radicle::node::routing::Store; use radicle::node::routing::Store;
use radicle::node::Database; use radicle::node::Database;
use radicle::node::{Alias, TRACKING_DB_FILE}; use radicle::node::{Alias, POLICIES_DB_FILE};
use radicle::node::{ConnectOptions, Handle as _}; use radicle::node::{ConnectOptions, Handle as _};
use radicle::profile; use radicle::profile;
use radicle::profile::Home; use radicle::profile::Home;
@ -81,8 +81,8 @@ impl Environment {
let profile = self.profile(&config.alias); let profile = self.profile(&config.alias);
let signer = MemorySigner::load(&profile.keystore, None).unwrap(); let signer = MemorySigner::load(&profile.keystore, None).unwrap();
let tracking_db = profile.home.node().join(TRACKING_DB_FILE); let policies_db = profile.home.node().join(POLICIES_DB_FILE);
let tracking = policy::Config::open(tracking_db).unwrap(); let policies = policy::Store::open(policies_db).unwrap();
let db = profile.database_mut().unwrap(); let db = profile.database_mut().unwrap();
let db = service::Stores::from(db); let db = service::Stores::from(db);
@ -92,7 +92,7 @@ impl Environment {
config, config,
signer, signer,
db, db,
tracking, policies,
storage: profile.storage, storage: profile.storage,
} }
} }
@ -103,7 +103,7 @@ impl Environment {
let home = Home::new(self.tmp().join("home").join(alias).join(".radicle")).unwrap(); let home = Home::new(self.tmp().join("home").join(alias).join(".radicle")).unwrap();
let keystore = Keystore::new(&home.keys()); let keystore = Keystore::new(&home.keys());
let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32])); let keypair = KeyPair::from_seed(Seed::from([!(self.users as u8); 32]));
let tracking_db = home.node().join(TRACKING_DB_FILE); let policies_db = home.node().join(POLICIES_DB_FILE);
let alias = Alias::from_str(alias).unwrap(); let alias = Alias::from_str(alias).unwrap();
let config = profile::Config { let config = profile::Config {
node: node::Config::new(alias.clone()), node: node::Config::new(alias.clone()),
@ -122,7 +122,7 @@ impl Environment {
) )
.unwrap(); .unwrap();
policy::Config::open(tracking_db).unwrap(); policy::Store::open(policies_db).unwrap();
home.database_mut().unwrap(); // Just create the database. home.database_mut().unwrap(); // Just create the database.
transport::local::register(storage.clone()); transport::local::register(storage.clone());
@ -149,7 +149,7 @@ pub struct Node<G> {
pub storage: Storage, pub storage: Storage,
pub config: Config, pub config: Config,
pub db: service::Stores<Database>, pub db: service::Stores<Database>,
pub tracking: policy::Config<policy::Write>, pub policies: policy::Store<policy::Write>,
} }
/// Handle to a running node. /// Handle to a running node.
@ -348,7 +348,7 @@ impl Node<MockSigner> {
}, },
) )
.unwrap(); .unwrap();
let tracking = home.tracking_mut().unwrap(); let policies = home.policies_mut().unwrap();
let db = home.database_mut().unwrap(); let db = home.database_mut().unwrap();
let db = service::Stores::from(db); let db = service::Stores::from(db);
@ -360,7 +360,7 @@ impl Node<MockSigner> {
storage, storage,
config, config,
db, db,
tracking, policies,
} }
} }
} }
@ -419,8 +419,8 @@ impl<G: cyphernet::Ecdh<Pk = NodeId> + Signer + Clone> Node<G> {
.unwrap(); .unwrap();
assert!(self assert!(self
.tracking .policies
.track_repo(&id, node::policy::Scope::Followed) .seed(&id, node::policy::Scope::Followed)
.unwrap()); .unwrap());
log::debug!( log::debug!(

View File

@ -15,8 +15,8 @@ use crate::service::NodeId;
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct Handle { pub struct Handle {
pub updates: Arc<Mutex<Vec<Id>>>, pub updates: Arc<Mutex<Vec<Id>>>,
pub tracking_repos: Arc<Mutex<HashSet<Id>>>, pub seeding: Arc<Mutex<HashSet<Id>>>,
pub tracking_nodes: Arc<Mutex<HashSet<NodeId>>>, pub following: Arc<Mutex<HashSet<NodeId>>>,
} }
impl radicle::node::Handle for Handle { impl radicle::node::Handle for Handle {
@ -61,15 +61,15 @@ impl radicle::node::Handle for Handle {
} }
fn seed(&mut self, id: Id, _scope: policy::Scope) -> Result<bool, Self::Error> { fn seed(&mut self, id: Id, _scope: policy::Scope) -> Result<bool, Self::Error> {
Ok(self.tracking_repos.lock().unwrap().insert(id)) Ok(self.seeding.lock().unwrap().insert(id))
} }
fn unseed(&mut self, id: Id) -> Result<bool, Self::Error> { fn unseed(&mut self, id: Id) -> Result<bool, Self::Error> {
Ok(self.tracking_repos.lock().unwrap().remove(&id)) Ok(self.seeding.lock().unwrap().remove(&id))
} }
fn follow(&mut self, id: NodeId, _alias: Option<Alias>) -> Result<bool, Self::Error> { fn follow(&mut self, id: NodeId, _alias: Option<Alias>) -> Result<bool, Self::Error> {
Ok(self.tracking_nodes.lock().unwrap().insert(id)) Ok(self.following.lock().unwrap().insert(id))
} }
fn subscribe( fn subscribe(
@ -80,7 +80,7 @@ impl radicle::node::Handle for Handle {
} }
fn unfollow(&mut self, id: NodeId) -> Result<bool, Self::Error> { fn unfollow(&mut self, id: NodeId) -> Result<bool, Self::Error> {
Ok(self.tracking_nodes.lock().unwrap().remove(&id)) Ok(self.following.lock().unwrap().remove(&id))
} }
fn announce_refs(&mut self, id: Id) -> Result<RefsAt, Self::Error> { fn announce_refs(&mut self, id: Id) -> Result<RefsAt, Self::Error> {

View File

@ -162,8 +162,8 @@ where
storage: S, storage: S,
mut config: Config<G>, mut config: Config<G>,
) -> Self { ) -> Self {
let tracking = policy::Store::<policy::store::Write>::memory().unwrap(); let policies = policy::Store::<policy::store::Write>::memory().unwrap();
let mut tracking = policy::Config::new(config.policy, config.scope, tracking); let mut policies = policy::Config::new(config.policy, config.scope, policies);
let id = *config.signer.public_key(); let id = *config.signer.public_key();
let ip = ip.into(); let ip = ip.into();
let local_addr = net::SocketAddr::new(ip, config.rng.u16(..)); let local_addr = net::SocketAddr::new(ip, config.rng.u16(..));
@ -172,7 +172,7 @@ where
config.config.external_addresses.push(local_addr.into()); config.config.external_addresses.push(local_addr.into());
for rid in storage.inventory().unwrap() { for rid in storage.inventory().unwrap() {
tracking.track_repo(&rid, Scope::Followed).unwrap(); policies.seed(&rid, Scope::Followed).unwrap();
} }
let announcement = service::gossip::node(&config.config, config.local_time.as_secs()); let announcement = service::gossip::node(&config.config, config.local_time.as_secs());
let emitter: Emitter<Event> = Default::default(); let emitter: Emitter<Event> = Default::default();
@ -181,7 +181,7 @@ where
config.local_time, config.local_time,
config.db, config.db,
storage, storage,
tracking, policies,
config.signer, config.signer,
config.rng.clone(), config.rng.clone(),
announcement, announcement,

View File

@ -388,25 +388,21 @@ fn test_inventory_pruning() {
} }
#[test] #[test]
fn test_tracking() { fn test_seeding() {
let mut alice = Peer::new("alice", [7, 7, 7, 7]); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let proj_id: identity::Id = test::arbitrary::gen(1); let proj_id: identity::Id = test::arbitrary::gen(1);
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
alice.command(Command::TrackRepo( alice.command(Command::Seed(proj_id, policy::Scope::default(), sender));
proj_id,
policy::Scope::default(),
sender,
));
let policy_change = receiver.recv().map_err(runtime::HandleError::from).unwrap(); let policy_change = receiver.recv().map_err(runtime::HandleError::from).unwrap();
assert!(policy_change); assert!(policy_change);
assert!(alice.tracking().is_repo_tracked(&proj_id).unwrap()); assert!(alice.policies().is_seeding(&proj_id).unwrap());
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
alice.command(Command::UntrackRepo(proj_id, sender)); alice.command(Command::Unseed(proj_id, sender));
let policy_change = receiver.recv().map_err(runtime::HandleError::from).unwrap(); let policy_change = receiver.recv().map_err(runtime::HandleError::from).unwrap();
assert!(policy_change); assert!(policy_change);
assert!(!alice.tracking().is_repo_tracked(&proj_id).unwrap()); assert!(!alice.policies().is_seeding(&proj_id).unwrap());
} }
#[test] #[test]
@ -504,7 +500,7 @@ fn test_announcement_rebroadcast_duplicates() {
anns.insert(bob.node_announcement()); anns.insert(bob.node_announcement());
for rid in rids { for rid in rids {
alice.track_repo(&rid, policy::Scope::All).unwrap(); alice.seed(&rid, policy::Scope::All).unwrap();
anns.insert(carol.refs_announcement(rid)); anns.insert(carol.refs_announcement(rid));
anns.insert(bob.refs_announcement(rid)); anns.insert(bob.refs_announcement(rid));
} }
@ -676,9 +672,9 @@ fn test_refs_announcement_relay() {
}; };
let bob_inv = bob.storage().inventory().unwrap(); let bob_inv = bob.storage().inventory().unwrap();
alice.track_repo(&bob_inv[0], policy::Scope::All).unwrap(); alice.seed(&bob_inv[0], policy::Scope::All).unwrap();
alice.track_repo(&bob_inv[1], policy::Scope::All).unwrap(); alice.seed(&bob_inv[1], policy::Scope::All).unwrap();
alice.track_repo(&bob_inv[2], policy::Scope::All).unwrap(); alice.seed(&bob_inv[2], policy::Scope::All).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
alice.connect_to(&eve); alice.connect_to(&eve);
alice.receive(eve.id(), Message::Subscribe(Subscribe::all())); alice.receive(eve.id(), Message::Subscribe(Subscribe::all()));
@ -742,7 +738,7 @@ fn test_refs_announcement_fetch_trusted_no_inventory() {
let bob_inv = bob.storage().inventory().unwrap(); let bob_inv = bob.storage().inventory().unwrap();
let rid = bob_inv[0]; let rid = bob_inv[0];
alice.track_repo(&rid, policy::Scope::Followed).unwrap(); alice.seed(&rid, policy::Scope::Followed).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
// Alice receives Bob's refs. // Alice receives Bob's refs.
@ -798,7 +794,7 @@ fn test_refs_announcement_followed() {
// Alice uses Scope::Followed, and did not track Bob yet. // Alice uses Scope::Followed, and did not track Bob yet.
alice.connect_to(&bob); alice.connect_to(&bob);
alice.track_repo(&rid, policy::Scope::Followed).unwrap(); alice.seed(&rid, policy::Scope::Followed).unwrap();
// Alice receives Bob's refs // Alice receives Bob's refs
alice.receive(bob.id(), bob.refs_announcement(rid)); alice.receive(bob.id(), bob.refs_announcement(rid));
@ -811,7 +807,7 @@ fn test_refs_announcement_followed() {
// Alice starts to track Bob. // Alice starts to track Bob.
let (sender, receiver) = chan::bounded(1); let (sender, receiver) = chan::bounded(1);
alice.command(Command::TrackNode( alice.command(Command::Follow(
bob.id, bob.id,
Some(node::Alias::new("bob")), Some(node::Alias::new("bob")),
sender, sender,
@ -834,7 +830,7 @@ fn test_refs_announcement_no_subscribe() {
let eve = Peer::new("eve", [9, 9, 9, 9]); let eve = Peer::new("eve", [9, 9, 9, 9]);
let id = arbitrary::gen(1); let id = arbitrary::gen(1);
alice.track_repo(&id, policy::Scope::All).unwrap(); alice.seed(&id, policy::Scope::All).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
alice.connect_to(&eve); alice.connect_to(&eve);
alice.receive(bob.id(), bob.refs_announcement(rid)); alice.receive(bob.id(), bob.refs_announcement(rid));
@ -863,7 +859,7 @@ fn test_refs_announcement_offline() {
let inv = alice.inventory(); let inv = alice.inventory();
let rid = inv.first().unwrap(); let rid = inv.first().unwrap();
let mut bob = Peer::new("bob", [8, 8, 8, 8]); let mut bob = Peer::new("bob", [8, 8, 8, 8]);
bob.track_repo(rid, policy::Scope::All).unwrap(); bob.seed(rid, policy::Scope::All).unwrap();
// Make sure alice's service wasn't initialized before. // Make sure alice's service wasn't initialized before.
assert!(alice.initialize()); assert!(alice.initialize());
@ -1248,14 +1244,14 @@ fn test_maintain_connections_failed_attempt() {
} }
#[test] #[test]
fn test_track_repo_subscribe() { fn test_seed_repo_subscribe() {
let mut alice = Peer::new("alice", [7, 7, 7, 7]); let mut alice = Peer::new("alice", [7, 7, 7, 7]);
let bob = Peer::new("bob", [8, 8, 8, 8]); let bob = Peer::new("bob", [8, 8, 8, 8]);
let rid = arbitrary::gen::<Id>(1); let rid = arbitrary::gen::<Id>(1);
let (send, recv) = chan::bounded(1); let (send, recv) = chan::bounded(1);
alice.connect_to(&bob); alice.connect_to(&bob);
alice.command(Command::TrackRepo(rid, policy::Scope::default(), send)); alice.command(Command::Seed(rid, policy::Scope::default(), send));
assert!(recv.recv().unwrap()); assert!(recv.recv().unwrap());
assert_matches!( assert_matches!(
@ -1275,7 +1271,7 @@ fn test_fetch_missing_inventory_on_gossip() {
let bob = Peer::new("bob", [8, 8, 8, 8]); let bob = Peer::new("bob", [8, 8, 8, 8]);
let now = LocalTime::now(); let now = LocalTime::now();
alice.track_repo(&rid, node::policy::Scope::All).unwrap(); alice.seed(&rid, node::policy::Scope::All).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
alice.receive( alice.receive(
bob.id(), bob.id(),
@ -1300,7 +1296,7 @@ fn test_fetch_missing_inventory_on_schedule() {
let bob = Peer::new("bob", [8, 8, 8, 8]); let bob = Peer::new("bob", [8, 8, 8, 8]);
let now = LocalTime::now(); let now = LocalTime::now();
alice.track_repo(&rid, node::policy::Scope::All).unwrap(); alice.seed(&rid, node::policy::Scope::All).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
alice.receive( alice.receive(
bob.id(), bob.id(),
@ -1441,7 +1437,7 @@ fn test_refs_synced_event() {
}); });
let msg = ann.signed(bob.signer()); let msg = ann.signed(bob.signer());
alice.track_repo(&acme, policy::Scope::All).unwrap(); alice.seed(&acme, policy::Scope::All).unwrap();
alice.connect_to(&bob); alice.connect_to(&bob);
alice.receive(bob.id, Message::Announcement(msg)); alice.receive(bob.id, Message::Announcement(msg));
@ -1540,14 +1536,14 @@ fn test_push_and_pull() {
// Bob seeds Alice's project. // Bob seeds Alice's project.
let (sender, _) = chan::bounded(1); let (sender, _) = chan::bounded(1);
bob.command(service::Command::TrackRepo( bob.command(service::Command::Seed(
proj_id, proj_id,
policy::Scope::default(), policy::Scope::default(),
sender, sender,
)); ));
// Eve seeds Alice's project. // Eve seeds Alice's project.
let (sender, _) = chan::bounded(1); let (sender, _) = chan::bounded(1);
eve.command(service::Command::TrackRepo( eve.command(service::Command::Seed(
proj_id, proj_id,
policy::Scope::default(), policy::Scope::default(),
sender, sender,

View File

@ -163,8 +163,8 @@ fn test_replication() {
let inventory = alice.storage.inventory().unwrap(); let inventory = alice.storage.inventory().unwrap();
assert!(inventory.is_empty()); assert!(inventory.is_empty());
let tracked = alice.handle.seed(acme, Scope::All).unwrap(); let updated = alice.handle.seed(acme, Scope::All).unwrap();
assert!(tracked); assert!(updated);
let seeds = alice.handle.seeds(acme).unwrap(); let seeds = alice.handle.seeds(acme).unwrap();
assert!(seeds.is_connected(&bob.id)); assert!(seeds.is_connected(&bob.id));
@ -314,8 +314,8 @@ fn test_migrated_clone() {
alice.connect(&bob); alice.connect(&bob);
converge([&alice, &bob]); converge([&alice, &bob]);
let tracked = bob.handle.seed(acme, Scope::All).unwrap(); let updated = bob.handle.seed(acme, Scope::All).unwrap();
assert!(tracked); assert!(updated);
let result = bob.handle.fetch(acme, alice.id, DEFAULT_TIMEOUT).unwrap(); let result = bob.handle.fetch(acme, alice.id, DEFAULT_TIMEOUT).unwrap();
assert!(result.is_success()); assert!(result.is_success());

View File

@ -50,11 +50,11 @@ pub enum FetchError {
#[error(transparent)] #[error(transparent)]
Storage(#[from] radicle::storage::Error), Storage(#[from] radicle::storage::Error),
#[error(transparent)] #[error(transparent)]
TrackingConfig(#[from] radicle::node::policy::store::Error), PolicyStore(#[from] radicle::node::policy::store::Error),
#[error(transparent)] #[error(transparent)]
Tracked(#[from] radicle_fetch::tracking::error::Tracking), Policy(#[from] radicle_fetch::policy::error::Policy),
#[error(transparent)] #[error(transparent)]
Blocked(#[from] radicle_fetch::tracking::error::Blocked), Blocked(#[from] radicle_fetch::policy::error::Blocked),
} }
impl FetchError { impl FetchError {
@ -156,8 +156,8 @@ pub struct FetchConfig {
pub policy: Policy, pub policy: Policy,
/// Default scope, if a scope for a specific repository was not found. /// Default scope, if a scope for a specific repository was not found.
pub scope: policy::Scope, pub scope: policy::Scope,
/// Path to the tracking database. /// Path to the policies database.
pub tracking_db: PathBuf, pub policies_db: PathBuf,
/// Data limits when fetching from a remote. /// Data limits when fetching from a remote.
pub limit: FetchLimit, pub limit: FetchLimit,
/// Public key of the local peer. /// Public key of the local peer.
@ -278,18 +278,18 @@ impl Worker {
let FetchConfig { let FetchConfig {
policy, policy,
scope, scope,
tracking_db, policies_db,
limit, limit,
local, local,
expiry, expiry,
} = &self.fetch_config; } = &self.fetch_config;
let policies = policy::Config::new(*policy, *scope, policy::Store::reader(tracking_db)?); let policies = policy::Config::new(*policy, *scope, policy::Store::reader(policies_db)?);
// N.b. if the `rid` is blocked this will return an error, so // N.b. if the `rid` is blocked this will return an error, so
// we won't continue with any further set up of the fetch. // we won't continue with any further set up of the fetch.
let tracked = radicle_fetch::Tracked::from_config(rid, &policies)?; let allowed = radicle_fetch::Allowed::from_config(rid, &policies)?;
let blocked = radicle_fetch::BlockList::from_config(&policies)?; let blocked = radicle_fetch::BlockList::from_config(&policies)?;
let handle = fetch::Handle::new(rid, *local, &self.storage, tracked, blocked, channels)?; let handle = fetch::Handle::new(rid, *local, &self.storage, allowed, blocked, channels)?;
let result = handle.fetch(rid, &self.storage, *limit, remote, refs_at)?; let result = handle.fetch(rid, &self.storage, *limit, remote, refs_at)?;
if let Err(e) = garbage::collect(&self.storage, rid, *expiry) { if let Err(e) = garbage::collect(&self.storage, rid, *expiry) {

View File

@ -7,7 +7,7 @@ use radicle::prelude::Id;
use radicle::storage::refs::RefsAt; use radicle::storage::refs::RefsAt;
use radicle::storage::{ReadStorage as _, RefUpdate, WriteRepository as _}; use radicle::storage::{ReadStorage as _, RefUpdate, WriteRepository as _};
use radicle::Storage; use radicle::Storage;
use radicle_fetch::{BlockList, FetchLimit, Tracked}; use radicle_fetch::{Allowed, BlockList, FetchLimit};
use super::channels::ChannelsFlush; use super::channels::ChannelsFlush;
@ -34,18 +34,18 @@ impl Handle {
rid: Id, rid: Id,
local: PublicKey, local: PublicKey,
storage: &Storage, storage: &Storage,
tracked: Tracked, follow: Allowed,
blocked: BlockList, blocked: BlockList,
channels: ChannelsFlush, channels: ChannelsFlush,
) -> Result<Self, error::Handle> { ) -> Result<Self, error::Handle> {
let exists = storage.contains(&rid)?; let exists = storage.contains(&rid)?;
if exists { if exists {
let repo = storage.repository(rid)?; let repo = storage.repository(rid)?;
let handle = radicle_fetch::Handle::new(local, repo, tracked, blocked, channels)?; let handle = radicle_fetch::Handle::new(local, repo, follow, blocked, channels)?;
Ok(Handle::Pull { handle }) Ok(Handle::Pull { handle })
} else { } else {
let (repo, tmp) = storage.lock_repository(rid)?; let (repo, tmp) = storage.lock_repository(rid)?;
let handle = radicle_fetch::Handle::new(local, repo, tracked, blocked, channels)?; let handle = radicle_fetch::Handle::new(local, repo, follow, blocked, channels)?;
Ok(Handle::Clone { handle, tmp }) Ok(Handle::Clone { handle, tmp })
} }
} }

View File

@ -47,8 +47,8 @@ pub const DEFAULT_TIMEOUT: time::Duration = time::Duration::from_secs(9);
pub const MAX_ALIAS_LENGTH: usize = 32; pub const MAX_ALIAS_LENGTH: usize = 32;
/// Filename of node database under the node directory. /// Filename of node database under the node directory.
pub const NODE_DB_FILE: &str = "node.db"; pub const NODE_DB_FILE: &str = "node.db";
/// Filename of tracking table database under the node directory. /// Filename of policies database under the node directory.
pub const TRACKING_DB_FILE: &str = "tracking.db"; pub const POLICIES_DB_FILE: &str = "policies.db";
/// Filename of last node announcement, when running in debug mode. /// Filename of last node announcement, when running in debug mode.
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub const NODE_ANNOUNCEMENT_FILE: &str = "announcement.wire.debug"; pub const NODE_ANNOUNCEMENT_FILE: &str = "announcement.wire.debug";

View File

@ -211,10 +211,10 @@ pub struct Config {
/// Configured service limits. /// Configured service limits.
#[serde(default)] #[serde(default)]
pub limits: Limits, pub limits: Limits,
/// Default tracking policy. /// Default seeding policy.
#[serde(default)] #[serde(default)]
pub policy: Policy, pub policy: Policy,
/// Default tracking scope. /// Default seeding scope.
#[serde(default)] #[serde(default)]
pub scope: Scope, pub scope: Scope,
} }

View File

@ -111,7 +111,7 @@ impl fmt::Display for Scope {
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
#[error("invalid tracking scope: {0:?}")] #[error("invalid seeding scope: {0:?}")]
pub struct ParseScopeError(String); pub struct ParseScopeError(String);
impl FromStr for Scope { impl FromStr for Scope {

View File

@ -10,21 +10,21 @@ use crate::prelude::{Id, NodeId};
use crate::storage::{Namespaces, ReadRepository as _, ReadStorage, RepositoryError}; use crate::storage::{Namespaces, ReadRepository as _, ReadStorage, RepositoryError};
pub use crate::node::policy::store; pub use crate::node::policy::store;
pub use crate::node::policy::store::Config as 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::{Alias, Node, Policy, Repo, Scope}; pub use crate::node::policy::{Alias, Node, Policy, Repo, Scope};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum NamespacesError { pub enum NamespacesError {
#[error("failed to find tracking policy for {rid}")] #[error("failed to find policy for {rid}")]
FailedPolicy { FailedPolicy {
rid: Id, rid: Id,
#[source] #[source]
err: Error, err: Error,
}, },
#[error("cannot fetch {rid} as it is not tracked")] #[error("cannot fetch {rid} as it is not seeded")]
BlockedPolicy { rid: Id }, BlockedPolicy { rid: Id },
#[error("failed to get tracking nodes for {rid}")] #[error("failed to get node policies for {rid}")]
FailedNodes { FailedNodes {
rid: Id, rid: Id,
#[source] #[source]
@ -42,7 +42,7 @@ pub enum NamespacesError {
NoFollowed { rid: Id }, NoFollowed { rid: Id },
} }
/// Tracking configuration. /// Policies configuration.
pub struct Config<T> { pub struct Config<T> {
/// Default policy, if a policy for a specific node or repository was not found. /// Default policy, if a policy for a specific node or repository was not found.
policy: Policy, policy: Policy,
@ -65,7 +65,7 @@ impl<T> fmt::Debug for Config<T> {
} }
impl<T> Config<T> { impl<T> Config<T> {
/// Create a new tracking configuration. /// Create a new policy configuration.
pub fn new(policy: Policy, scope: Scope, store: Store<T>) -> Self { pub fn new(policy: Policy, scope: Scope, store: Store<T>) -> Self {
Self { Self {
policy, policy,
@ -74,32 +74,32 @@ impl<T> Config<T> {
} }
} }
/// Check if a repository is tracked. /// Check if a repository is seeded.
pub fn is_repo_tracked(&self, id: &Id) -> Result<bool, Error> { pub fn is_seeding(&self, id: &Id) -> Result<bool, Error> {
self.repo_policy(id) self.repo_policy(id)
.map(|entry| entry.policy == Policy::Allow) .map(|entry| entry.policy == Policy::Allow)
} }
/// Check if a node is tracked. /// Check if a node is followed.
pub fn is_node_tracked(&self, id: &NodeId) -> Result<bool, Error> { pub fn is_following(&self, id: &NodeId) -> Result<bool, Error> {
self.node_policy(id) self.node_policy(id)
.map(|entry| entry.policy == Policy::Allow) .map(|entry| entry.policy == Policy::Allow)
} }
/// Get a node's tracking 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 node_policy(&self, id: &NodeId) -> Result<Node, Error> {
Ok(self.store.node_policy(id)?.unwrap_or(Node { Ok(self.store.follow_policy(id)?.unwrap_or(Node {
id: *id, id: *id,
alias: None, alias: None,
policy: self.policy, policy: self.policy,
})) }))
} }
/// Get a repository's tracking information. /// Get a repository's seediing 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: &Id) -> Result<Repo, Error> { pub fn repo_policy(&self, id: &Id) -> Result<Repo, Error> {
Ok(self.store.repo_policy(id)?.unwrap_or(Repo { Ok(self.store.seed_policy(id)?.unwrap_or(Repo {
id: *id, id: *id,
scope: self.scope, scope: self.scope,
policy: self.policy, policy: self.policy,
@ -124,7 +124,7 @@ impl<T> Config<T> {
Scope::All => Ok(Namespaces::All), Scope::All => Ok(Namespaces::All),
Scope::Followed => { Scope::Followed => {
let nodes = self let nodes = self
.node_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.id))

View File

@ -32,23 +32,23 @@ pub struct Read;
pub struct Write; pub struct Write;
/// Read only config. /// Read only config.
pub type ConfigReader = Config<Read>; pub type StoreReader = Store<Read>;
/// Read-write config. /// Read-write config.
pub type ConfigWriter = Config<Write>; pub type StoreWriter = Store<Write>;
/// Tracking configuration. /// Policy configuration.
pub struct Config<T> { pub struct Store<T> {
db: sql::Connection, db: sql::Connection,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
impl<T> fmt::Debug for Config<T> { impl<T> fmt::Debug for Store<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Config(..)") write!(f, "Store(..)")
} }
} }
impl Config<Read> { impl Store<Read> {
const SCHEMA: &'static str = include_str!("schema.sql"); const SCHEMA: &'static str = include_str!("schema.sql");
/// Same as [`Self::open`], but in read-only mode. This is useful to have multiple /// Same as [`Self::open`], but in read-only mode. This is useful to have multiple
@ -80,7 +80,7 @@ impl Config<Read> {
} }
} }
impl Config<Write> { impl Store<Write> {
const SCHEMA: &'static str = include_str!("schema.sql"); const SCHEMA: &'static str = include_str!("schema.sql");
/// Open a policy store at the given path. Creates a new store if it /// Open a policy store at the given path. Creates a new store if it
@ -108,15 +108,15 @@ impl Config<Write> {
} }
/// Get a read-only version of this store. /// Get a read-only version of this store.
pub fn read_only(self) -> ConfigReader { pub fn read_only(self) -> StoreReader {
Config { Store {
db: self.db, db: self.db,
_marker: PhantomData, _marker: PhantomData,
} }
} }
/// Track a node. /// Follow a node.
pub fn track_node(&mut self, id: &NodeId, alias: Option<&str>) -> Result<bool, Error> { pub fn follow(&mut self, id: &NodeId, alias: Option<&str>) -> Result<bool, Error> {
let mut stmt = self.db.prepare( let mut stmt = self.db.prepare(
"INSERT INTO `following` (id, alias) "INSERT INTO `following` (id, alias)
VALUES (?1, ?2) VALUES (?1, ?2)
@ -131,8 +131,8 @@ impl Config<Write> {
Ok(self.db.change_count() > 0) Ok(self.db.change_count() > 0)
} }
/// Track a repository. /// Seed a repository.
pub fn track_repo(&mut self, id: &Id, scope: Scope) -> Result<bool, Error> { pub fn seed(&mut self, id: &Id, scope: Scope) -> Result<bool, Error> {
let mut stmt = self.db.prepare( let mut stmt = self.db.prepare(
"INSERT INTO `seeding` (id, scope) "INSERT INTO `seeding` (id, scope)
VALUES (?1, ?2) VALUES (?1, ?2)
@ -147,8 +147,8 @@ impl Config<Write> {
Ok(self.db.change_count() > 0) Ok(self.db.change_count() > 0)
} }
/// Set a node's tracking policy. /// Set a node's follow policy.
pub fn set_node_policy(&mut self, id: &NodeId, policy: Policy) -> Result<bool, Error> { pub fn set_follow_policy(&mut self, id: &NodeId, policy: Policy) -> Result<bool, Error> {
let mut stmt = self.db.prepare( let mut stmt = self.db.prepare(
"INSERT INTO `following` (id, policy) "INSERT INTO `following` (id, policy)
VALUES (?1, ?2) VALUES (?1, ?2)
@ -163,8 +163,8 @@ impl Config<Write> {
Ok(self.db.change_count() > 0) Ok(self.db.change_count() > 0)
} }
/// Set a repository's tracking policy. /// Set a repository's seeding policy.
pub fn set_repo_policy(&mut self, id: &Id, policy: Policy) -> Result<bool, Error> { pub fn set_seed_policy(&mut self, id: &Id, policy: Policy) -> Result<bool, Error> {
let mut stmt = self.db.prepare( let mut stmt = self.db.prepare(
"INSERT INTO `seeding` (id, policy) "INSERT INTO `seeding` (id, policy)
VALUES (?1, ?2) VALUES (?1, ?2)
@ -179,8 +179,8 @@ impl Config<Write> {
Ok(self.db.change_count() > 0) Ok(self.db.change_count() > 0)
} }
/// Untrack a node. /// Unfollow a node.
pub fn untrack_node(&mut self, id: &NodeId) -> Result<bool, Error> { pub fn unfollow(&mut self, id: &NodeId) -> Result<bool, Error> {
let mut stmt = self.db.prepare("DELETE FROM `following` WHERE id = ?")?; let mut stmt = self.db.prepare("DELETE FROM `following` WHERE id = ?")?;
stmt.bind((1, id))?; stmt.bind((1, id))?;
@ -189,8 +189,8 @@ impl Config<Write> {
Ok(self.db.change_count() > 0) Ok(self.db.change_count() > 0)
} }
/// Untrack a repository. /// Unseed a repository.
pub fn untrack_repo(&mut self, id: &Id) -> Result<bool, Error> { pub fn unseed(&mut self, id: &Id) -> Result<bool, Error> {
let mut stmt = self.db.prepare("DELETE FROM `seeding` WHERE id = ?")?; let mut stmt = self.db.prepare("DELETE FROM `seeding` WHERE id = ?")?;
stmt.bind((1, id))?; stmt.bind((1, id))?;
@ -202,11 +202,11 @@ impl Config<Write> {
/// `Read` methods for `Config`. This implies that a /// `Read` methods for `Config`. This implies that a
/// `Config<Write>` can access these functions as well. /// `Config<Write>` can access these functions as well.
impl<T> Config<T> { impl<T> Store<T> {
/// Check if a node is tracked. /// Check if a node is followed.
pub fn is_node_tracked(&self, id: &NodeId) -> Result<bool, Error> { pub fn is_node_followed(&self, id: &NodeId) -> Result<bool, Error> {
Ok(matches!( Ok(matches!(
self.node_policy(id)?, self.follow_policy(id)?,
Some(Node { Some(Node {
policy: Policy::Allow, policy: Policy::Allow,
.. ..
@ -214,10 +214,10 @@ impl<T> Config<T> {
)) ))
} }
/// Check if a repository is tracked. /// Check if a repository is seeded.
pub fn is_repo_tracked(&self, id: &Id) -> Result<bool, Error> { pub fn is_repo_seeded(&self, id: &Id) -> Result<bool, Error> {
Ok(matches!( Ok(matches!(
self.repo_policy(id)?, self.seed_policy(id)?,
Some(Repo { Some(Repo {
policy: Policy::Allow, policy: Policy::Allow,
.. ..
@ -225,8 +225,8 @@ impl<T> Config<T> {
)) ))
} }
/// Get a node's tracking policy. /// Get a node's follow policy.
pub fn node_policy(&self, id: &NodeId) -> Result<Option<Node>, Error> { pub fn follow_policy(&self, id: &NodeId) -> Result<Option<Node>, 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 = ?")?;
@ -251,8 +251,8 @@ impl<T> Config<T> {
Ok(None) Ok(None)
} }
/// Get a repository's tracking policy. /// Get a repository's seeding policy.
pub fn repo_policy(&self, id: &Id) -> Result<Option<Repo>, Error> { pub fn seed_policy(&self, id: &Id) -> Result<Option<Repo>, 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 = ?")?;
@ -269,8 +269,8 @@ impl<T> Config<T> {
Ok(None) Ok(None)
} }
/// Get node tracking policies. /// Get node follow policies.
pub fn node_policies(&self) -> Result<Box<dyn Iterator<Item = Node>>, Error> { pub fn follow_policies(&self) -> Result<Box<dyn Iterator<Item = Node>>, 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`")?
@ -293,8 +293,8 @@ impl<T> Config<T> {
} }
// TODO: see if sql can return iterator directly // TODO: see if sql can return iterator directly
/// Get repository tracking policies. /// Get repository seed policies.
pub fn repo_policies(&self) -> Result<Box<dyn Iterator<Item = Repo>>, Error> { pub fn seed_policies(&self) -> Result<Box<dyn Iterator<Item = Repo>>, 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`")?
@ -312,11 +312,11 @@ impl<T> Config<T> {
} }
} }
impl<T> AliasStore for Config<T> { impl<T> AliasStore for Store<T> {
/// Retrieve `alias` of given node. /// Retrieve `alias` of given node.
/// Calls `Self::node_policy` under the hood. /// Calls `Self::node_policy` under the hood.
fn alias(&self, nid: &NodeId) -> Option<Alias> { fn alias(&self, nid: &NodeId) -> Option<Alias> {
self.node_policy(nid) self.follow_policy(nid)
.map(|node| node.and_then(|n| n.alias)) .map(|node| node.and_then(|n| n.alias))
.unwrap_or(None) .unwrap_or(None)
} }
@ -330,38 +330,38 @@ mod test {
use crate::test::arbitrary; use crate::test::arbitrary;
#[test] #[test]
fn test_track_and_untrack_node() { fn test_follow_and_unfollow_node() {
let id = arbitrary::gen::<NodeId>(1); let id = arbitrary::gen::<NodeId>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_node(&id, Some("eve")).unwrap()); assert!(db.follow(&id, Some("eve")).unwrap());
assert!(db.is_node_tracked(&id).unwrap()); assert!(db.is_node_followed(&id).unwrap());
assert!(!db.track_node(&id, Some("eve")).unwrap()); assert!(!db.follow(&id, Some("eve")).unwrap());
assert!(db.untrack_node(&id).unwrap()); assert!(db.unfollow(&id).unwrap());
assert!(!db.is_node_tracked(&id).unwrap()); assert!(!db.is_node_followed(&id).unwrap());
} }
#[test] #[test]
fn test_track_and_untrack_repo() { fn test_seed_and_unseed_repo() {
let id = arbitrary::gen::<Id>(1); let id = arbitrary::gen::<Id>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_repo(&id, Scope::All).unwrap()); assert!(db.seed(&id, Scope::All).unwrap());
assert!(db.is_repo_tracked(&id).unwrap()); assert!(db.is_repo_seeded(&id).unwrap());
assert!(!db.track_repo(&id, Scope::All).unwrap()); assert!(!db.seed(&id, Scope::All).unwrap());
assert!(db.untrack_repo(&id).unwrap()); assert!(db.unseed(&id).unwrap());
assert!(!db.is_repo_tracked(&id).unwrap()); assert!(!db.is_repo_seeded(&id).unwrap());
} }
#[test] #[test]
fn test_node_policies() { fn test_node_policies() {
let ids = arbitrary::vec::<NodeId>(3); let ids = arbitrary::vec::<NodeId>(3);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
for id in &ids { for id in &ids {
assert!(db.track_node(id, None).unwrap()); assert!(db.follow(id, None).unwrap());
} }
let mut entries = db.node_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(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[1]);
assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[2]); assert_matches!(entries.next(), Some(Node { id, .. }) if id == ids[2]);
@ -370,12 +370,12 @@ mod test {
#[test] #[test]
fn test_repo_policies() { fn test_repo_policies() {
let ids = arbitrary::vec::<Id>(3); let ids = arbitrary::vec::<Id>(3);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
for id in &ids { for id in &ids {
assert!(db.track_repo(id, Scope::All).unwrap()); assert!(db.seed(id, Scope::All).unwrap());
} }
let mut entries = db.repo_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(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[1]);
assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[2]); assert_matches!(entries.next(), Some(Repo { id, .. }) if id == ids[2]);
@ -384,19 +384,19 @@ mod test {
#[test] #[test]
fn test_update_alias() { fn test_update_alias() {
let id = arbitrary::gen::<NodeId>(1); let id = arbitrary::gen::<NodeId>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_node(&id, Some("eve")).unwrap()); assert!(db.follow(&id, Some("eve")).unwrap());
assert_eq!( assert_eq!(
db.node_policy(&id).unwrap().unwrap().alias, db.follow_policy(&id).unwrap().unwrap().alias,
Some(Alias::from_str("eve").unwrap()) Some(Alias::from_str("eve").unwrap())
); );
assert!(db.track_node(&id, None).unwrap()); assert!(db.follow(&id, None).unwrap());
assert_eq!(db.node_policy(&id).unwrap().unwrap().alias, None); assert_eq!(db.follow_policy(&id).unwrap().unwrap().alias, None);
assert!(!db.track_node(&id, None).unwrap()); assert!(!db.follow(&id, None).unwrap());
assert!(db.track_node(&id, Some("alice")).unwrap()); assert!(db.follow(&id, Some("alice")).unwrap());
assert_eq!( assert_eq!(
db.node_policy(&id).unwrap().unwrap().alias, db.follow_policy(&id).unwrap().unwrap().alias,
Some(Alias::new("alice")) Some(Alias::new("alice"))
); );
} }
@ -404,33 +404,39 @@ mod test {
#[test] #[test]
fn test_update_scope() { fn test_update_scope() {
let id = arbitrary::gen::<Id>(1); let id = arbitrary::gen::<Id>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_repo(&id, Scope::All).unwrap()); assert!(db.seed(&id, Scope::All).unwrap());
assert_eq!(db.repo_policy(&id).unwrap().unwrap().scope, Scope::All); assert_eq!(db.seed_policy(&id).unwrap().unwrap().scope, Scope::All);
assert!(db.track_repo(&id, Scope::Followed).unwrap()); assert!(db.seed(&id, Scope::Followed).unwrap());
assert_eq!(db.repo_policy(&id).unwrap().unwrap().scope, Scope::Followed); assert_eq!(db.seed_policy(&id).unwrap().unwrap().scope, Scope::Followed);
} }
#[test] #[test]
fn test_repo_policy() { fn test_repo_policy() {
let id = arbitrary::gen::<Id>(1); let id = arbitrary::gen::<Id>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_repo(&id, Scope::All).unwrap()); assert!(db.seed(&id, Scope::All).unwrap());
assert_eq!(db.repo_policy(&id).unwrap().unwrap().policy, Policy::Allow); assert_eq!(db.seed_policy(&id).unwrap().unwrap().policy, Policy::Allow);
assert!(db.set_repo_policy(&id, Policy::Block).unwrap()); assert!(db.set_seed_policy(&id, Policy::Block).unwrap());
assert_eq!(db.repo_policy(&id).unwrap().unwrap().policy, Policy::Block); assert_eq!(db.seed_policy(&id).unwrap().unwrap().policy, Policy::Block);
} }
#[test] #[test]
fn test_node_policy() { fn test_node_policy() {
let id = arbitrary::gen::<NodeId>(1); let id = arbitrary::gen::<NodeId>(1);
let mut db = Config::open(":memory:").unwrap(); let mut db = Store::open(":memory:").unwrap();
assert!(db.track_node(&id, None).unwrap()); assert!(db.follow(&id, None).unwrap());
assert_eq!(db.node_policy(&id).unwrap().unwrap().policy, Policy::Allow); assert_eq!(
assert!(db.set_node_policy(&id, Policy::Block).unwrap()); db.follow_policy(&id).unwrap().unwrap().policy,
assert_eq!(db.node_policy(&id).unwrap().unwrap().policy, Policy::Block); Policy::Allow
);
assert!(db.set_follow_policy(&id, Policy::Block).unwrap());
assert_eq!(
db.follow_policy(&id).unwrap().unwrap().policy,
Policy::Block
);
} }
} }

View File

@ -146,7 +146,7 @@ pub enum Error {
#[error("profile key `{0}` is not registered with ssh-agent")] #[error("profile key `{0}` is not registered with ssh-agent")]
KeyNotRegistered(PublicKey), KeyNotRegistered(PublicKey),
#[error(transparent)] #[error(transparent)]
TrackingStore(#[from] node::policy::store::Error), PolicyStore(#[from] node::policy::store::Error),
#[error(transparent)] #[error(transparent)]
DatabaseStore(#[from] node::db::Error), DatabaseStore(#[from] node::db::Error),
} }
@ -341,22 +341,6 @@ impl Profile {
} }
} }
/// Return a read-only handle to the tracking configuration of the node.
pub fn tracking(&self) -> Result<policy::store::ConfigReader, policy::store::Error> {
let path = self.home.node().join(node::TRACKING_DB_FILE);
let config = policy::store::Config::reader(path)?;
Ok(config)
}
/// Return a read-write handle to the tracking configuration of the node.
pub fn tracking_mut(&self) -> Result<policy::store::ConfigWriter, policy::store::Error> {
let path = self.home.node().join(node::TRACKING_DB_FILE);
let config = policy::store::Config::open(path)?;
Ok(config)
}
/// Get radicle home. /// Get radicle home.
pub fn home(&self) -> &Home { pub fn home(&self) -> &Home {
&self.home &self.home
@ -364,10 +348,10 @@ impl Profile {
/// Return a multi-source store for aliases. /// Return a multi-source store for aliases.
pub fn aliases(&self) -> Aliases { pub fn aliases(&self) -> Aliases {
let tracking = self.home.tracking().ok(); let policies = self.home.policies().ok();
let db = self.home.database().ok(); let db = self.home.database().ok();
Aliases { tracking, db } Aliases { policies, db }
} }
} }
@ -388,15 +372,15 @@ impl std::ops::DerefMut for Profile {
/// Holds multiple alias stores, and will try /// Holds multiple alias stores, and will try
/// them one by one when asking for an alias. /// them one by one when asking for an alias.
pub struct Aliases { pub struct Aliases {
tracking: Option<policy::store::ConfigReader>, policies: Option<policy::store::StoreReader>,
db: Option<node::Database>, db: Option<node::Database>,
} }
impl AliasStore for Aliases { impl AliasStore for Aliases {
/// Retrieve `alias` of given node. /// Retrieve `alias` of given node.
/// First looks in `tracking.db` and then `addresses.db`. /// First looks in `policies.db` and then `addresses.db`.
fn alias(&self, nid: &NodeId) -> Option<Alias> { fn alias(&self, nid: &NodeId) -> Option<Alias> {
self.tracking self.policies
.as_ref() .as_ref()
.and_then(|db| db.alias(nid)) .and_then(|db| db.alias(nid))
.or_else(|| self.db.as_ref().and_then(|db| db.alias(nid))) .or_else(|| self.db.as_ref().and_then(|db| db.alias(nid)))
@ -487,18 +471,18 @@ impl Home {
.unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME)) .unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
} }
/// Return a read-only handle to the tracking configuration of the node. /// Return a read-only handle to the policies of the node.
pub fn tracking(&self) -> Result<policy::store::ConfigReader, policy::store::Error> { pub fn policies(&self) -> Result<policy::store::StoreReader, policy::store::Error> {
let path = self.node().join(node::TRACKING_DB_FILE); let path = self.node().join(node::POLICIES_DB_FILE);
let config = policy::store::Config::reader(path)?; let config = policy::store::Store::reader(path)?;
Ok(config) Ok(config)
} }
/// Return a read-write handle to the tracking configuration of the node. /// Return a read-write handle to the policies of the node.
pub fn tracking_mut(&self) -> Result<policy::store::ConfigWriter, policy::store::Error> { pub fn policies_mut(&self) -> Result<policy::store::StoreWriter, policy::store::Error> {
let path = self.node().join(node::TRACKING_DB_FILE); let path = self.node().join(node::POLICIES_DB_FILE);
let config = policy::store::Config::open(path)?; let config = policy::store::Store::open(path)?;
Ok(config) Ok(config)
} }

View File

@ -52,7 +52,7 @@ pub struct RepositoryInfo<V> {
/// Identity document. /// Identity document.
pub doc: Doc<V>, pub doc: Doc<V>,
/// Local signed refs, if any. /// Local signed refs, if any.
/// Repositories with this set to `None` are ones that are tracked but not forked. /// Repositories with this set to `None` are ones that are seeded but not forked.
pub refs: Option<refs::SignedRefsAt>, pub refs: Option<refs::SignedRefsAt>,
} }