diff --git a/src/error.rs b/src/error.rs index 7edfba6..6dad3de 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,7 @@ pub enum Error { BadMedia, NoUserData, TooManyRequests, + ApiError(String), Unknown } @@ -16,6 +17,7 @@ impl fmt::Display for Error { Error::Reqwest(ref err) => write!(f, "HTTP request error: {}", err), Error::BadMedia => write!(f, "faulty media"), Error::NoUserData => write!(f, "No user data found"), + Error::ApiError(ref str) => write!(f, "Api Error: {}", str), Error::Unknown => write!(f, "unknown"), Error::TooManyRequests => write!(f, "too many reqs"), } @@ -28,6 +30,7 @@ impl error::Error for Error { Error::Reqwest(ref err) => Some(err), Error::BadMedia => None, Error::NoUserData => None, + Error::ApiError(_) => None, Error::Unknown => None, Error::TooManyRequests => None, } diff --git a/src/lib.rs b/src/lib.rs index 8417231..0c3efc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,6 +119,7 @@ impl TweetBuilder { pub mod error; use error::Error; +use error::Error::ApiError; #[derive(Debug, Deserialize)] struct TwitterApiResponse { @@ -160,6 +161,18 @@ impl TwitterClient { .await?) } + fn collect_errors(&self, response: &TwitterApiResponse) -> Vec { + let mut res = vec![]; + if let Some(errors) = &response.errors { + errors.iter(). + for_each(|e| res.push(e.message.to_string())); + } + if let Some(detail) = &response.detail { + res.push(detail.to_string()); + } + res + } + async fn _request( &mut self, method: &str, @@ -181,17 +194,14 @@ impl TwitterClient { match res.data { Some(data) => Ok(serde_json::from_value(data).unwrap()), None => { - if let Some(detail) = res.detail { - match detail.as_ref() { - "Too Many Requests" => Err(Error::TooManyRequests), - _ => Err(Error::Unknown), - } - } else if let Some(errors) = res.errors { - println!("got errors: {:?}", errors); - Err(Error::Unknown) - } else { - Err(Error::Unknown) + let error_strings = self.collect_errors(&res); + if error_strings.contains(&String::from("Too Many Requests")) { + return Err(Error::TooManyRequests); + } + if !error_strings.is_empty() { + return Err(ApiError(error_strings.join(" ").to_string())); } + return Err(Error::Unknown); } } } @@ -219,17 +229,14 @@ impl TwitterClient { match res.data { Some(data) => Ok(serde_json::from_value(data).unwrap()), None => { - if let Some(detail) = res.detail { - match detail.as_ref() { - "Too Many Requests" => Err(Error::TooManyRequests), - _ => Err(Error::Unknown), - } - } else if let Some(errors) = res.errors { - println!("got errors: {:?}", errors); - Err(Error::Unknown) - } else { - Err(Error::Unknown) + let error_strings = self.collect_errors(&res); + if error_strings.contains(&String::from("Too Many Requests")) { + return Err(Error::TooManyRequests); + } + if !error_strings.is_empty() { + return Err(ApiError(error_strings.join(" ").to_string())); } + return Err(Error::Unknown); } } } @@ -277,9 +284,10 @@ impl TwitterClient { &mut self, path: &str, filename: Option, + mime: Option ) -> Result { let file_bytes; - let mime; + let detected_mime: Option; if path.starts_with("http") { let media = reqwest::get(path).await?; let headers = media.headers().clone(); @@ -290,12 +298,12 @@ impl TwitterClient { .unwrap() .to_owned(); file_bytes = media.bytes().await?.to_vec(); - mime = content_type_header; + detected_mime = Some(content_type_header); } else { match fs::read(path) { Ok(bytes) => { file_bytes = bytes; - mime = infer::get(&file_bytes).unwrap().mime_type().to_string(); + detected_mime = infer::get(&file_bytes).map(|m| m.mime_type().to_string()); } _ => return Err(Error::BadMedia), } @@ -319,6 +327,7 @@ impl TwitterClient { } else { // chunked media upload chunked = true; + let media_type = mime.unwrap_or_else(|| detected_mime.expect("Unable to infer media_type and no mime provided")); let init = self ._multipart_request::( "POST", @@ -326,7 +335,7 @@ impl TwitterClient { reqwest::multipart::Form::new() .text("command", "INIT") .text("total_bytes", len.to_string()) - .text("media_type", mime.clone()), + .text("media_type", media_type.clone()), None, ) .await;