use crate::{Error, ErrorKind};
use async_http_range_reader::AsyncHttpRangeReader;
use futures::io::BufReader;
use tokio_util::compat::TokioAsyncReadCompatExt;
use url::Url;
use uv_distribution_filename::WheelFilename;
use uv_metadata::find_archive_dist_info;
pub(crate) async fn wheel_metadata_from_remote_zip(
filename: &WheelFilename,
debug_name: &Url,
reader: &mut AsyncHttpRangeReader,
) -> Result<String, Error> {
const CENTRAL_DIRECTORY_SIZE: u64 = 16384;
reader
.prefetch(reader.len().saturating_sub(CENTRAL_DIRECTORY_SIZE)..reader.len())
.await;
let buf = BufReader::new(reader.compat());
let mut reader = async_zip::base::read::seek::ZipFileReader::new(buf)
.await
.map_err(|err| ErrorKind::Zip(filename.clone(), err))?;
let ((metadata_idx, metadata_entry), _dist_info_prefix) = find_archive_dist_info(
filename,
reader
.file()
.entries()
.iter()
.enumerate()
.filter_map(|(idx, e)| Some(((idx, e), e.filename().as_str().ok()?))),
)
.map_err(|err| ErrorKind::Metadata(debug_name.to_string(), err))?;
let offset = metadata_entry.header_offset();
let size = metadata_entry.compressed_size()
+ 30 + metadata_entry.filename().as_bytes().len() as u64;
let buffer_size = 8192;
let size = size.div_ceil(buffer_size) * buffer_size;
reader
.inner_mut()
.get_mut()
.get_mut()
.prefetch(offset..offset + size)
.await;
let mut contents = String::new();
reader
.reader_with_entry(metadata_idx)
.await
.map_err(|err| ErrorKind::Zip(filename.clone(), err))?
.read_to_string_checked(&mut contents)
.await
.map_err(|err| ErrorKind::Zip(filename.clone(), err))?;
Ok(contents)
}