upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bin/git_remote_nostr/fetch.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-09-06 10:43:34 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-09-06 11:05:05 +0100
commit935bc0ca630d7964082966e4c0caeb255f5a4f57 (patch)
tree21a2eec2abf81a54714c40c974ecc3c4e9170e11 /src/bin/git_remote_nostr/fetch.rs
parent92e06d80540a12d91e23ed6e557cc074d90d4d66 (diff)
fix(remote): improve protocol selction / fallback
abstract the protocols and order to try under different scenarios add some additional scenarios eg hardcoded http tweak error reporting
Diffstat (limited to 'src/bin/git_remote_nostr/fetch.rs')
-rw-r--r--src/bin/git_remote_nostr/fetch.rs116
1 files changed, 34 insertions, 82 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs
index 6836456..f591fed 100644
--- a/src/bin/git_remote_nostr/fetch.rs
+++ b/src/bin/git_remote_nostr/fetch.rs
@@ -1,6 +1,6 @@
1use std::io::Stdin; 1use std::io::Stdin;
2 2
3use anyhow::{anyhow, bail, Context, Result}; 3use anyhow::{bail, Result};
4use auth_git2::GitAuthenticator; 4use auth_git2::GitAuthenticator;
5use git2::Repository; 5use git2::Repository;
6use ngit::{ 6use ngit::{
@@ -16,6 +16,7 @@ use ngit::{
16 16
17use crate::utils::{ 17use crate::utils::{
18 find_proposal_and_patches_by_branch_name, get_oids_from_fetch_batch, get_open_proposals, 18 find_proposal_and_patches_by_branch_name, get_oids_from_fetch_batch, get_open_proposals,
19 get_read_protocols_to_try, join_with_and,
19}; 20};
20 21
21pub async fn run_fetch( 22pub async fn run_fetch(
@@ -58,10 +59,10 @@ pub async fn run_fetch(
58 && !errors.is_empty() 59 && !errors.is_empty()
59 { 60 {
60 bail!( 61 bail!(
61 "failed to fetch objects in nostr state event from:\r\n{}", 62 "fetch: failed to fetch objects in nostr state event from:\r\n{}",
62 errors 63 errors
63 .iter() 64 .iter()
64 .map(std::string::ToString::to_string) 65 .map(|e| format!(" - {e}"))
65 .collect::<Vec<String>>() 66 .collect::<Vec<String>>()
66 .join("\r\n") 67 .join("\r\n")
67 ); 68 );
@@ -114,97 +115,45 @@ fn fetch_from_git_server(
114) -> Result<()> { 115) -> Result<()> {
115 let server_url = git_server_url.parse::<CloneUrl>()?; 116 let server_url = git_server_url.parse::<CloneUrl>()?;
116 117
117 // if protocol is local - just try local 118 let protocols_to_attempt = get_read_protocols_to_try(&server_url, decoded_nostr_url);
118 if server_url.protocol() == ServerProtocol::Local {
119 let formatted_url = server_url.format_as(&ServerProtocol::Local, &None)?;
120 term.write_line(format!("fetching from {formatted_url}...").as_str())?;
121 if let Err(error) = fetch_from_git_server_url(git_repo, oids, &formatted_url) {
122 term.write_line(
123 format!("WARNING: failed to fetch from {formatted_url} error:{error}").as_str(),
124 )?;
125 return Err(error).context(format!("{formatted_url}: failed to fetch"));
126 }
127 return Ok(());
128 }
129 119
130 term.write_line(format!("fetching from {}...", server_url.domain()).as_str())?; 120 let mut failed_protocols = vec![];
121 let mut success = false;
122 for protocol in &protocols_to_attempt {
123 term.write_line(
124 format!("fetching from {} over {protocol}...", server_url.domain(),).as_str(),
125 )?;
131 126
132 // use overide protocol if specified
133 if let Some(protocol) = &decoded_nostr_url.protocol {
134 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; 127 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?;
135 let res = fetch_from_git_server_url(git_repo, oids, &formatted_url); 128 let res = if [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol) {
129 fetch_from_git_server_url_unauthenticated(git_repo, oids, &formatted_url)
130 } else {
131 fetch_from_git_server_url(git_repo, oids, &formatted_url)
132 };
136 term.clear_last_lines(1)?; 133 term.clear_last_lines(1)?;
137 if let Err(error) = res { 134 if let Err(error) = res {
138 term.write_line( 135 term.write_line(
139 format!( 136 format!("fetch: {formatted_url} failed over {protocol}: {error}").as_str(),
140 "WARNING: {formatted_url} failed to fetch over {protocol}{} as specified in nostr url. error:{error}",
141 if let Some(user) = &decoded_nostr_url.user {
142 format!(" with user '{user}'")
143 } else {
144 String::new()
145 }
146 ).as_str(),
147 )?; 137 )?;
148 return Err(error).context(format!("{formatted_url}: failed to fetch")); 138 failed_protocols.push(protocol);
149 } 139 } else {
150 return Ok(()); 140 success = true;
151 } 141 if !failed_protocols.is_empty() {
152 142 term.write_line(format!("fetch: succeeded over {protocol}").as_str())?;
153 // Try https unauthenticated
154 let formatted_url = server_url.format_as(&ServerProtocol::Https, &None)?;
155 let res = fetch_from_git_server_url_unauthenticated(git_repo, oids, &formatted_url);
156 term.clear_last_lines(1)?;
157 if let Err(unauth_error) = res {
158 term.write_line(
159 format!(
160 "WARNING: {formatted_url} failed to fetch over unauthenticated https. {unauth_error}",
161 ).as_str(),
162 )?;
163 // TODO what about timeout errors?
164 // try over ssh
165 let mut ssh_error = None;
166 if check_ssh_keys() {
167 term.write_line(format!("fetching from {} over ssh...", server_url.domain()).as_str())?;
168 let formatted_url = server_url.format_as(&ServerProtocol::Ssh, &None)?;
169 let res = fetch_from_git_server_url(git_repo, oids, &formatted_url);
170 term.clear_last_lines(1)?;
171 if let Err(error) = res {
172 term.write_line(
173 format!("WARNING: {formatted_url} failed to fetch over ssh. error:{error}")
174 .as_str(),
175 )?;
176 term.write_line(
177 format!("fetching from {} over ssh...", server_url.domain()).as_str(),
178 )?;
179 ssh_error = Some(error);
180 } else {
181 return Ok(());
182 } 143 }
183 } 144 }
184 // try over https authenticated 145 }
185 term.write_line( 146 if !success {
186 format!( 147 if decoded_nostr_url.protocol.is_some() {
187 "fetching from {} over authenticated https...",
188 server_url.domain()
189 )
190 .as_str(),
191 )?;
192 let formatted_url = server_url.format_as(&ServerProtocol::Ssh, &None)?;
193 let res = fetch_from_git_server_url(git_repo, oids, &formatted_url);
194 term.clear_last_lines(1)?;
195 if let Err(auth_https_error) = res {
196 term.write_line( 148 term.write_line(
197 format!("WARNING: {formatted_url} failed to fetch over authenticated https. error:{auth_https_error}",) 149 "fetch: protocol override in nostr url so not attempting with any other protocols",
198 .as_str(),
199 )?; 150 )?;
200 let error_message = format!(
201 "{} failed to fetch over unauthenticated https ({unauth_error}), ssh ({}) and authenticated https ({auth_https_error})",
202 server_url.format_as(&ServerProtocol::Unspecified, &None)?,
203 ssh_error.unwrap_or(anyhow!("no keys found"))
204 );
205
206 bail!(error_message)
207 } 151 }
152 bail!(
153 "{} failed over {}",
154 server_url.domain(),
155 join_with_and(&failed_protocols)
156 );
208 } 157 }
209 Ok(()) 158 Ok(())
210} 159}
@@ -214,6 +163,9 @@ fn fetch_from_git_server_url(
214 oids: &[String], 163 oids: &[String],
215 git_server_url: &str, 164 git_server_url: &str,
216) -> Result<()> { 165) -> Result<()> {
166 if git_server_url.parse::<CloneUrl>()?.protocol() == ServerProtocol::Ssh && !check_ssh_keys() {
167 bail!("no ssh keys found");
168 }
217 let git_config = git_repo.config()?; 169 let git_config = git_repo.config()?;
218 let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?; 170 let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?;
219 let auth = GitAuthenticator::default(); 171 let auth = GitAuthenticator::default();