sendly 3.30.0

Official Rust SDK for the Sendly SMS API
Documentation
use std::path::Path;

use reqwest::multipart;
use tokio::fs;

use crate::client::Sendly;
use crate::error::{Error, Result};
use crate::models::MediaFile;

pub struct Media<'a> {
    client: &'a Sendly,
}

impl<'a> Media<'a> {
    pub(crate) fn new(client: &'a Sendly) -> Self {
        Self { client }
    }

    pub async fn upload(&self, file_path: &str) -> Result<MediaFile> {
        let path = Path::new(file_path);

        let filename = path
            .file_name()
            .and_then(|n| n.to_str())
            .unwrap_or("file")
            .to_string();

        let content_type = mime_from_extension(path);

        let data = fs::read(file_path).await.map_err(|e| Error::Validation {
            message: format!("Failed to read file: {}", e),
        })?;

        self.upload_bytes(data, &filename, &content_type).await
    }

    pub async fn upload_bytes(
        &self,
        data: Vec<u8>,
        filename: &str,
        content_type: &str,
    ) -> Result<MediaFile> {
        let part = multipart::Part::bytes(data)
            .file_name(filename.to_string())
            .mime_str(content_type)
            .map_err(|e| Error::Validation {
                message: format!("Invalid content type: {}", e),
            })?;

        let form = multipart::Form::new().part("file", part);

        let response = self.client.post_multipart("/media", form).await?;
        let media_file: MediaFile = response.json().await?;

        Ok(media_file)
    }
}

fn mime_from_extension(path: &Path) -> String {
    match path.extension().and_then(|e| e.to_str()) {
        Some("jpg") | Some("jpeg") => "image/jpeg".to_string(),
        Some("png") => "image/png".to_string(),
        Some("gif") => "image/gif".to_string(),
        Some("webp") => "image/webp".to_string(),
        Some("mp4") => "video/mp4".to_string(),
        Some("3gp") => "video/3gpp".to_string(),
        Some("pdf") => "application/pdf".to_string(),
        Some("vcf") => "text/vcard".to_string(),
        _ => "application/octet-stream".to_string(),
    }
}