use std::env;
use std::fmt;
use std::path::PathBuf;
use clap::Args;
use owo_colors::OwoColorize;
use jax_daemon::http_server::api::client::{resolve_bucket, ApiError};
use jax_daemon::http_server::api::v0::bucket::add::AddResponse;
use reqwest::multipart;
#[derive(Args, Debug, Clone)]
pub struct Add {
pub bucket: String,
pub path: String,
#[arg(long)]
pub mount_path: String,
}
#[derive(Debug)]
pub struct AddOutput {
pub successful: usize,
pub failed: usize,
pub bucket_link: String,
}
impl fmt::Display for AddOutput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.failed > 0 {
writeln!(
f,
"{} {} file(s), {} failed",
"Uploaded".green().bold(),
self.successful,
self.failed.to_string().red()
)?;
} else {
writeln!(
f,
"{} {} file(s)",
"Uploaded".green().bold(),
self.successful
)?;
}
write!(f, " {} {}", "link:".dimmed(), self.bucket_link)
}
}
#[derive(Debug, thiserror::Error)]
pub enum AddError {
#[error("API error: {0}")]
Api(#[from] ApiError),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("HTTP error: {0}")]
Reqwest(#[from] reqwest::Error),
}
#[async_trait::async_trait]
impl crate::cli::op::Op for Add {
type Error = AddError;
type Output = AddOutput;
async fn execute(&self, ctx: &crate::cli::op::OpContext) -> Result<Self::Output, Self::Error> {
let mut client = ctx.client.clone();
let bucket_id = resolve_bucket(&mut client, &self.bucket).await?;
let path = PathBuf::from(&self.path);
let absolute_path = if path.is_absolute() {
path
} else {
env::current_dir()?.join(&path)
};
let file_data = std::fs::read(&absolute_path)?;
let form = multipart::Form::new()
.text("bucket_id", bucket_id.to_string())
.text("mount_path", self.mount_path.clone())
.part("file", multipart::Part::bytes(file_data));
let url = client.base_url().join("/api/v0/bucket/add").unwrap();
let response = client
.http_client()
.post(url)
.multipart(form)
.send()
.await?;
if !response.status().is_success() {
let status = response.status();
let body = response.text().await?;
return Err(AddError::Api(ApiError::HttpStatus(status, body)));
}
let response: AddResponse = response.json().await?;
Ok(AddOutput {
successful: response.successful_files,
failed: response.failed_files,
bucket_link: response.bucket_link.hash().to_string(),
})
}
}