pub mod types;
use anyhow::{bail, Result};
use async_trait::async_trait;
use reqwest::multipart::{Form, Part};
use reqwest::{Body, StatusCode};
use tokio::fs::File;
use tokio_util::codec::{BytesCodec, FramedRead};
use crate::{ErrorResponse, ImageKit};
use self::types::Response;
pub enum UploadFile {
Binary(File),
}
impl From<File> for UploadFile {
fn from(file: File) -> Self {
UploadFile::Binary(file)
}
}
pub struct Options {
file: UploadFile,
file_name: String,
}
impl Options {
pub fn new<T: ToString>(file: UploadFile, file_name: T) -> Self {
Self {
file,
file_name: file_name.to_string(),
}
}
}
#[async_trait]
pub trait Upload {
async fn upload(&self, opts: Options) -> Result<Response>;
}
#[async_trait]
impl Upload for ImageKit {
async fn upload(&self, opts: Options) -> Result<Response> {
let mut form = Form::new();
form = form.text("fileName", opts.file_name.clone());
match opts.file {
UploadFile::Binary(file) => {
let stream = FramedRead::new(file, BytesCodec::new());
let file_body = Body::wrap_stream(stream);
let form_file = Part::stream(file_body)
.file_name(opts.file_name)
.mime_str("image/jpeg")
.unwrap();
form = form.part("file", form_file);
}
}
let private_key = self.private_key.to_owned();
let response = self
.client
.post(&self.upload_endpoint)
.basic_auth::<String, String>(private_key, None)
.multipart(form)
.send()
.await
.unwrap();
if matches!(response.status(), StatusCode::OK) {
let result = response.json::<Response>().await.unwrap();
return Ok(result);
}
let result = response.json::<ErrorResponse>().await.unwrap();
bail!(result.message);
}
}