use std::num::NonZeroU32;
use std::sync::Arc;
use super::{Advertisement, DownloadedFetch, FetchError, FetchLimits, KnownHistory, protocol};
use crate::ObjectId;
use crate::packet::Wire;
use crate::transport::TransportControl;
use crate::transport::http::{HttpRemote, RequestBody};
pub async fn receive_http(
remote: &HttpRemote,
select: impl FnOnce(&Advertisement) -> Vec<ObjectId>,
known: Option<Arc<KnownHistory>>,
limits: FetchLimits,
control: TransportControl<'_>,
) -> Result<DownloadedFetch, FetchError> {
receive_http_with_depth(remote, select, known, None, limits, control).await
}
pub async fn receive_http_with_depth(
remote: &HttpRemote,
select: impl FnOnce(&Advertisement) -> Vec<ObjectId>,
known: Option<Arc<KnownHistory>>,
depth: Option<NonZeroU32>,
limits: FetchLimits,
control: TransportControl<'_>,
) -> Result<DownloadedFetch, FetchError> {
#[cfg(feature = "tracing")]
let span = tracing::debug_span!(
target: "girt",
"fetch.http",
outcome = "incomplete",
failure_class = tracing::field::Empty,
effects = tracing::field::Empty,
wire_bytes = tracing::field::Empty,
);
let operation = async {
control.check()?;
let empty = KnownHistory::default();
let history = known.as_deref().unwrap_or(&empty);
protocol::validate_known(history, limits, control.cancel)?;
let (bytes, advertisement_bytes) = remote
.discover(
"git-upload-pack",
limits.max_advertisement_bytes.min(limits.max_wire_bytes),
control,
)
.await?;
let mut reader = bytes.as_slice();
let mut wire = Wire {
reader: &mut reader,
remaining: limits.max_wire_bytes,
cancel: control.cancel,
};
let advertisement = protocol::advertise(&mut wire, limits)?;
wire.end()?;
let remaining = limits.max_wire_bytes - advertisement_bytes;
control.check()?;
let mut request = Vec::new();
let negotiation = protocol::request(
&mut request,
&advertisement,
select(&advertisement),
history,
depth,
limits,
control.cancel,
)?;
control.check()?;
if !negotiation.needs_pack {
return Ok(DownloadedFetch {
#[cfg(feature = "tracing")]
trace: crate::trace::DownloadContext::capture(),
advertisement,
negotiation,
known,
limits,
remaining,
body: Vec::new(),
});
}
let response = remote
.exchange(
"git-upload-pack",
Some(RequestBody::new(request, Vec::new())),
remaining,
control,
)
.await;
response.result?;
Ok(DownloadedFetch {
#[cfg(feature = "tracing")]
trace: crate::trace::DownloadContext::capture(),
advertisement,
negotiation,
known,
limits,
remaining,
body: response.body,
})
};
#[cfg(feature = "tracing")]
let result = tracing::Instrument::instrument(operation, span.clone()).await;
#[cfg(not(feature = "tracing"))]
let result = operation.await;
#[cfg(feature = "tracing")]
crate::trace::finish(&span, &result, crate::trace::fetch);
#[cfg(feature = "tracing")]
if let Ok(value) = &result {
span.record("wire_bytes", value.body.len());
}
result
}