radicle: Rename many more methods using new naming
This commit is contained in:
parent
1b026ae0ee
commit
6ca7da2768
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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:?}");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
])
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}..");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue