Get gix_proxy working completely

This commit is contained in:
Brian Picciano 2024-02-15 11:00:59 +01:00
parent 1667bac39c
commit 1e8f970486

View File

@ -1,4 +1,4 @@
use crate::error::unexpected::{self, Mappable}; use crate::error::unexpected::{self, Intoable, Mappable};
use crate::{origin, util}; use crate::{origin, util};
use std::{collections, sync}; use std::{collections, sync};
@ -7,6 +7,15 @@ struct DescrState {
current_tree: gix_hash::ObjectId, current_tree: gix_hash::ObjectId,
} }
#[derive(thiserror::Error, Clone, Debug, PartialEq)]
enum GetObjectError {
#[error("unavailable due to server-side issue")]
Unavailable,
#[error(transparent)]
Unexpected(#[from] unexpected::Error),
}
#[derive(Default)] #[derive(Default)]
pub struct Proxy { pub struct Proxy {
client: reqwest::Client, client: reqwest::Client,
@ -101,7 +110,8 @@ impl Proxy {
&self, &self,
descr: &origin::Descr, descr: &origin::Descr,
oid: &gix_hash::ObjectId, oid: &gix_hash::ObjectId,
) -> unexpected::Result<Option<util::BoxByteStream>> { expect_kind: gix_object::Kind,
) -> Result<util::BoxByteStream, GetObjectError> {
let hex = oid.to_string(); let hex = oid.to_string();
let (url, _) = Self::deconstruct_descr(descr); let (url, _) = Self::deconstruct_descr(descr);
@ -109,26 +119,40 @@ impl Proxy {
Self::construct_url(url, format!("objects/{}/{}", &hex[..2], &hex[2..]).as_str()) Self::construct_url(url, format!("objects/{}/{}", &hex[..2], &hex[2..]).as_str())
.or_unexpected_while("constructing refs url")?; .or_unexpected_while("constructing refs url")?;
Ok(self let mut loose_object = self
.client .client
.get(object_url) .get(object_url)
.send() .send()
.await .await
.or_unexpected_while("performing request")? .or(Err(GetObjectError::Unavailable))?
.error_for_status() .error_for_status()
.ok()
.map(|res| { .map(|res| {
use async_compression::tokio::bufread::ZlibDecoder; use async_compression::tokio::bufread::ZlibDecoder;
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use std::io; use std::io;
let r = tokio_util::io::StreamReader::new( tokio::io::BufReader::new(ZlibDecoder::new(tokio_util::io::StreamReader::new(
res.bytes_stream() res.bytes_stream()
.map_err(|e| io::Error::new(io::ErrorKind::Other, e)), .map_err(|e| io::Error::new(io::ErrorKind::Other, e)),
); )))
})
.or(Err(GetObjectError::Unavailable))?;
util::BoxByteStream::from_async_read(ZlibDecoder::new(r)) use tokio::io::AsyncBufReadExt;
})) let mut header = Vec::<u8>::new();
loose_object
.read_until(0, &mut header)
.await
.or(Err(GetObjectError::Unavailable))?;
let (kind, _, _) =
gix_object::decode::loose_header(&header).or(Err(GetObjectError::Unavailable))?;
if kind != expect_kind {
return Err(GetObjectError::Unavailable);
}
Ok(util::BoxByteStream::from_async_read(loose_object))
} }
async fn get_commit_tree( async fn get_commit_tree(
@ -137,17 +161,18 @@ impl Proxy {
commit_hash: &gix_hash::ObjectId, commit_hash: &gix_hash::ObjectId,
) -> Result<gix_hash::ObjectId, origin::SyncError> { ) -> Result<gix_hash::ObjectId, origin::SyncError> {
let commit_object_bytes = self let commit_object_bytes = self
.get_object(descr, commit_hash) .get_object(descr, commit_hash, gix_object::Kind::Commit)
.await? .await
.ok_or(origin::SyncError::Unavailable)? .map_err(|e| match e {
GetObjectError::Unavailable => origin::SyncError::Unavailable,
GetObjectError::Unexpected(_) => e.into_unexpected().into(),
})?
.read_to_end() .read_to_end()
.await .await
.or(Err(origin::SyncError::Unavailable))?; .or(Err(origin::SyncError::Unavailable))?;
let commit_object = gix_object::ObjectRef::from_loose(commit_object_bytes.as_ref()) let commit_object = gix_object::CommitRef::from_bytes(commit_object_bytes.as_ref())
.or(Err(origin::SyncError::Unavailable))? .or(Err(origin::SyncError::Unavailable))?;
.into_commit()
.ok_or(origin::SyncError::Unavailable)?;
Ok(commit_object.tree()) Ok(commit_object.tree())
} }
@ -159,17 +184,18 @@ impl Proxy {
entry_name: &str, entry_name: &str,
) -> Result<gix_object::tree::Entry, origin::GetFileError> { ) -> Result<gix_object::tree::Entry, origin::GetFileError> {
let tree_object_bytes = self let tree_object_bytes = self
.get_object(descr, tree_hash) .get_object(descr, tree_hash, gix_object::Kind::Tree)
.await? .await
.ok_or(origin::GetFileError::Unavailable)? .map_err(|e| match e {
GetObjectError::Unavailable => origin::GetFileError::Unavailable,
GetObjectError::Unexpected(_) => e.into_unexpected().into(),
})?
.read_to_end() .read_to_end()
.await .await
.or(Err(origin::GetFileError::Unavailable))?; .or(Err(origin::GetFileError::Unavailable))?;
let tree_object = gix_object::ObjectRef::from_loose(tree_object_bytes.as_ref()) let tree_object = gix_object::TreeRef::from_bytes(tree_object_bytes.as_ref())
.or(Err(origin::GetFileError::Unavailable))? .or(Err(origin::GetFileError::Unavailable))?;
.into_tree()
.ok_or(origin::GetFileError::Unavailable)?;
for entry in tree_object.entries { for entry in tree_object.entries {
if entry.filename == entry_name { if entry.filename == entry_name {
@ -236,9 +262,7 @@ impl origin::Store for Proxy {
let path = path let path = path
.as_str() .as_str()
.parse::<std::path::PathBuf>() .parse::<std::path::PathBuf>()
.or_unexpected_while("parsing path")? .or_unexpected_while("parsing path")?;
.canonicalize()
.or_unexpected_while("canonicalizing path")?;
let path_parts = path.iter().collect::<Vec<&std::ffi::OsStr>>(); let path_parts = path.iter().collect::<Vec<&std::ffi::OsStr>>();
@ -297,12 +321,14 @@ impl origin::Store for Proxy {
.into()); .into());
} }
Ok(self self.get_object(&descr, &entry.oid, gix_object::Kind::Blob)
.get_object(&descr, &entry.oid) .await
.await? .map_err(|e| match e {
.map_unexpected_while(|| format!("object for entry {:?} not found", entry))?) GetObjectError::Unavailable => origin::GetFileError::Unavailable,
GetObjectError::Unexpected(_) => e
// TODO this is still not correct, as it will include the git object header .into_unexpected_while(format!("getting object for entry {:?}", entry))
.into(),
})
}) })
} }
} }