diff --git a/.gitignore b/.gitignore index 7111969..812dc72 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ Cargo.lock .env mastodon-data.toml* libtest.rmeta +examples/playground.rs diff --git a/Cargo.toml b/Cargo.toml index 488c3e6..93e6653 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mastodon-async" -version = "1.0.2" +version = "1.0.3" authors = ["Aaron Power ", "Paul Woolcock ", "D. Scott Boggs "] description = "A wrapper around the Mastodon API." readme = "README.md" @@ -20,15 +20,11 @@ serde_json = "1" serde_qs = "0.4.5" serde_urlencoded = "0.6.1" tap-reader = "1" -tungstenite = "0.18" url = "1" # Provides parsing for the link header in get_links() in page.rs hyper-old-types = "0.11.0" futures-util = "0.3.25" - -[dependencies.magic] -version = "0.13.0" -optional = true +static_assertions = "1.1.0" [dependencies.uuid] version = "1.2.2" @@ -79,14 +75,17 @@ tempfile = "3" # for examples: femme = "2.2.1" html2text = "0.4.4" +[dev-dependencies.criterion] +version = "0.4.0" +features = ["async_tokio"] [build-dependencies.skeptic] version = "0.13" [features] -all = ["toml", "json", "env", "magic"] +all = ["toml", "json", "env"] # default = ["reqwest/default-tls"] -default = ["reqwest/default-tls", "magic"] +default = ["reqwest/default-tls"] env = ["envy"] json = [] rustls-tls = ["reqwest/rustls-tls"] diff --git a/src/errors.rs b/src/errors.rs index 9b7e7e5..d87fb9d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,8 +3,6 @@ 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; @@ -70,9 +68,6 @@ 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), } @@ -102,11 +97,7 @@ impl error::Error for Error { Envy(ref e) => Some(e), SerdeQs(ref e) => Some(e), IntConversion(ref e) => Some(e), - #[cfg(feature = "magic")] - Magic(ref e) => Some(e), - Api { - .. - } + Api { .. } | ClientIdRequired | ClientSecretRequired | AccessTokenRequired @@ -164,8 +155,6 @@ from! { SerdeQsError => SerdeQs, String => Other, TryFromIntError => IntConversion, - #[cfg(feature = "magic")] - MagicError => Magic, } #[macro_export] diff --git a/src/macros.rs b/src/macros.rs index 2c7dad4..85b6c5e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -173,7 +173,7 @@ macro_rules! route_v2 { let form_data = Form::new() $( - .part(stringify!($param), self.get_form_part($param)?) + .part(stringify!($param), Self::get_form_part($param)?) )*; let form_data = if let Some(description) = description { @@ -217,7 +217,7 @@ macro_rules! route_v2 { let form_data = Form::new() $( - .part(stringify!($param), self.get_form_part($param)?) + .part(stringify!($param), Self::get_form_part($param)?) )*; let url = &self.route(concat!("/api/v2/", $url)); @@ -261,7 +261,7 @@ macro_rules! route { let form_data = Form::new() $( - .part(stringify!($param), self.get_form_part($param)?) + .part(stringify!($param), Self::get_form_part($param)?) )*; let url = &self.route(concat!("/api/v1/", $url)); @@ -302,7 +302,7 @@ macro_rules! route { let form_data = Form::new() $( - .part(stringify!($param), self.get_form_part($param)?) + .part(stringify!($param), Self::get_form_part($param)?) )*; let form_data = if let Some(description) = description { diff --git a/src/mastodon.rs b/src/mastodon.rs index 0cb0b6b..a437867 100644 --- a/src/mastodon.rs +++ b/src/mastodon.rs @@ -11,20 +11,11 @@ use crate::{ errors::{Error, Result}, event_stream::event_stream, helpers::read_response::read_response, - log_serde, - AddFilterRequest, - AddPushRequest, - Data, - NewStatus, - Page, - StatusesRequest, - UpdateCredsRequest, - UpdatePushRequest, + log_serde, AddFilterRequest, AddPushRequest, Data, NewStatus, Page, StatusesRequest, + UpdateCredsRequest, UpdatePushRequest, }; use futures::TryStream; use log::{as_debug, as_serde, debug, error, trace}; -#[cfg(feature = "magic")] -use magic::CookieFlags; use reqwest::{multipart::Part, Client, RequestBuilder}; use url::Url; use uuid::Uuid; @@ -35,15 +26,15 @@ pub struct MastodonClient { pub(crate) client: Client, /// Raw data about your mastodon instance. pub data: Data, - /// A handle to access libmagic for mime-types. - #[cfg(feature = "magic")] - magic: magic::Cookie, } /// Your mastodon application client, handles all requests to and from Mastodon. #[derive(Debug, Clone)] pub struct Mastodon(Arc); +// This ensures we don't accidentally make Mastodon not Send or Sync again +static_assertions::assert_impl_all!(Mastodon: Send, Sync); + /// A client for making unauthenticated requests to the public API. #[derive(Clone, Debug)] pub struct MastodonUnauthenticated { @@ -54,24 +45,8 @@ pub struct MastodonUnauthenticated { impl From for Mastodon { /// Creates a mastodon instance from the data struct. - #[cfg(feature = "magic")] fn from(data: Data) -> Mastodon { - MastodonClient { - client: Client::new(), - data, - magic: Self::default_magic().expect("failed to open magic cookie or load database"), - } - .into() - } - - /// Creates a mastodon instance from the data struct. - #[cfg(not(feature = "magic"))] - fn from(data: Data) -> Mastodon { - MastodonClient { - client: Client::new(), - data, - } - .into() + Mastodon::new(Client::new(), data) } } impl Mastodon { @@ -173,46 +148,9 @@ impl Mastodon { stream_direct@"direct", } - /// Return a magic cookie, loaded with the default mime - #[cfg(feature = "magic")] - fn default_magic() -> Result { - let magic = magic::Cookie::open(Default::default())?; - magic.load::<&str>(&[])?; - magic.set_flags(CookieFlags::MIME)?; - Ok(magic) - } - - /// Create a new Mastodon Client - #[cfg(feature = "magic")] + /// A new instance. pub fn new(client: Client, data: Data) -> Self { - Self::new_with_magic( - client, - data, - Self::default_magic().expect("failed to open magic cookie or load database"), - ) - } - - /// Create a new Mastodon Client, passing in a pre-constructed magic - /// cookie. - /// - /// This is mainly here so you have a wait to construct the client which - /// won't panic. - #[cfg(feature = "magic")] - pub fn new_with_magic(client: Client, data: Data, magic: magic::Cookie) -> Self { - Mastodon(Arc::new(MastodonClient { - client, - data, - magic, - })) - } - - /// Create a new Mastodon Client - #[cfg(not(feature = "magic"))] - pub fn new(client: Client, data: Data) -> Self { - Mastodon(Arc::new(MastodonClient { - client, - data, - })) + Mastodon(Arc::new(MastodonClient { client, data })) } fn route(&self, url: &str) -> String { @@ -395,20 +333,12 @@ impl Mastodon { } /// Return a part for a multipart form submission from a file, including - /// the name of the file, and, if the "magic" feature is enabled, the mime- - /// type. - fn get_form_part(&self, path: impl AsRef) -> Result { + /// the name of the file. + fn get_form_part(path: impl AsRef) -> Result { use std::io::Read; let path = path.as_ref(); - // if it doesn't work, it's no big deal. The server will look at - // the filepath if this isn't here and things should still work. - #[cfg(feature = "magic")] - let mime = self.magic.file(path).ok(); - #[cfg(not(feature = "magic"))] - let mime: Option = None; - match std::fs::File::open(path) { Ok(mut file) => { let mut data = if let Ok(metadata) = file.metadata() { @@ -417,13 +347,8 @@ impl Mastodon { vec![] }; file.read_to_end(&mut data)?; - let part = - Part::bytes(data).file_name(Cow::Owned(path.to_string_lossy().to_string())); - Ok(if let Some(mime) = mime { - part.mime_str(&mime)? - } else { - part - }) + // TODO extract filename, error on dirs, etc. + Ok(Part::bytes(data).file_name(Cow::Owned(path.to_string_lossy().to_string()))) }, Err(err) => { error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");