diff --git a/src/lib.rs b/src/lib.rs index 9f5142d..fef08ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,15 +61,19 @@ pub use streaming::Streaming; #[derive(Deserialize)] struct Instance { - title: String, - uri: String, - urls: entities::URLs, + // title: String, + // uri: String, + // urls: entities::URLs, version: String, } /// Detect which SNS the provided URL is. To detect SNS, the URL has to open `/api/v1/instance` or `/api/meta` endpoint. pub async fn detector(url: &str) -> Result { - let res = reqwest::get(format!("{}{}", url, "/api/v1/instance")).await; + let client = reqwest::Client::builder().user_agent("megalodon").build()?; + let res = client + .get(format!("{}{}", url, "/api/v1/instance")) + .send() + .await; match res { Ok(res) => { diff --git a/src/mastodon/mastodon.rs b/src/mastodon/mastodon.rs index 18b96c0..c198d4a 100644 --- a/src/mastodon/mastodon.rs +++ b/src/mastodon/mastodon.rs @@ -25,6 +25,7 @@ pub struct Mastodon { client: APIClient, base_url: String, access_token: Option, + user_agent: Option, } impl Mastodon { @@ -34,11 +35,12 @@ impl Mastodon { access_token: Option, user_agent: Option, ) -> Mastodon { - let client = APIClient::new(base_url.clone(), access_token.clone(), user_agent); + let client = APIClient::new(base_url.clone(), access_token.clone(), user_agent.clone()); Mastodon { client, base_url, access_token, + user_agent, } } @@ -2805,6 +2807,7 @@ impl megalodon::Megalodon for Mastodon { String::from("user"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2817,6 +2820,7 @@ impl megalodon::Megalodon for Mastodon { String::from("public"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2829,6 +2833,7 @@ impl megalodon::Megalodon for Mastodon { String::from("public:local"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2841,6 +2846,7 @@ impl megalodon::Megalodon for Mastodon { String::from("direct"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2857,6 +2863,7 @@ impl megalodon::Megalodon for Mastodon { String::from("hashtag"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2873,6 +2880,7 @@ impl megalodon::Megalodon for Mastodon { String::from("list"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) diff --git a/src/mastodon/web_socket.rs b/src/mastodon/web_socket.rs index f7770b4..7f2f5bd 100644 --- a/src/mastodon/web_socket.rs +++ b/src/mastodon/web_socket.rs @@ -3,11 +3,13 @@ use std::thread; use std::time::Duration; use super::entities; +use crate::default::DEFAULT_UA; use crate::error::{Error, Kind}; use crate::streaming::{Message, Streaming}; use async_trait::async_trait; use futures_util::{SinkExt, StreamExt}; use serde::Deserialize; +use tokio_tungstenite::tungstenite::client::IntoClientRequest; use tokio_tungstenite::{ connect_async, tungstenite::protocol::frame::coding::CloseCode, tungstenite::protocol::Message as WebSocketMessage, @@ -23,6 +25,7 @@ pub struct WebSocket { stream: String, params: Option>, access_token: Option, + user_agent: String, } #[derive(Deserialize)] @@ -37,12 +40,19 @@ impl WebSocket { stream: String, params: Option>, access_token: Option, + user_agent: Option, ) -> Self { + let ua: String; + match user_agent { + Some(agent) => ua = agent, + None => ua = DEFAULT_UA.to_string(), + } Self { url, stream, params, access_token, + user_agent: ua, } } @@ -133,11 +143,19 @@ impl WebSocket { url: &str, callback: &Box, ) -> Result<(), InnerError> { - let (mut socket, response) = - connect_async(Url::parse(url).unwrap()).await.map_err(|e| { - log::error!("Failed to connect: {}", e); + let mut req = Url::parse(url) + .unwrap() + .into_client_request() + .map_err(|e| { + log::error!("Failed to parse url: {}", e); InnerError::new(InnerKind::ConnectionError) })?; + req.headers_mut() + .insert("User-Agent", self.user_agent.parse().unwrap()); + let (mut socket, response) = connect_async(req).await.map_err(|e| { + log::error!("Failed to connect: {}", e); + InnerError::new(InnerKind::ConnectionError) + })?; log::debug!("Connected to {}", url); log::debug!("Response HTTP code: {}", response.status()); diff --git a/src/pleroma/pleroma.rs b/src/pleroma/pleroma.rs index e3eb691..c8e45b1 100644 --- a/src/pleroma/pleroma.rs +++ b/src/pleroma/pleroma.rs @@ -26,16 +26,18 @@ pub struct Pleroma { client: APIClient, base_url: String, access_token: Option, + user_agent: Option, } impl Pleroma { /// Create a new [`Pleroma`]. pub fn new(base_url: String, access_token: Option, user_agent: Option) -> Self { - let client = APIClient::new(base_url.clone(), access_token.clone(), user_agent); + let client = APIClient::new(base_url.clone(), access_token.clone(), user_agent.clone()); Self { client, base_url, access_token, + user_agent, } } @@ -2806,6 +2808,7 @@ impl megalodon::Megalodon for Pleroma { String::from("user"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2818,6 +2821,7 @@ impl megalodon::Megalodon for Pleroma { String::from("public"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2830,6 +2834,7 @@ impl megalodon::Megalodon for Pleroma { String::from("public:local"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2842,6 +2847,7 @@ impl megalodon::Megalodon for Pleroma { String::from("direct"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2858,6 +2864,7 @@ impl megalodon::Megalodon for Pleroma { String::from("hashtag"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) @@ -2874,6 +2881,7 @@ impl megalodon::Megalodon for Pleroma { String::from("list"), Some(params), self.access_token.clone(), + self.user_agent.clone(), ); Box::new(c) diff --git a/src/pleroma/web_socket.rs b/src/pleroma/web_socket.rs index f7770b4..7f2f5bd 100644 --- a/src/pleroma/web_socket.rs +++ b/src/pleroma/web_socket.rs @@ -3,11 +3,13 @@ use std::thread; use std::time::Duration; use super::entities; +use crate::default::DEFAULT_UA; use crate::error::{Error, Kind}; use crate::streaming::{Message, Streaming}; use async_trait::async_trait; use futures_util::{SinkExt, StreamExt}; use serde::Deserialize; +use tokio_tungstenite::tungstenite::client::IntoClientRequest; use tokio_tungstenite::{ connect_async, tungstenite::protocol::frame::coding::CloseCode, tungstenite::protocol::Message as WebSocketMessage, @@ -23,6 +25,7 @@ pub struct WebSocket { stream: String, params: Option>, access_token: Option, + user_agent: String, } #[derive(Deserialize)] @@ -37,12 +40,19 @@ impl WebSocket { stream: String, params: Option>, access_token: Option, + user_agent: Option, ) -> Self { + let ua: String; + match user_agent { + Some(agent) => ua = agent, + None => ua = DEFAULT_UA.to_string(), + } Self { url, stream, params, access_token, + user_agent: ua, } } @@ -133,11 +143,19 @@ impl WebSocket { url: &str, callback: &Box, ) -> Result<(), InnerError> { - let (mut socket, response) = - connect_async(Url::parse(url).unwrap()).await.map_err(|e| { - log::error!("Failed to connect: {}", e); + let mut req = Url::parse(url) + .unwrap() + .into_client_request() + .map_err(|e| { + log::error!("Failed to parse url: {}", e); InnerError::new(InnerKind::ConnectionError) })?; + req.headers_mut() + .insert("User-Agent", self.user_agent.parse().unwrap()); + let (mut socket, response) = connect_async(req).await.map_err(|e| { + log::error!("Failed to connect: {}", e); + InnerError::new(InnerKind::ConnectionError) + })?; log::debug!("Connected to {}", url); log::debug!("Response HTTP code: {}", response.status());