From d973fd42f2e04bdf8f9c33f5ddba2497a5c750cd Mon Sep 17 00:00:00 2001 From: cloudhead Date: Wed, 9 Aug 2023 10:48:58 +0200 Subject: [PATCH] cli: Auto-connect on sync This adds functionality so that on `rad sync` and `rad clone`, we connect to known seeds if necessary, before attempting to fetch. In passing, some related changes were made: * The `rad sync` command's arguments were reworked: `--replicas ` can be used to specify a replica count when fetching * The `rad patch` command no longer has a `--fetch` option * It's now possible to tell the node not to automatically connect to peers in the background * `AddressBook` is being used underneath `Seeds` to allow for shuffled iteration --- radicle-cli/examples/rad-clone-connect.md | 16 ++ radicle-cli/examples/rad-sync.md | 38 ++++ radicle-cli/src/commands/clone.rs | 8 +- radicle-cli/src/commands/patch.rs | 16 +- radicle-cli/src/commands/sync.rs | 216 +++++++++++++++------- radicle-cli/src/commands/track.rs | 8 +- radicle-cli/tests/commands.rs | 74 ++++++++ radicle-crypto/src/lib.rs | 14 +- radicle-node/src/service.rs | 53 +++--- radicle-node/src/test/environment.rs | 28 ++- radicle/src/node.rs | 42 +++-- radicle/src/node/address/types.rs | 27 ++- radicle/src/node/config.rs | 24 +++ radicle/src/profile.rs | 14 +- 14 files changed, 429 insertions(+), 149 deletions(-) create mode 100644 radicle-cli/examples/rad-clone-connect.md diff --git a/radicle-cli/examples/rad-clone-connect.md b/radicle-cli/examples/rad-clone-connect.md new file mode 100644 index 00000000..af23c657 --- /dev/null +++ b/radicle-cli/examples/rad-clone-connect.md @@ -0,0 +1,16 @@ +If we're not connecting to seed nodes when cloning, the `clone` command will +automatically connect to the necessary seeds. + +``` +$ rad clone rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji +✓ Tracking relationship established for rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji with scope 'all' +✓ Connecting to z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi[..] +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6MknSL…StBU8Vi.. +✓ Connecting to z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk[..] +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk.. +✓ Forking under z6Mkux1…nVhib7Z.. +✓ Creating checkout in ./heartwood.. +✓ Remote alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi added +✓ Remote-tracking branch alice@z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi/master created for z6MknSL…StBU8Vi +✓ Repository successfully cloned under [..]/heartwood/ +``` diff --git a/radicle-cli/examples/rad-sync.md b/radicle-cli/examples/rad-sync.md index a319ab5c..fd400da3 100644 --- a/radicle-cli/examples/rad-sync.md +++ b/radicle-cli/examples/rad-sync.md @@ -25,3 +25,41 @@ $ rad sync --announce --timeout 1 ! Seed z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z timed out.. ✗ Sync failed: all seeds timed out ``` + +We can also use the `--fetch` option to only fetch objects: + +``` +$ rad sync --fetch +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkux1…nVhib7Z.. +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk.. +✓ Fetched repository from 2 seed(s) +``` + +Specifying both `--fetch` and `--announce` is equivalent to specifying none: + +``` (fail) +$ rad sync --fetch --announce +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkux1…nVhib7Z.. +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk.. +✓ Fetched repository from 2 seed(s) +✗ Syncing with 2 node(s).. +! Seed z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk timed out.. +! Seed z6Mkux1aUQD2voWWukVb5nNUR7thrHveQG4pDQua8nVhib7Z timed out.. +✗ Sync failed: all seeds timed out +``` + +It's also possible to use the `--seed` flag to only sync with a specific node: + +``` +$ rad sync --fetch --seed z6Mkt67GdsW7715MEfRuP4pSZxJRJh6kj6Y48WRqVv4N1tRk +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkt67…v4N1tRk.. +✓ Fetched repository from 1 seed(s) +``` + +And the `--replicas` flag to sync with a number of nodes: + +``` +$ rad sync --fetch --replicas 1 +✓ Fetching rad:z42hL2jL4XNk6K8oHQaSWfMgCL7ji from z6Mkux1…nVhib7Z.. +✓ Fetched repository from 1 seed(s) +``` diff --git a/radicle-cli/src/commands/clone.rs b/radicle-cli/src/commands/clone.rs index 9f4edbd6..3f54713d 100644 --- a/radicle-cli/src/commands/clone.rs +++ b/radicle-cli/src/commands/clone.rs @@ -2,6 +2,7 @@ use std::ffi::OsString; use std::path::Path; use std::str::FromStr; +use std::time; use anyhow::anyhow; use thiserror::Error; @@ -183,7 +184,12 @@ pub fn clone( ); } - let results = sync::fetch_all(id, node)?; + let results = sync::fetch( + id, + sync::SyncMode::default(), + time::Duration::from_secs(9), + node, + )?; let Ok(repository) = storage.repository(id) else { // If we don't have the project locally, even after attempting to fetch, // there's nothing we can do. diff --git a/radicle-cli/src/commands/patch.rs b/radicle-cli/src/commands/patch.rs index 5e5cd7c9..ececa1a7 100644 --- a/radicle-cli/src/commands/patch.rs +++ b/radicle-cli/src/commands/patch.rs @@ -25,10 +25,9 @@ use anyhow::anyhow; use radicle::cob::patch; use radicle::cob::patch::PatchId; +use radicle::prelude::*; use radicle::storage::git::transport; -use radicle::{prelude::*, Node}; -use crate::commands::rad_sync as sync; use crate::git::Rev; use crate::terminal as term; use crate::terminal::args::{string, Args, Error, Help}; @@ -158,7 +157,6 @@ pub enum Operation { #[derive(Debug)] pub struct Options { pub op: Operation, - pub fetch: bool, pub announce: bool, pub push: bool, pub verbose: bool, @@ -171,7 +169,6 @@ impl Args for Options { let mut parser = lexopt::Parser::from_args(args); let mut op: Option = None; let mut verbose = false; - let mut fetch = false; let mut announce = false; let mut patch_id = None; let mut revision_id = None; @@ -194,12 +191,6 @@ impl Args for Options { Long("no-message") => { message = Message::Blank; } - Long("fetch") => { - fetch = true; - } - Long("no-fetch") => { - fetch = false; - } Long("announce") => { announce = true; } @@ -327,7 +318,6 @@ impl Args for Options { Ok(( Options { op, - fetch, push, verbose, announce, @@ -346,10 +336,6 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> { transport::local::register(profile.storage.clone()); - if options.fetch { - sync::fetch_all(repository.id(), &mut Node::new(profile.socket()))?; - } - match options.op { Operation::List { filter: Filter(f) } => { list::run(f, &repository, &profile)?; diff --git a/radicle-cli/src/commands/sync.rs b/radicle-cli/src/commands/sync.rs index d0b1141f..01e1856c 100644 --- a/radicle-cli/src/commands/sync.rs +++ b/radicle-cli/src/commands/sync.rs @@ -6,7 +6,7 @@ use anyhow::{anyhow, Context as _}; use radicle::node; use radicle::node::{FetchResult, FetchResults, Handle as _, Node}; -use radicle::prelude::{Id, NodeId, Profile}; +use radicle::prelude::{Id, NodeId}; use crate::terminal as term; use crate::terminal::args::{Args, Error, Help}; @@ -19,35 +19,57 @@ pub const HELP: Help = Help { Usage rad sync [] [