use bytes::Bytes;
use reqwest::Method;
use serde::Deserialize;
use crate::api::{
DownloadOptions, RedundantUploadOptions, UploadResult, prepare_download_headers,
prepare_redundant_upload_headers,
};
use crate::client::{Inner, request};
use crate::swarm::{BatchId, Error, Reference};
use super::FileApi;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReferenceInformation {
pub content_length: u64,
}
#[derive(Deserialize)]
struct UploadBody {
reference: String,
}
impl FileApi {
pub async fn upload_data(
&self,
batch_id: &BatchId,
data: impl Into<Bytes>,
opts: Option<&RedundantUploadOptions>,
) -> Result<UploadResult, Error> {
let builder = request(&self.inner, Method::POST, "bytes")?
.header("Content-Type", "application/octet-stream")
.body(data.into());
let builder =
Inner::apply_headers(builder, prepare_redundant_upload_headers(batch_id, opts));
let resp = self.inner.send(builder).await?;
let headers = resp.headers().clone();
let body: UploadBody = serde_json::from_slice(&resp.bytes().await?)?;
UploadResult::from_response(&body.reference, &headers)
}
pub async fn download_data(
&self,
reference: &Reference,
opts: Option<&DownloadOptions>,
) -> Result<Bytes, Error> {
let resp = self.download_data_response(reference, opts).await?;
Ok(resp.bytes().await?)
}
pub async fn download_data_response(
&self,
reference: &Reference,
opts: Option<&DownloadOptions>,
) -> Result<reqwest::Response, Error> {
let path = format!("bytes/{}", reference.to_hex());
let builder = request(&self.inner, Method::GET, &path)?;
let builder = Inner::apply_headers(builder, prepare_download_headers(opts));
self.inner.send(builder).await
}
pub async fn probe_data(&self, reference: &Reference) -> Result<ReferenceInformation, Error> {
let path = format!("bytes/{}", reference.to_hex());
let builder = request(&self.inner, Method::HEAD, &path)?;
let resp = self.inner.send(builder).await?;
let content_length = resp
.headers()
.get(reqwest::header::CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse::<u64>().ok())
.or_else(|| resp.content_length())
.ok_or_else(|| Error::argument("missing Content-Length"))?;
Ok(ReferenceInformation { content_length })
}
}