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.
For example, let's track a remote node we know about, and alias it to "eve":
To configure our node's seeding and follow policy, we can use the `rad seed`
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
✓ 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

View File

@ -22,7 +22,7 @@ Usage
local operator or a delegate of the repository.
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

View File

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

View File

@ -60,7 +60,7 @@ pub struct Options {
pub scope: Scope,
pub set_upstream: bool,
pub verbose: bool,
pub track: bool,
pub seed: bool,
}
impl Args for Options {
@ -77,7 +77,7 @@ impl Args for Options {
let mut set_upstream = false;
let mut setup_signing = false;
let mut scope = Scope::All;
let mut track = true;
let mut seed = true;
let mut verbose = false;
let mut visibility = None;
@ -129,8 +129,8 @@ impl Args for Options {
Long("no-confirm") => {
interactive = Interactive::No;
}
Long("no-track") => {
track = false;
Long("no-seed") => {
seed = false;
}
Long("private") => {
visibility = Some(Visibility::private([]));
@ -161,7 +161,7 @@ impl Args for Options {
interactive,
set_upstream,
setup_signing,
track,
seed,
visibility,
verbose,
},
@ -279,10 +279,10 @@ pub fn init(options: Options, profile: &profile::Profile) -> anyhow::Result<()>
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.
if options.track {
cli::project::track(id, options.scope, &mut node, profile)?;
if options.seed {
cli::project::seed(id, options.scope, &mut node, profile)?;
}
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 => {
let tracking = profile.tracking()?;
if let Some(repo) = tracking.repo_policy(&rid)? {
let tracking = profile.policies()?;
if let Some(repo) = tracking.seed_policy(&rid)? {
let tracking = match repo.policy {
Policy::Allow => term::format::positive("tracked"),
Policy::Block => term::format::negative("blocked"),

View File

@ -17,7 +17,7 @@ Usage
rad ls [<option>...]
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

View File

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

View File

@ -23,7 +23,7 @@ fn get_branch(git_ref: git::Qualified) -> git::RefString {
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`).
pub fn get_merge_target(
storage: &Repository,

View File

@ -131,7 +131,7 @@ pub fn update(
node: &mut Node,
profile: &Profile,
) -> 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" };
term::success!(
@ -143,7 +143,7 @@ pub fn update(
}
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));
}
Ok(())

View File

@ -279,8 +279,8 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
}
Operation::Synchronize(SyncMode::Repo { mode, direction }) => {
if [SyncDirection::Fetch, SyncDirection::Both].contains(&direction) {
if !profile.tracking()?.is_repo_tracked(&rid)? {
anyhow::bail!("repository {rid} is not tracked");
if !profile.policies()?.is_repo_seeded(&rid)? {
anyhow::bail!("repository {rid} is not seeded");
}
let results = fetch(rid, mode.clone(), options.timeout, &mut node)?;
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) {
Ok(updated) => updated,
Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?;
config.untrack_node(&nid)?
let mut config = profile.policies_mut()?;
config.unfollow(&nid)?
}
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,
/// by updating the tracking database directly.
pub fn track(
/// Seed a repository by first trying to seed through the node, and if the node isn't running,
/// by updating the policy database directly.
pub fn seed(
rid: Id,
scope: Scope,
node: &mut Node,
@ -63,21 +63,21 @@ pub fn track(
match node.seed(rid, scope) {
Ok(updated) => Ok(updated),
Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?;
config.track_repo(&rid, scope).map_err(|e| e.into())
let mut config = profile.policies_mut()?;
config.seed(&rid, scope).map_err(|e| 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,
/// by updating the tracking database directly.
pub fn untrack(rid: Id, node: &mut Node, profile: &Profile) -> Result<bool, anyhow::Error> {
/// Unseed a repository by first trying to unseed through the node, and if the node isn't running,
/// by updating the policy database directly.
pub fn unseed(rid: Id, node: &mut Node, profile: &Profile) -> Result<bool, anyhow::Error> {
match node.unseed(rid) {
Ok(updated) => Ok(updated),
Err(e) if e.is_connection_err() => {
let mut config = profile.tracking_mut()?;
config.untrack_repo(&rid).map_err(|e| e.into())
let mut config = profile.policies_mut()?;
config.unseed(&rid).map_err(|e| e.into())
}
Err(e) => Err(e.into()),
}

View File

@ -741,14 +741,14 @@ fn rad_clean() {
}
#[test]
fn rad_track() {
fn rad_seed_and_follow() {
let mut environment = Environment::new();
let alice = environment.node(Config::test(Alias::new("alice")));
let working = tempfile::tempdir().unwrap();
let alice = alice.spawn();
test(
"examples/rad-track.md",
"examples/rad-seed-and-follow.md",
working.path(),
Some(&alice.home),
[],
@ -897,7 +897,7 @@ fn rad_sync_without_node() {
let mut eve = environment.node(Config::test(Alias::new("eve")));
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")
.unwrap()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -64,7 +64,7 @@ impl Context {
let issues = issue::Issues::open(&repo)?.counts()?;
let patches = patch::Patches::open(&repo)?.counts()?;
let db = &self.profile.database()?;
let trackings = db.count(&id).unwrap_or_default();
let seeding = db.count(&id).unwrap_or_default();
Ok(project::Info {
payload,
@ -74,7 +74,7 @@ impl Context {
issues,
patches,
id,
trackings,
seeding,
})
}
@ -213,7 +213,7 @@ mod project {
pub patches: cob::patch::PatchCounts,
pub issues: cob::issue::IssueCounts,
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 trackings = db.count(&id.rid).unwrap_or_default();
let seeding = db.count(&id.rid).unwrap_or_default();
Some(Info {
payload,
@ -88,7 +88,7 @@ async fn delegates_projects_handler(
issues,
patches,
id: id.rid,
trackings,
seeding,
})
})
.skip(page * per_page)
@ -146,7 +146,7 @@ mod routes {
"closed": 0,
},
"id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK",
"trackings": 0,
"seeding": 0,
},
{
"name": "hello-world",
@ -168,7 +168,7 @@ mod routes {
"closed": 0,
},
"id": RID,
"trackings": 0,
"seeding": 0,
},
])
);
@ -207,7 +207,7 @@ mod routes {
"closed": 0,
},
"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))
}
/// Return local tracking repos information.
/// Return local repo policies information.
/// `GET /node/policies/repos`
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();
for policy::Repo { id, scope, policy } in tracking.repo_policies()? {
for policy::Repo { id, scope, policy } in policies.seed_policies()? {
repos.push(json!({
"id": id,
"scope": scope,
@ -68,7 +68,7 @@ async fn node_policies_repos_handler(State(ctx): State<Context>) -> impl IntoRes
Ok::<_, Error>(Json(repos))
}
/// Track a new repo.
/// Seed a new repo.
/// `PUT /node/policies/repos/:rid`
async fn node_policies_seed_handler(
State(ctx): State<Context>,
@ -90,7 +90,7 @@ async fn node_policies_seed_handler(
Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true }))))
}
/// Untrack a repo.
/// Unseed a repo.
/// `DELETE /node/policies/repos/:rid`
async fn node_policies_unseed_handler(
State(ctx): State<Context>,

View File

@ -119,7 +119,7 @@ async fn project_root_handler(
return None;
};
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 {
payload,
@ -129,7 +129,7 @@ async fn project_root_handler(
issues,
patches,
id: id.rid,
trackings,
seeding,
})
})
.skip(page * per_page)
@ -994,7 +994,7 @@ mod routes {
"closed": 0,
},
"id": "rad:zLuTzcmoWMcdK37xqArS8eckp9vK",
"trackings": 0,
"seeding": 0,
},
{
"name": "hello-world",
@ -1016,7 +1016,7 @@ mod routes {
"closed": 0,
},
"id": RID,
"trackings": 0,
"seeding": 0,
},
])
);
@ -1051,7 +1051,7 @@ mod routes {
"closed": 0,
},
"id": RID,
"trackings": 0,
"seeding": 0,
}
])
);
@ -1086,7 +1086,7 @@ mod routes {
"closed": 0,
},
"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();
profile.tracking_mut().unwrap();
profile.policies_mut().unwrap();
profile.database_mut().unwrap(); // Create the database.
let workdir = dir.join("hello-world-private");

View File

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

View File

@ -44,9 +44,9 @@ pub enum Error {
/// A node database error.
#[error("node database error: {0}")]
Database(#[from] node::db::Error),
/// A tracking database error.
#[error("tracking database error: {0}")]
Tracking(#[from] policy::Error),
/// A policies database error.
#[error("policies database error: {0}")]
Policy(#[from] policy::Error),
/// A gossip database error.
#[error("gossip database error: {0}")]
Gossip(#[from] gossip::Error),
@ -145,11 +145,11 @@ impl Runtime {
log::info!(target: "node", "Opening node database..");
let mut db: service::Stores<_> = home.database_mut()?.into();
log::info!(target: "node", "Opening tracking policy configuration..");
let tracking = home.tracking_mut()?;
let tracking = policy::Config::new(policy, scope, tracking);
log::info!(target: "node", "Opening policy database..");
let policies = home.policies_mut()?;
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);
let announcement = if let Some(ann) = fs::read(node_dir.join(node::NODE_ANNOUNCEMENT_FILE))
@ -202,7 +202,7 @@ impl Runtime {
clock,
db,
storage.clone(),
tracking,
policies,
signer.clone(),
rng,
announcement,
@ -237,7 +237,7 @@ impl Runtime {
let fetch = worker::FetchConfig {
policy,
scope,
tracking_db: home.node().join(node::TRACKING_DB_FILE),
policies_db: home.node().join(node::POLICIES_DB_FILE),
limit: FetchLimit::default(),
local: nid,
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> {
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)
}
fn unfollow(&mut self, id: NodeId) -> Result<bool, Error> {
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)
}
fn seed(&mut self, id: Id, scope: policy::Scope) -> Result<bool, Error> {
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)
}
fn unseed(&mut self, id: Id) -> Result<bool, Error> {
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)
}

View File

@ -140,7 +140,7 @@ pub enum Error {
#[error(transparent)]
Seeds(#[from] seed::Error),
#[error(transparent)]
Tracking(#[from] policy::Error),
Policy(#[from] policy::Error),
#[error(transparent)]
Repository(#[from] radicle::storage::RepositoryError),
#[error("namespaces error: {0}")]
@ -173,14 +173,14 @@ pub enum Command {
Seeds(Id, chan::Sender<Seeds>),
/// Fetch the given repository from the network.
Fetch(Id, NodeId, time::Duration, chan::Sender<FetchResult>),
/// Track the given repository.
TrackRepo(Id, Scope, chan::Sender<bool>),
/// Untrack the given repository.
UntrackRepo(Id, chan::Sender<bool>),
/// Track the given node.
TrackNode(NodeId, Option<Alias>, chan::Sender<bool>),
/// Untrack the given node.
UntrackNode(NodeId, chan::Sender<bool>),
/// Seed the given repository.
Seed(Id, Scope, chan::Sender<bool>),
/// Unseed the given repository.
Unseed(Id, chan::Sender<bool>),
/// Follow the given node.
Follow(NodeId, Option<Alias>, chan::Sender<bool>),
/// Unfollow the given node.
Unfollow(NodeId, chan::Sender<bool>),
/// Query the internal service state.
QueryState(Arc<QueryState>, chan::Sender<Result<(), CommandError>>),
}
@ -196,10 +196,10 @@ impl fmt::Debug for Command {
Self::Config(_) => write!(f, "Config"),
Self::Seeds(id, _) => write!(f, "Seeds({id})"),
Self::Fetch(id, node, _, _) => write!(f, "Fetch({id}, {node})"),
Self::TrackRepo(id, scope, _) => write!(f, "TrackRepo({id}, {scope})"),
Self::UntrackRepo(id, _) => write!(f, "UntrackRepo({id})"),
Self::TrackNode(id, _, _) => write!(f, "TrackNode({id})"),
Self::UntrackNode(id, _) => write!(f, "UntrackNode({id})"),
Self::Seed(id, scope, _) => write!(f, "Seed({id}, {scope})"),
Self::Unseed(id, _) => write!(f, "Unseed({id})"),
Self::Follow(id, _, _) => write!(f, "Follow({id})"),
Self::Unfollow(id, _) => write!(f, "Unfollow({id})"),
Self::QueryState { .. } => write!(f, "QueryState(..)"),
}
}
@ -213,7 +213,7 @@ pub enum CommandError {
#[error(transparent)]
Routing(#[from] routing::Error),
#[error(transparent)]
Tracking(#[from] policy::Error),
Policy(#[from] policy::Error),
}
/// Error returned by [`Service::try_fetch`].
@ -304,8 +304,8 @@ pub struct Service<D, S, G> {
storage: S,
/// Node database.
db: Stores<D>,
/// Tracking policy configuration.
tracking: policy::Config<Write>,
/// Policy configuration.
policies: policy::Config<Write>,
/// Peer sessions, currently or recently connected.
sessions: Sessions,
/// Clock. Tells the time.
@ -322,7 +322,7 @@ pub struct Service<D, S, G> {
queue: VecDeque<(Id, NodeId)>,
/// Request/connection rate limitter.
limiter: RateLimiter,
/// Current tracked repository bloom filter.
/// Current seeded repositories bloom filter.
filter: Filter,
/// Last time the service was idle.
last_idle: LocalTime,
@ -364,7 +364,7 @@ where
clock: LocalTime,
db: Stores<D>,
storage: S,
tracking: policy::Config<Write>,
policies: policy::Config<Write>,
signer: G,
rng: Rng,
node: NodeAnnouncement,
@ -375,7 +375,7 @@ where
Self {
config,
storage,
tracking,
policies,
signer,
rng,
node,
@ -402,42 +402,37 @@ where
self.outbox.next()
}
/// Track a repository.
/// Returns whether or not the tracking policy was updated.
pub fn track_repo(&mut self, id: &Id, scope: Scope) -> Result<bool, policy::Error> {
let updated = self.tracking.track_repo(id, scope)?;
/// Seed a repository.
/// Returns whether or not the repo policy was updated.
pub fn seed(&mut self, id: &Id, scope: Scope) -> Result<bool, policy::Error> {
let updated = self.policies.seed(id, scope)?;
self.filter.insert(id);
Ok(updated)
}
/// Untrack a repository.
/// Returns whether or not the tracking policy was updated.
/// Note that when untracking, we don't announce anything to the network. This is because by
/// Unseed a repository.
/// Returns whether or not the repo policy was updated.
/// 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.
pub fn untrack_repo(&mut self, id: &Id) -> Result<bool, policy::Error> {
let updated = self.tracking.untrack_repo(id)?;
// Nb. This is potentially slow if we have lots of projects. We should probably
// only re-compute the filter when we've untracked a certain amount of projects
pub fn unseed(&mut self, id: &Id) -> Result<bool, policy::Error> {
let updated = self.policies.unseed(id)?;
// Nb. This is potentially slow if we have lots of repos. We should probably
// only re-compute the filter when we've unseeded a certain amount of repos
// and the filter is really out of date.
//
// TODO: Share this code with initialization code.
self.filter = Filter::new(
self.tracking
.repo_policies()?
self.policies
.seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)),
);
Ok(updated)
}
/// Check whether we are tracking a certain repository.
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.
/// Find the closest `n` peers by proximity in seeding graphs.
/// 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)]
pub fn closest_peers(&self, n: usize) -> Vec<NodeId> {
todo!()
@ -463,9 +458,9 @@ where
&mut self.storage
}
/// Get the tracking policy.
pub fn tracking(&self) -> &policy::Config<Write> {
&self.tracking
/// Get the node policies.
pub fn policies(&self) -> &policy::Config<Write> {
&self.policies
}
/// Get the local signer.
@ -520,8 +515,8 @@ where
for (id, addr) in addrs.into_iter().map(|ca| ca.into()) {
self.connect(id, addr);
}
// Ensure that our inventory is recorded in our routing table, and we are tracking
// all of it. It can happen that inventory is not properly tracked if for eg. the
// 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 seeded if for eg. the
// user creates a new repository while the node is stopped.
let rids = self.storage.inventory()?;
self.db.routing_mut().insert(&rids, nid, time.as_millis())?;
@ -534,8 +529,8 @@ where
for rid in rids {
let repo = self.storage.repository(rid)?;
if !self.is_tracking(&rid)? {
warn!(target: "service", "Local repository {rid} is not tracked");
if !self.policies.is_seeding(&rid)? {
warn!(target: "service", "Local repository {rid} is not seeded");
}
// If we have no owned refs for this repo, then there's nothing to announce.
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.tracking
.repo_policies()?
self.policies
.seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id)),
);
// Try to establish some connections.
@ -677,12 +672,12 @@ where
Command::Fetch(rid, seed, timeout, resp) => {
self.fetch(rid, &seed, timeout, Some(resp));
}
Command::TrackRepo(rid, scope, resp) => {
// Update our tracking policy.
let tracked = self
.track_repo(&rid, scope)
.expect("Service::command: error tracking repository");
resp.send(tracked).ok();
Command::Seed(rid, scope, resp) => {
// Update our seeding policy.
let seeded = self
.seed(&rid, scope)
.expect("Service::command: error seeding repository");
resp.send(seeded).ok();
// Let all our peers know that we're interested in this repo from now on.
self.outbox.broadcast(
@ -690,25 +685,25 @@ where
self.sessions.connected().map(|(_, s)| s),
);
}
Command::UntrackRepo(id, resp) => {
let untracked = self
.untrack_repo(&id)
.expect("Service::command: error untracking repository");
resp.send(untracked).ok();
Command::Unseed(id, resp) => {
let updated = self
.unseed(&id)
.expect("Service::command: error unseeding repository");
resp.send(updated).ok();
}
Command::TrackNode(id, alias, resp) => {
let tracked = self
.tracking
.track_node(&id, alias.as_deref())
.expect("Service::command: error tracking node");
resp.send(tracked).ok();
Command::Follow(id, alias, resp) => {
let seeded = self
.policies
.follow(&id, alias.as_deref())
.expect("Service::command: error following node");
resp.send(seeded).ok();
}
Command::UntrackNode(id, resp) => {
let untracked = self
.tracking
.untrack_node(&id)
.expect("Service::command: error untracking node");
resp.send(untracked).ok();
Command::Unfollow(id, resp) => {
let updated = self
.policies
.unfollow(&id)
.expect("Service::command: error unfollowing node");
resp.send(updated).ok();
}
Command::AnnounceRefs(id, resp) => match self.announce_refs(id, [self.node_id()]) {
Ok(refs) => match refs.as_slice() {
@ -833,7 +828,7 @@ where
from,
subscribers: vec![],
});
let namespaces = self.tracking.namespaces_for(&self.storage, &rid)?;
let namespaces = self.policies.namespaces_for(&self.storage, &rid)?;
self.outbox
.fetch(session, rid, namespaces, refs_at, timeout);
@ -1190,10 +1185,10 @@ where
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.
if self.tracking.is_repo_tracked(id).expect(
"Service::handle_announcement: error accessing tracking configuration",
if self.policies.is_seeding(id).expect(
"Service::handle_announcement: error accessing seeding configuration",
) {
// 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.
@ -1202,7 +1197,7 @@ where
// Do nothing.
}
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);
}
Err(e) => {
@ -1262,8 +1257,8 @@ where
}
// TODO: Buffer/throttle fetches.
let repo_entry = self.tracking.repo_policy(&message.rid).expect(
"Service::handle_announcement: error accessing repo tracking configuration",
let repo_entry = self.policies.repo_policy(&message.rid).expect(
"Service::handle_announcement: error accessing repo seeding configuration",
);
if repo_entry.policy == Policy::Allow {
@ -1336,7 +1331,7 @@ where
} else {
debug!(
target: "service",
"Ignoring refs announcement from {announcer}: repository {} isn't tracked",
"Ignoring refs announcement from {announcer}: repository {} isn't seeded",
message.rid
);
}
@ -1425,7 +1420,7 @@ where
match scope {
policy::Scope::All => Ok(refs),
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::Followed(mut followed)) => {
// Get the set of followed nodes except self.
@ -1618,9 +1613,11 @@ where
info!(target: "service", "Routing table updated for {rid} with seed {from}");
self.emitter.emit(Event::SeedDiscovered { rid, nid: from });
if self.tracking.is_repo_tracked(&rid).expect(
"Service::process_inventory: error accessing tracking configuration",
) {
if self
.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
// refs we don't have.
}
@ -1797,7 +1794,7 @@ where
}
// 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.
for nid in self.db.routing().get(rid)? {
if nid == self.node_id() {
@ -1815,7 +1812,7 @@ where
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 {
if self.config.policy == Policy::Allow {
// 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> {
let inventory = self.storage().inventory()?;
let missing = self
.tracking
.repo_policies()?
.policies
.seed_policies()?
.filter_map(|t| (t.policy == Policy::Allow).then_some(t.id))
.filter(|rid| !inventory.contains(rid));
@ -1938,7 +1935,7 @@ where
// 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
// 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.
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::routing::Store;
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::profile;
use radicle::profile::Home;
@ -81,8 +81,8 @@ impl Environment {
let profile = self.profile(&config.alias);
let signer = MemorySigner::load(&profile.keystore, None).unwrap();
let tracking_db = profile.home.node().join(TRACKING_DB_FILE);
let tracking = policy::Config::open(tracking_db).unwrap();
let policies_db = profile.home.node().join(POLICIES_DB_FILE);
let policies = policy::Store::open(policies_db).unwrap();
let db = profile.database_mut().unwrap();
let db = service::Stores::from(db);
@ -92,7 +92,7 @@ impl Environment {
config,
signer,
db,
tracking,
policies,
storage: profile.storage,
}
}
@ -103,7 +103,7 @@ impl Environment {
let home = Home::new(self.tmp().join("home").join(alias).join(".radicle")).unwrap();
let keystore = Keystore::new(&home.keys());
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 config = profile::Config {
node: node::Config::new(alias.clone()),
@ -122,7 +122,7 @@ impl Environment {
)
.unwrap();
policy::Config::open(tracking_db).unwrap();
policy::Store::open(policies_db).unwrap();
home.database_mut().unwrap(); // Just create the database.
transport::local::register(storage.clone());
@ -149,7 +149,7 @@ pub struct Node<G> {
pub storage: Storage,
pub config: Config,
pub db: service::Stores<Database>,
pub tracking: policy::Config<policy::Write>,
pub policies: policy::Store<policy::Write>,
}
/// Handle to a running node.
@ -348,7 +348,7 @@ impl Node<MockSigner> {
},
)
.unwrap();
let tracking = home.tracking_mut().unwrap();
let policies = home.policies_mut().unwrap();
let db = home.database_mut().unwrap();
let db = service::Stores::from(db);
@ -360,7 +360,7 @@ impl Node<MockSigner> {
storage,
config,
db,
tracking,
policies,
}
}
}
@ -419,8 +419,8 @@ impl<G: cyphernet::Ecdh<Pk = NodeId> + Signer + Clone> Node<G> {
.unwrap();
assert!(self
.tracking
.track_repo(&id, node::policy::Scope::Followed)
.policies
.seed(&id, node::policy::Scope::Followed)
.unwrap());
log::debug!(

View File

@ -15,8 +15,8 @@ use crate::service::NodeId;
#[derive(Default, Clone)]
pub struct Handle {
pub updates: Arc<Mutex<Vec<Id>>>,
pub tracking_repos: Arc<Mutex<HashSet<Id>>>,
pub tracking_nodes: Arc<Mutex<HashSet<NodeId>>>,
pub seeding: Arc<Mutex<HashSet<Id>>>,
pub following: Arc<Mutex<HashSet<NodeId>>>,
}
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> {
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> {
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> {
Ok(self.tracking_nodes.lock().unwrap().insert(id))
Ok(self.following.lock().unwrap().insert(id))
}
fn subscribe(
@ -80,7 +80,7 @@ impl radicle::node::Handle for Handle {
}
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> {

View File

@ -162,8 +162,8 @@ where
storage: S,
mut config: Config<G>,
) -> Self {
let tracking = policy::Store::<policy::store::Write>::memory().unwrap();
let mut tracking = policy::Config::new(config.policy, config.scope, tracking);
let policies = policy::Store::<policy::store::Write>::memory().unwrap();
let mut policies = policy::Config::new(config.policy, config.scope, policies);
let id = *config.signer.public_key();
let ip = ip.into();
let local_addr = net::SocketAddr::new(ip, config.rng.u16(..));
@ -172,7 +172,7 @@ where
config.config.external_addresses.push(local_addr.into());
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 emitter: Emitter<Event> = Default::default();
@ -181,7 +181,7 @@ where
config.local_time,
config.db,
storage,
tracking,
policies,
config.signer,
config.rng.clone(),
announcement,

View File

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

View File

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

View File

@ -50,11 +50,11 @@ pub enum FetchError {
#[error(transparent)]
Storage(#[from] radicle::storage::Error),
#[error(transparent)]
TrackingConfig(#[from] radicle::node::policy::store::Error),
PolicyStore(#[from] radicle::node::policy::store::Error),
#[error(transparent)]
Tracked(#[from] radicle_fetch::tracking::error::Tracking),
Policy(#[from] radicle_fetch::policy::error::Policy),
#[error(transparent)]
Blocked(#[from] radicle_fetch::tracking::error::Blocked),
Blocked(#[from] radicle_fetch::policy::error::Blocked),
}
impl FetchError {
@ -156,8 +156,8 @@ pub struct FetchConfig {
pub policy: Policy,
/// Default scope, if a scope for a specific repository was not found.
pub scope: policy::Scope,
/// Path to the tracking database.
pub tracking_db: PathBuf,
/// Path to the policies database.
pub policies_db: PathBuf,
/// Data limits when fetching from a remote.
pub limit: FetchLimit,
/// Public key of the local peer.
@ -278,18 +278,18 @@ impl Worker {
let FetchConfig {
policy,
scope,
tracking_db,
policies_db,
limit,
local,
expiry,
} = &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
// 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 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)?;
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::{ReadStorage as _, RefUpdate, WriteRepository as _};
use radicle::Storage;
use radicle_fetch::{BlockList, FetchLimit, Tracked};
use radicle_fetch::{Allowed, BlockList, FetchLimit};
use super::channels::ChannelsFlush;
@ -34,18 +34,18 @@ impl Handle {
rid: Id,
local: PublicKey,
storage: &Storage,
tracked: Tracked,
follow: Allowed,
blocked: BlockList,
channels: ChannelsFlush,
) -> Result<Self, error::Handle> {
let exists = storage.contains(&rid)?;
if exists {
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 })
} else {
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 })
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ pub struct RepositoryInfo<V> {
/// Identity document.
pub doc: Doc<V>,
/// 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>,
}