Merge pull request #13 from dscottboggs/fix/magic-is-not-send

no more magic
This commit is contained in:
Scott Boggs 2022-12-28 08:56:42 -05:00 committed by GitHub
commit 4287c7526f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 25 additions and 111 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ Cargo.lock
.env .env
mastodon-data.toml* mastodon-data.toml*
libtest.rmeta libtest.rmeta
examples/playground.rs

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mastodon-async" name = "mastodon-async"
version = "1.0.2" version = "1.0.3"
authors = ["Aaron Power <theaaronepower@gmail.com>", "Paul Woolcock <paul@woolcock.us>", "D. Scott Boggs <scott@tams.tech>"] authors = ["Aaron Power <theaaronepower@gmail.com>", "Paul Woolcock <paul@woolcock.us>", "D. Scott Boggs <scott@tams.tech>"]
description = "A wrapper around the Mastodon API." description = "A wrapper around the Mastodon API."
readme = "README.md" readme = "README.md"
@ -20,15 +20,11 @@ serde_json = "1"
serde_qs = "0.4.5" serde_qs = "0.4.5"
serde_urlencoded = "0.6.1" serde_urlencoded = "0.6.1"
tap-reader = "1" tap-reader = "1"
tungstenite = "0.18"
url = "1" url = "1"
# Provides parsing for the link header in get_links() in page.rs # Provides parsing for the link header in get_links() in page.rs
hyper-old-types = "0.11.0" hyper-old-types = "0.11.0"
futures-util = "0.3.25" futures-util = "0.3.25"
static_assertions = "1.1.0"
[dependencies.magic]
version = "0.13.0"
optional = true
[dependencies.uuid] [dependencies.uuid]
version = "1.2.2" version = "1.2.2"
@ -79,14 +75,17 @@ tempfile = "3"
# for examples: # for examples:
femme = "2.2.1" femme = "2.2.1"
html2text = "0.4.4" html2text = "0.4.4"
[dev-dependencies.criterion]
version = "0.4.0"
features = ["async_tokio"]
[build-dependencies.skeptic] [build-dependencies.skeptic]
version = "0.13" version = "0.13"
[features] [features]
all = ["toml", "json", "env", "magic"] all = ["toml", "json", "env"]
# default = ["reqwest/default-tls"] # default = ["reqwest/default-tls"]
default = ["reqwest/default-tls", "magic"] default = ["reqwest/default-tls"]
env = ["envy"] env = ["envy"]
json = [] json = []
rustls-tls = ["reqwest/rustls-tls"] rustls-tls = ["reqwest/rustls-tls"]

View File

@ -3,8 +3,6 @@ use std::{error, fmt, io::Error as IoError, num::TryFromIntError};
#[cfg(feature = "env")] #[cfg(feature = "env")]
use envy::Error as EnvyError; use envy::Error as EnvyError;
use hyper_old_types::Error as HeaderParseError; use hyper_old_types::Error as HeaderParseError;
#[cfg(feature = "magic")]
use magic::MagicError;
use reqwest::{header::ToStrError as HeaderStrError, Error as HttpError, StatusCode}; use reqwest::{header::ToStrError as HeaderStrError, Error as HttpError, StatusCode};
use serde::Deserialize; use serde::Deserialize;
use serde_json::Error as SerdeError; 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 /// At the time of writing, this can only be triggered when a file is
/// larger than the system's usize allows. /// larger than the system's usize allows.
IntConversion(TryFromIntError), IntConversion(TryFromIntError),
#[cfg(feature = "magic")]
/// An error received from the magic crate
Magic(MagicError),
/// Other errors /// Other errors
Other(String), Other(String),
} }
@ -102,11 +97,7 @@ impl error::Error for Error {
Envy(ref e) => Some(e), Envy(ref e) => Some(e),
SerdeQs(ref e) => Some(e), SerdeQs(ref e) => Some(e),
IntConversion(ref e) => Some(e), IntConversion(ref e) => Some(e),
#[cfg(feature = "magic")] Api { .. }
Magic(ref e) => Some(e),
Api {
..
}
| ClientIdRequired | ClientIdRequired
| ClientSecretRequired | ClientSecretRequired
| AccessTokenRequired | AccessTokenRequired
@ -164,8 +155,6 @@ from! {
SerdeQsError => SerdeQs, SerdeQsError => SerdeQs,
String => Other, String => Other,
TryFromIntError => IntConversion, TryFromIntError => IntConversion,
#[cfg(feature = "magic")]
MagicError => Magic,
} }
#[macro_export] #[macro_export]

