This commit is contained in:
2026-08-31 11:02:20 +07:00
parent 675e40ca1c
commit 43ea3708d2
6 changed files with 367 additions and 591 deletions
+44 -57
View File
@@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
@@ -515,38 +515,11 @@ impl Backend {
let owner = owner.clone();
let repo_id = repo_id.clone();
let servers = servers.clone();
async move {
let mut failures = Vec::new();
let mut pushed = 0;
for relay in &servers {
let Some(base_url) = grasp_base_url(relay) else {
failures.push(format!("{relay}: no domain"));
continue;
};
match signed_git::push_main(&path, &base_url, &owner, &repo_id) {
Ok(()) => pushed += 1,
Err(e) => failures.push(format!("{relay}: {e}")),
}
}
if pushed == 0 {
bail!(
"could not push the repository to any grasp server: {}",
failures.join("; ")
);
}
for failure in failures {
log::warn!("grasp push failed: {failure}");
}
Ok::<_, Error>(())
}
push_to_grasp_servers(path, owner, repo_id, servers, signed_git::push_main)
});
push.await?;
Announcement::from_event(&event)
.ok_or_else(|| anyhow!("failed to parse the published announcement"))
Announcement::from_event(&event).ok_or_else(|| anyhow!("failed to parse announcement"))
})
}
@@ -667,33 +640,7 @@ impl Backend {
let owner = owner.clone();
let repo_id = repo_id.clone();
let servers = servers.clone();
async move {
let mut failures = Vec::new();
let mut pushed = 0;
for relay in &servers {
let Some(base_url) = grasp_base_url(relay) else {
failures.push(format!("{relay}: no domain"));
continue;
};
match signed_git::push_all(&path, &base_url, &owner, &repo_id) {
Ok(()) => pushed += 1,
Err(e) => failures.push(format!("{relay}: {e}")),
}
}
if pushed == 0 {
bail!(
"could not push the repository to any grasp server: {}",
failures.join("; ")
);
}
for failure in failures {
log::warn!("grasp push failed: {failure}");
}
Ok::<_, Error>(())
}
push_to_grasp_servers(path, owner, repo_id, servers, signed_git::push_all)
});
push.await?;
}
@@ -1331,6 +1278,46 @@ fn grasp_clone_url(relay: &RelayUrl, owner: &str, repo_id: &str) -> Option<Url>
Url::parse(&format!("{base}/{owner}/{repo_id}.git")).ok()
}
/// Push the repository at `path` to every grasp server: a server that
/// rejects the push is logged, but the push only fails when no server
/// accepted it. `push` performs the single-server push (e.g.
/// [`signed_git::push_main`] for the create flow, [`signed_git::push_all`]
/// for the init flow).
async fn push_to_grasp_servers(
path: PathBuf,
owner: String,
repo_id: String,
servers: Vec<RelayUrl>,
push: fn(&Path, &str, &str, &str) -> Result<(), Error>,
) -> Result<(), Error> {
let mut failures = Vec::new();
let mut pushed = 0;
for relay in &servers {
let Some(base_url) = grasp_base_url(relay) else {
failures.push(format!("{relay}: no domain"));
continue;
};
match push(&path, &base_url, &owner, &repo_id) {
Ok(()) => pushed += 1,
Err(e) => failures.push(format!("{relay}: {e}")),
}
}
if pushed == 0 {
bail!(
"could not push the repository to any grasp server: {}",
failures.join("; ")
);
}
for failure in failures {
log::warn!("grasp push failed: {failure}");
}
Ok(())
}
/// Split a stored bunker credential into the plain URI and the session key.
/// Credentials without an embedded key (legacy) get a fresh one.
fn extract_master_key(credential: &str) -> (&str, Keys) {