Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix bug in media upload, add optional detectoin of mime-/file-type #8

Merged
merged 1 commit into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ url = "1"
hyper-old-types = "0.11.0"
futures-util = "0.3.25"

[dependencies.magic]
version = "0.13.0"
optional = true

[dependencies.uuid]
version = "1.2.2"
features = ["v4"]
Expand Down Expand Up @@ -80,8 +84,9 @@ html2text = "0.4.4"
version = "0.13"

[features]
all = ["toml", "json", "env"]
default = ["reqwest/default-tls"]
all = ["toml", "json", "env", "magic"]
# default = ["reqwest/default-tls"]
default = ["reqwest/default-tls", "magic"]
env = ["envy"]
json = []
rustls-tls = ["reqwest/rustls-tls"]
8 changes: 7 additions & 1 deletion examples/upload_photo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ async fn main() -> Result<()> {
femme::with_level(femme::LevelFilter::Trace);
let mastodon = register::get_mastodon_data().await?;
let input = register::read_line("Enter the path to the photo you'd like to post: ")?;
let description = register::read_line("describe the media? ")?;
let description = if description.trim().is_empty() {
None
} else {
Some(description)
};

let media = mastodon.media(input).await?;
let media = mastodon.media(input, description).await?;
let status = StatusBuilder::new()
.status("Mastodon-async photo upload example/demo (automated post)")
.media_ids([media.id])
Expand Down
55 changes: 34 additions & 21 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::{error, fmt, io::Error as IoError, num::TryFromIntError};
#[cfg(feature = "env")]
use envy::Error as EnvyError;
use hyper_old_types::Error as HeaderParseError;
#[cfg(feature = "magic")]
use magic::MagicError;
use reqwest::{header::ToStrError as HeaderStrError, Error as HttpError, StatusCode};
use serde::Deserialize;
use serde_json::Error as SerdeError;
Expand Down Expand Up @@ -68,6 +70,9 @@ pub enum Error {
/// At the time of writing, this can only be triggered when a file is
/// larger than the system's usize allows.
IntConversion(TryFromIntError),
#[cfg(feature = "magic")]
/// An error received from the magic crate
Magic(MagicError),
/// Other errors
Other(String),
}
Expand All @@ -80,30 +85,33 @@ impl fmt::Display for Error {

impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
use Error::*;
match *self {
Error::Serde(ref e) => Some(e),
Error::UrlEncoded(ref e) => Some(e),
Error::Http(ref e) => Some(e),
Error::Io(ref e) => Some(e),
Error::Url(ref e) => Some(e),
Serde(ref e) => Some(e),
UrlEncoded(ref e) => Some(e),
Http(ref e) => Some(e),
Io(ref e) => Some(e),
Url(ref e) => Some(e),
#[cfg(feature = "toml")]
Error::TomlSer(ref e) => Some(e),
TomlSer(ref e) => Some(e),
#[cfg(feature = "toml")]
Error::TomlDe(ref e) => Some(e),
Error::HeaderStrError(ref e) => Some(e),
Error::HeaderParseError(ref e) => Some(e),
TomlDe(ref e) => Some(e),
HeaderStrError(ref e) => Some(e),
HeaderParseError(ref e) => Some(e),
#[cfg(feature = "env")]
Error::Envy(ref e) => Some(e),
Error::SerdeQs(ref e) => Some(e),
Error::IntConversion(ref e) => Some(e),
Error::Api {
Envy(ref e) => Some(e),
SerdeQs(ref e) => Some(e),
IntConversion(ref e) => Some(e),
#[cfg(feature = "magic")]
Magic(ref e) => Some(e),
Api {
..
}
| Error::ClientIdRequired
| Error::ClientSecretRequired
| Error::AccessTokenRequired
| Error::MissingField(_)
| Error::Other(..) => None,
| ClientIdRequired
| ClientSecretRequired
| AccessTokenRequired
| MissingField(_)
| Other(..) => None,
}
}
}
Expand Down Expand Up @@ -145,14 +153,19 @@ from! {
SerdeError => Serde,
UrlEncodedError => UrlEncoded,
UrlError => Url,
#[cfg(feature = "toml")] TomlSerError => TomlSer,
#[cfg(feature = "toml")] TomlDeError => TomlDe,
#[cfg(feature = "toml")]
TomlSerError => TomlSer,
#[cfg(feature = "toml")]
TomlDeError => TomlDe,
HeaderStrError => HeaderStrError,
HeaderParseError => HeaderParseError,
#[cfg(feature = "env")] EnvyError => Envy,
#[cfg(feature = "env")]
EnvyError => Envy,
SerdeQsError => SerdeQs,
String => Other,
TryFromIntError => IntConversion,
#[cfg(feature = "magic")]
MagicError => Magic,
}

#[macro_export]
Expand Down
99 changes: 15 additions & 84 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,33 +163,15 @@ macro_rules! route_v2 {
"`, with a description/alt-text.",
"\n# Errors\nIf `access_token` is not set."),
pub async fn $name(&self $(, $param: $typ)*, description: Option<String>) -> Result<$ret> {
use reqwest::multipart::{Form, Part};
use std::io::Read;
use log::{debug, error, as_debug};
use reqwest::multipart::Form;
use log::{debug, as_debug};
use uuid::Uuid;

let call_id = Uuid::new_v4();

let form_data = Form::new()
$(
.part(stringify!($param), {
let path = $param.as_ref();
match std::fs::File::open(path) {
Ok(mut file) => {
let mut data = if let Ok(metadata) = file.metadata() {
Vec::with_capacity(metadata.len().try_into()?)
} else {
vec![]
};
file.read_to_end(&mut data)?;
Part::bytes(data)
}
Err(err) => {
error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");
return Err(err.into());
}
}
})
.part(stringify!($param), self.get_form_part($param)?)
)*;

let form_data = if let Some(description) = description {
Expand Down Expand Up @@ -224,33 +206,16 @@ macro_rules! route_v2 {
$url,
"`\n# Errors\nIf `access_token` is not set."),
pub async fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
use reqwest::multipart::{Form, Part};
use std::io::Read;
use log::{debug, error, as_debug};
use reqwest::multipart::Form;
use log::{debug, as_debug};
use uuid::Uuid;


let call_id = Uuid::new_v4();

let form_data = Form::new()
$(
.part(stringify!($param), {
let path = $param.as_ref();
match std::fs::File::open(path) {
Ok(mut file) => {
let mut data = if let Ok(metadata) = file.metadata() {
Vec::with_capacity(metadata.len().try_into()?)
} else {
vec![]
};
file.read_to_end(&mut data)?;
Part::bytes(data)
}
Err(err) => {
error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");
return Err(err.into());
}
}
})
.part(stringify!($param), self.get_form_part($param)?)
)*;

let url = &self.route(concat!("/api/v2/", $url));
Expand Down Expand Up @@ -285,33 +250,16 @@ macro_rules! route {
$url,
"`\n# Errors\nIf `access_token` is not set."),
pub async fn $name(&self, $($param: $typ,)*) -> Result<$ret> {
use reqwest::multipart::{Form, Part};
use std::io::Read;
use log::{debug, error, as_debug};
use reqwest::multipart::Form;
use log::{debug, as_debug};
use uuid::Uuid;


let call_id = Uuid::new_v4();

let form_data = Form::new()
$(
.part(stringify!($param), {
let path = $param.as_ref();
match std::fs::File::open(path) {
Ok(mut file) => {
let mut data = if let Ok(metadata) = file.metadata() {
Vec::with_capacity(metadata.len().try_into()?)
} else {
vec![]
};
file.read_to_end(&mut data)?;
Part::bytes(data)
}
Err(err) => {
error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");
return Err(err.into());
}
}
})
.part(stringify!($param), self.get_form_part($param)?)
)*;

let url = &self.route(concat!("/api/v1/", $url));
Expand Down Expand Up @@ -343,33 +291,16 @@ macro_rules! route {
"`, with a description/alt-text.",
"\n# Errors\nIf `access_token` is not set."),
pub async fn $name(&self $(, $param: $typ)*, description: Option<String>) -> Result<$ret> {
use reqwest::multipart::{Form, Part};
use std::io::Read;
use log::{debug, error, as_debug};
use reqwest::multipart::Form;
use log::{debug, as_debug};
use uuid::Uuid;


let call_id = Uuid::new_v4();

let form_data = Form::new()
$(
.part(stringify!($param), {
let path = $param.as_ref();
match std::fs::File::open(path) {
Ok(mut file) => {
let mut data = if let Ok(metadata) = file.metadata() {
Vec::with_capacity(metadata.len().try_into()?)
} else {
vec![]
};
file.read_to_end(&mut data)?;
Part::bytes(data)
}
Err(err) => {
error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");
return Err(err.into());
}
}
})
.part(stringify!($param), self.get_form_part($param)?)
)*;

let form_data = if let Some(description) = description {
Expand Down
Loading