Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
httpd: Fetch projects after starting seeding it
✗ CI failure Sebastian Martinez committed 2 years ago
commit 59d1548e5afd285fe0a051b3ab9ed127937df77d
parent 936c69c9df5bfd5e1354cf8acd7fb72af54a95ba
1 failed (1 total) View logs
4 files changed +76 -16
modified radicle-cli/src/commands/sync.rs
@@ -500,14 +500,14 @@ pub fn fetch(

    // Fetch from connected seeds.
    let connected = connected
-
        .iter()
+
        .into_iter()
        .filter(|c| !results.contains(&c.nid))
-
        .map(|c| &c.nid)
+
        .map(|c| c.nid)
        .take(replicas)
        .collect::<Vec<_>>();
    for nid in connected {
-
        let result = fetch_from(rid, nid, timeout, node)?;
-
        results.push(*nid, result);
+
        let result = fetch_from(rid, &nid, timeout, node)?;
+
        results.push(nid, result);
    }

    // Try to connect to disconnected seeds and fetch from them.
modified radicle-httpd/src/api.rs
@@ -19,7 +19,7 @@ use radicle::cob::patch;
use radicle::identity::{DocAt, RepoId};
use radicle::node::policy::Scope;
use radicle::node::routing::Store;
-
use radicle::node::{Handle, NodeId};
+
use radicle::node::Handle;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::{Node, Profile};

@@ -156,8 +156,6 @@ pub struct CobsQuery<T> {
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PoliciesQuery {
-
    /// The NID from which to fetch from after tracking a repo.
-
    pub from: Option<NodeId>,
    pub scope: Option<Scope>,
}

modified radicle-httpd/src/api/v1/node.rs
@@ -8,7 +8,7 @@ use serde_json::json;

use radicle::identity::RepoId;
use radicle::node::routing::Store;
-
use radicle::node::{policy, AliasStore, Handle, NodeId, DEFAULT_TIMEOUT};
+
use radicle::node::{self, policy, AliasStore, FetchResults, Handle, NodeId, DEFAULT_TIMEOUT};
use radicle::Node;

use crate::api::error::Error;
@@ -109,17 +109,79 @@ async fn node_policies_seed_handler(
    Query(qs): Query<PoliciesQuery>,
) -> impl IntoResponse {
    api::auth::validate(&ctx, &token).await?;
-
    let mut node = Node::new(ctx.profile.socket());
-
    node.seed(project, qs.scope.unwrap_or_default())?;
-

-
    if let Some(from) = qs.from {
-
        let results = node.fetch(project, from, DEFAULT_TIMEOUT)?;
+
    let profile = &ctx.profile;
+
    let mut node = Node::new(profile.socket());
+
    let updated = node.seed(project, qs.scope.unwrap_or_default())?;
+
    let outcome = if updated { "updated" } else { "exists" };
+

+
    let local = ctx.profile.id();
+
    let seeds = node.seeds(project)?;
+
    let settings = node::seed::RepoSync::default().with_profile(profile);
+
    let replicas = settings
+
        .replicas
+
        .min(seeds.iter().filter(|s| s.nid != *local).count());
+
    let sessions = node.sessions()?;
+
    let mut results = FetchResults::default();
+
    let (connected, mut disconnected) = seeds.partition();
+

+
    // Fetch from specified seeds, plus our preferred seeds.
+
    for nid in &settings.seeds {
+
        if !sessions.iter().any(|s| s.nid == *nid) {
+
            // Node isn't connected, skipping it.
+
            continue;
+
        }
+
        let result = node.fetch(project, *nid, DEFAULT_TIMEOUT)?;
+
        results.push(*nid, result);
+
    }
+
    if results.success().count() >= replicas {
        return Ok::<_, Error>((
            StatusCode::OK,
-
            Json(json!({ "success": true, "results": results })),
+
            Json(json!({ "success": true, "outcome": outcome, "results": results })),
        ));
    }
-
    Ok::<_, Error>((StatusCode::OK, Json(json!({ "success": true }))))
+

+
    // Fetch from connected seeds.
+
    let connected = connected
+
        .into_iter()
+
        .filter(|c| !results.contains(&c.nid))
+
        .map(|c| c.nid)
+
        .take(replicas)
+
        .collect::<Vec<_>>();
+
    for nid in connected {
+
        let result = node.fetch(project, nid, DEFAULT_TIMEOUT)?;
+
        results.push(nid, result);
+
    }
+

+
    // Try to connect to disconnected seeds and fetch from them.
+
    while results.success().count() < replicas {
+
        let Some(seed) = disconnected.pop() else {
+
            break;
+
        };
+
        if seed.nid == *local {
+
            // Skip our own node.
+
            continue;
+
        }
+
        for addr in seed.addrs.into_iter().map(|ka| ka.addr) {
+
            if let node::ConnectResult::Connected = node.connect(
+
                seed.nid,
+
                addr,
+
                node::ConnectOptions {
+
                    persistent: false,
+
                    timeout: DEFAULT_TIMEOUT,
+
                },
+
            )? {
+
                let result = node.fetch(project, seed.nid, DEFAULT_TIMEOUT)?;
+
                results.push(seed.nid, result);
+
            } else {
+
                continue;
+
            }
+
        }
+
    }
+

+
    Ok::<_, Error>((
+
        StatusCode::OK,
+
        Json(json!({ "success": true, "outcome": outcome, "results": results })),
+
    ))
}

/// Unseed a repo.
modified radicle/src/node.rs
@@ -694,7 +694,7 @@ impl<S: ToString> From<Result<(Vec<RefUpdate>, HashSet<NodeId>), S>> for FetchRe
}

/// Holds multiple fetch results.
-
#[derive(Debug, Default)]
+
#[derive(Debug, Default, Serialize)]
pub struct FetchResults(Vec<(NodeId, FetchResult)>);

impl FetchResults {