use std::ops::ControlFlow;
use std::sync::atomic::AtomicBool;
use super::{CloneHead, CloneReady, CloneRequest, CloneTransferError, plan, workflow};
use crate::fetch::{DownloadedFetch, FetchLimits};
#[cfg(any(
feature = "http",
all(feature = "ssh", any(target_os = "macos", target_os = "linux"))
))]
use crate::transport::TransportControl;
#[derive(Debug)]
pub struct CloneDownload {
request: CloneRequest,
head: CloneHead,
downloaded: DownloadedFetch,
}
impl CloneDownload {
pub fn validate(
self,
cancel: &AtomicBool,
progress: impl FnMut(&[u8]) -> ControlFlow<()>,
) -> Result<CloneReady, CloneTransferError> {
self.validate_with_progress(cancel, progress, |_| {})
}
pub fn validate_with_progress(
self,
cancel: &AtomicBool,
progress: impl FnMut(&[u8]) -> ControlFlow<()>,
observe: impl FnMut(crate::fetch::ValidationProgress),
) -> Result<CloneReady, CloneTransferError> {
let mut received = self
.downloaded
.validate_with_progress(cancel, progress, observe)?;
if self.request.filter.is_some() {
received.mark_clone_promisor();
}
Ok(CloneReady {
request: self.request,
head: self.head,
received,
})
}
}
impl CloneRequest {
#[cfg(feature = "http")]
pub async fn receive_http(
self,
remote: &crate::transport::http::HttpRemote,
limits: FetchLimits,
control: TransportControl<'_>,
) -> Result<CloneDownload, CloneTransferError> {
self.receive_http_with_progress(remote, limits, control, |_| {})
.await
}
#[cfg(feature = "http")]
pub async fn receive_http_with_progress(
self,
remote: &crate::transport::http::HttpRemote,
limits: FetchLimits,
control: TransportControl<'_>,
progress: impl FnMut(&[u8]),
) -> Result<CloneDownload, CloneTransferError> {
let mut saved = None;
let download = crate::fetch::receive_http_with_options(
remote,
|ad| plan::select(self.plan(ad), &mut saved),
None,
crate::fetch::FetchOptions::default()
.with_limits(limits)
.with_filter(self.filter.clone()),
control,
progress,
)
.await;
let (plan, downloaded) = workflow::selected(saved, download)?;
Ok(CloneDownload {
request: self,
head: plan.head,
downloaded,
})
}
pub(crate) fn receive_connection(
self,
connection: &mut dyn crate::transport::Connection,
requested: crate::transport::RequestedProtocol,
limits: FetchLimits,
cancel: &AtomicBool,
progress: impl FnMut(&[u8]),
) -> Result<CloneDownload, CloneTransferError> {
let mut saved = None;
let download = crate::fetch::stream::download(
connection,
requested,
|ad| plan::select(self.plan(ad), &mut saved),
None,
crate::fetch::FetchOptions {
limits,
depth: None,
filter: self.filter.clone(),
explicit_wants: false,
},
cancel,
progress,
);
let (plan, downloaded) = workflow::selected(saved, download)?;
Ok(CloneDownload {
request: self,
head: plan.head,
downloaded,
})
}
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
pub async fn receive_ssh(
self,
remote: &crate::transport::ssh::SshRemote,
limits: FetchLimits,
control: TransportControl<'_>,
) -> Result<CloneDownload, CloneTransferError> {
self.receive_ssh_with_progress(remote, limits, control, |_| {}, |_| {})
.await
}
#[cfg(all(feature = "ssh", any(target_os = "macos", target_os = "linux")))]
pub async fn receive_ssh_with_progress(
self,
remote: &crate::transport::ssh::SshRemote,
limits: FetchLimits,
control: TransportControl<'_>,
diagnostics: impl FnMut(&[u8]),
progress: impl FnMut(&[u8]),
) -> Result<CloneDownload, CloneTransferError> {
let mut saved = None;
let download = crate::fetch::receive_ssh_with_progress(
remote,
|ad| plan::select(self.plan(ad), &mut saved),
None,
crate::fetch::FetchOptions {
limits,
depth: None,
filter: self.filter.clone(),
explicit_wants: false,
},
control,
diagnostics,
progress,
)
.await;
let (plan, downloaded) = workflow::selected(saved, download)?;
Ok(CloneDownload {
request: self,
head: plan.head,
downloaded,
})
}
}