Added authentication and more robust response logs

This commit is contained in:
D. Scott Boggs 2022-12-18 16:03:46 -05:00
parent 648de8c8e5
commit 6afdc06cc7
2 changed files with 37 additions and 27 deletions

View File

@ -22,15 +22,10 @@ macro_rules! methods {
let url = url.as_ref(); let url = url.as_ref();
debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request"); debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request");
let response = self.client let response = self.authenticated(self.client.$method(url)).send().await?;
.$method(url)
.send()
.await?;
match response.error_for_status() { match response.error_for_status() {
Ok(response) => { Ok(response) => {
let response = response let response = read_response(response).await?;
.json()
.await?;
debug!(response = as_serde!(response), url = url, method = stringify!($method), call_id = as_debug!(call_id); "received API response"); debug!(response = as_serde!(response), url = url, method = stringify!($method), call_id = as_debug!(call_id); "received API response");
Ok(response) Ok(response)
} }
@ -66,7 +61,7 @@ macro_rules! paged_routes {
let url = self.route(concat!("/api/v1/", $url)); let url = self.route(concat!("/api/v1/", $url));
let call_id = uuid::Uuid::new_v4(); let call_id = uuid::Uuid::new_v4();
debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request"); debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request");
let response = self.client.$method(&url).send().await?; let response = self.authenticated(self.client.$method(&url)).send().await?;
match response.error_for_status() { match response.error_for_status() {
Ok(response) => { Ok(response) => {
@ -122,7 +117,7 @@ macro_rules! paged_routes {
debug!(url = url, method = "get", call_id = as_debug!(call_id); "making API request"); debug!(url = url, method = "get", call_id = as_debug!(call_id); "making API request");
let response = self.client.get(&url).send().await?; let response = self.authenticated(self.client.get(&url)).send().await?;
match response.error_for_status() { match response.error_for_status() {
Ok(response) => { Ok(response) => {
@ -208,7 +203,8 @@ macro_rules! route {
let form_data = Form::new() let form_data = Form::new()
$( $(
.part(stringify!($param), { .part(stringify!($param), {
match std::fs::File::open($param.as_ref()) { let path = $param.as_ref();
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() {
Vec::with_capacity(metadata.len().try_into()?) Vec::with_capacity(metadata.len().try_into()?)
@ -219,7 +215,7 @@ macro_rules! route {
Part::bytes(data) Part::bytes(data)
} }
Err(err) => { Err(err) => {
error!(path = $param.as_ref(), 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");
return Err(err.into()); return Err(err.into());
} }
} }
@ -234,8 +230,7 @@ macro_rules! route {
"making API request" "making API request"
); );
let response = self.client let response = self.authenticated(self.client.post(url))
.post(url)
.multipart(form_data) .multipart(form_data)
.send() .send()
.await?; .await?;
@ -319,15 +314,15 @@ macro_rules! route {
stringify!($param): $param, stringify!($param): $param,
)* )*
}); });
let url = &self.route(concat!("/api/v1/", $url));
debug!( debug!(
url = $url, method = stringify!($method), url = url.as_str(), method = stringify!($method),
call_id = as_debug!(call_id), call_id = as_debug!(call_id),
form_data = as_serde!(&form_data); form_data = as_serde!(&form_data);
"making API request" "making API request"
); );
let response = self.client let response = self.authenticated(self.client.$method(url))
.$method(&self.route(concat!("/api/v1/", $url)))
.json(&form_data) .json(&form_data)
.send() .send()
.await?; .await?;
@ -425,7 +420,7 @@ macro_rules! paged_routes_with_id {
let url = self.route(&format!(concat!("/api/v1/", $url), id)); let url = self.route(&format!(concat!("/api/v1/", $url), id));
debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request"); debug!(url = url, method = stringify!($method), call_id = as_debug!(call_id); "making API request");
let response = self.client.$method(&url).send().await?; let response = self.authenticated(self.client.$method(&url)).send().await?;
match response.error_for_status() { match response.error_for_status() {
Ok(response) => { Ok(response) => {
Page::new(self.clone(), response, call_id).await Page::new(self.clone(), response, call_id).await

View File

@ -1,4 +1,4 @@
use std::{borrow::Cow, ops::Deref, sync::Arc}; use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc};
use crate::{ use crate::{
entities::{ entities::{
@ -11,6 +11,7 @@ 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,
AddFilterRequest, AddFilterRequest,
AddPushRequest, AddPushRequest,
Data, Data,
@ -22,7 +23,7 @@ use crate::{
}; };
use futures::TryStream; use futures::TryStream;
use log::{as_debug, as_serde, debug, error, info, trace}; use log::{as_debug, as_serde, debug, error, info, trace};
use reqwest::Client; use reqwest::{Client, RequestBuilder};
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
@ -91,7 +92,7 @@ impl Mastodon {
(get (q: &'a str, resolve: bool,)) search: "search" => SearchResult, (get (q: &'a str, resolve: bool,)) search: "search" => SearchResult,
(get (local: bool,)) get_public_timeline: "timelines/public" => Vec<Status>, (get (local: bool,)) get_public_timeline: "timelines/public" => Vec<Status>,
(post (uri: Cow<'static, str>,)) follows: "follows" => Account, (post (uri: Cow<'static, str>,)) follows: "follows" => Account,
(post multipart (file: Cow<'static, str>,)) media: "media" => Attachment, (post multipart (file: impl AsRef<Path>,)) media: "media" => Attachment,
(post) clear_notifications: "notifications/clear" => Empty, (post) clear_notifications: "notifications/clear" => Empty,
(post (id: &str,)) dismiss_notification: "notifications/dismiss" => Empty, (post (id: &str,)) dismiss_notification: "notifications/dismiss" => Empty,
(get) get_push_subscription: "push/subscription" => Subscription, (get) get_push_subscription: "push/subscription" => Subscription,
@ -187,14 +188,18 @@ impl Mastodon {
/// Post a new status to the account. /// Post a new status to the account.
pub async fn new_status(&self, status: NewStatus) -> Result<Status> { pub async fn new_status(&self, status: NewStatus) -> Result<Status> {
Ok(self let url = self.route("/api/v1/statuses");
.client let response = self
.post(&self.route("/api/v1/statuses")) .authenticated(self.client.post(&url))
.json(&status) .json(&status)
.send() .send()
.await? .await?;
.json() debug!(
.await?) status = log_serde!(response Status), url = url,
headers = log_serde!(response Headers);
"received API response"
);
Ok(read_response(response).await?)
} }
/// Get timeline filtered by a hashtag(eg. `#coffee`) either locally or /// Get timeline filtered by a hashtag(eg. `#coffee`) either locally or
@ -252,6 +257,8 @@ impl Mastodon {
Ok(response) => Page::new(self.clone(), response, call_id).await, Ok(response) => Page::new(self.clone(), response, call_id).await,
Err(err) => { Err(err) => {
error!(err = as_debug!(err), url = url, method = stringify!($method), call_id = as_debug!(call_id); "error making API request"); error!(err = as_debug!(err), url = url, method = stringify!($method), call_id = as_debug!(call_id); "error making API request");
// Cannot retrieve request body as it's been moved into the
// other match arm.
Err(err.into()) Err(err.into())
}, },
} }
@ -411,7 +418,9 @@ impl Mastodon {
url.set_scheme(new_scheme) url.set_scheme(new_scheme)
.map_err(|_| Error::Other("Bad URL scheme!".to_string()))?; .map_err(|_| Error::Other("Bad URL scheme!".to_string()))?;
event_stream(url.to_string()) /// Set the bearer authentication token
fn authenticated(&self, request: RequestBuilder) -> RequestBuilder {
request.bearer_auth(&self.data.token)
} }
} }
@ -460,6 +469,12 @@ impl MastodonUnauthenticated {
let route = route.join("card")?; let route = route.join("card")?;
self.get(route.as_str()).await self.get(route.as_str()).await
} }
/// Since this client needs no authentication, this returns the
/// `RequestBuilder` unmodified.
fn authenticated(&self, request: RequestBuilder) -> RequestBuilder {
request
}
} }
impl Deref for Mastodon { impl Deref for Mastodon {
type Target = Arc<MastodonClient>; type Target = Arc<MastodonClient>;