View File

@ -173,7 +173,7 @@ macro_rules! route_v2 {
let form_data = Form::new() 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 { let form_data = if let Some(description) = description {
@ -217,7 +217,7 @@ macro_rules! route_v2 {
let form_data = Form::new() 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)); let url = &self.route(concat!("/api/v2/", $url));
@ -261,7 +261,7 @@ macro_rules! route {
let form_data = Form::new() 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)); let url = &self.route(concat!("/api/v1/", $url));
@ -302,7 +302,7 @@ macro_rules! route {
let form_data = Form::new() 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 { let form_data = if let Some(description) = description {

View File

@ -11,20 +11,11 @@ use crate::{
errors::{Error, Result}, errors::{Error, Result},
event_stream::event_stream, event_stream::event_stream,
helpers::read_response::read_response, helpers::read_response::read_response,
log_serde, log_serde, AddFilterRequest, AddPushRequest, Data, NewStatus, Page, StatusesRequest,
AddFilterRequest, UpdateCredsRequest, UpdatePushRequest,
AddPushRequest,
Data,
NewStatus,
Page,
StatusesRequest,
UpdateCredsRequest,
UpdatePushRequest,
}; };
use futures::TryStream; use futures::TryStream;
use log::{as_debug, as_serde, debug, error, trace}; use log::{as_debug, as_serde, debug, error, trace};
#[cfg(feature = "magic")]
use magic::CookieFlags;
use reqwest::{multipart::Part, Client, RequestBuilder}; use reqwest::{multipart::Part, Client, RequestBuilder};
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
@ -35,15 +26,15 @@ pub struct MastodonClient {
pub(crate) client: Client, pub(crate) client: Client,
/// Raw data about your mastodon instance. /// Raw data about your mastodon instance.
pub data: Data, 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. /// Your mastodon application client, handles all requests to and from Mastodon.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mastodon(Arc<MastodonClient>); pub struct Mastodon(Arc<MastodonClient>);
// 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. /// A client for making unauthenticated requests to the public API.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MastodonUnauthenticated { pub struct MastodonUnauthenticated {
@ -54,24 +45,8 @@ pub struct MastodonUnauthenticated {
impl From<Data> for Mastodon { impl From<Data> for Mastodon {
/// Creates a mastodon instance from the data struct. /// Creates a mastodon instance from the data struct.
#[cfg(feature = "magic")]
fn from(data: Data) -> Mastodon { fn from(data: Data) -> Mastodon {
MastodonClient { Mastodon::new(Client::new(), data)
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()
} }
} }
impl Mastodon { impl Mastodon {
@ -173,46 +148,9 @@ impl Mastodon {
stream_direct@"direct", stream_direct@"direct",
} }
/// Return a magic cookie, loaded with the default mime /// A new instance.
#[cfg(feature = "magic")]
fn default_magic() -> Result<magic::Cookie> {
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")]
pub fn new(client: Client, data: Data) -> Self { pub fn new(client: Client, data: Data) -> Self {
Self::new_with_magic( Mastodon(Arc::new(MastodonClient { client, data }))
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,
}))
} }
fn route(&self, url: &str) -> String { fn route(&self, url: &str) -> String {
@ -395,20 +333,12 @@ impl Mastodon {
} }
/// Return a part for a multipart form submission from a file, including /// 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- /// the name of the file.
/// type. fn get_form_part(path: impl AsRef<Path>) -> Result<Part> {
fn get_form_part(&self, path: impl AsRef<Path>) -> Result<Part> {
use std::io::Read; use std::io::Read;
let path = path.as_ref(); 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<String> = None;
match std::fs::File::open(path) { match std::fs::File::open(path) {
Ok(mut file) => { Ok(mut file) => {
let mut data = if let Ok(metadata) = file.metadata() { let mut data = if let Ok(metadata) = file.metadata() {
@ -417,13 +347,8 @@ impl Mastodon {
vec![] vec![]
}; };
file.read_to_end(&mut data)?; file.read_to_end(&mut data)?;
let part = // TODO extract filename, error on dirs, etc.
Part::bytes(data).file_name(Cow::Owned(path.to_string_lossy().to_string())); Ok(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
})
}, },
Err(err) => { Err(err) => {
error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form"); error!(path = as_debug!(path), error = as_debug!(err); "error reading file contents for multipart form");