agent_twitter_client/api/
client.rs1use crate::auth::user_auth::TwitterAuth;
2use crate::error::{Result, TwitterError};
3use crate::models::Tweet;
4use reqwest::{Client, Method};
5use serde::de::DeserializeOwned;
6use std::time::Duration;
7
8pub struct TwitterClient {
9 pub client: Client,
10 pub auth: Box<dyn TwitterAuth + Send + Sync>,
11}
12
13impl TwitterClient {
14 pub fn new(auth: Box<dyn TwitterAuth + Send + Sync>) -> Result<Self> {
15 let client = Client::builder()
16 .timeout(Duration::from_secs(30))
17 .cookie_store(true)
18 .build()?;
19
20 Ok(Self { client, auth })
21 }
22
23 pub async fn send_tweet(&self, text: &str, media_ids: Option<Vec<String>>) -> Result<Tweet> {
24 let mut params = serde_json::json!({
25 "text": text,
26 });
27
28 if let Some(ids) = media_ids {
29 params["media"] = serde_json::json!({ "media_ids": ids });
30 }
31
32 let endpoint = "https://api.twitter.com/2/tweets";
33 self.post(endpoint, Some(params)).await
34 }
35
36 pub async fn get_tweet(&self, tweet_id: &str) -> Result<Tweet> {
37 let endpoint = format!("https://api.twitter.com/2/tweets/{}", tweet_id);
38 self.get(&endpoint).await
39 }
40
41 pub async fn get_user_tweets(&self, user_id: &str, limit: usize) -> Result<Vec<Tweet>> {
42 let endpoint = format!("https://api.twitter.com/2/users/{}/tweets", user_id);
43 let params = serde_json::json!({
44 "max_results": limit,
45 "tweet.fields": "created_at,author_id,conversation_id,public_metrics"
46 });
47 self.get_with_params(&endpoint, Some(params)).await
48 }
49
50 pub async fn get<T: DeserializeOwned>(&self, endpoint: &str) -> Result<T> {
51 self.request(Method::GET, endpoint, None).await
52 }
53
54 pub async fn get_with_params<T: DeserializeOwned>(
55 &self,
56 endpoint: &str,
57 params: Option<serde_json::Value>,
58 ) -> Result<T> {
59 self.request(Method::GET, endpoint, params).await
60 }
61
62 pub async fn post<T: DeserializeOwned>(
63 &self,
64 endpoint: &str,
65 params: Option<serde_json::Value>,
66 ) -> Result<T> {
67 self.request(Method::POST, endpoint, params).await
68 }
69
70 pub async fn request<T: DeserializeOwned>(
71 &self,
72 method: Method,
73 endpoint: &str,
74 params: Option<serde_json::Value>,
75 ) -> Result<T> {
76 let mut headers = reqwest::header::HeaderMap::new();
77 self.auth.install_headers(&mut headers).await?;
78
79 let mut request = self.client.request(method, endpoint);
80 request = request.headers(headers);
81
82 if let Some(params) = params {
83 request = request.json(¶ms);
84 }
85
86 let response = request.send().await?;
87
88 if response.status().is_success() {
89 Ok(response.json().await?)
90 } else {
91 Err(TwitterError::Api(format!(
92 "Request failed with status: {}",
93 response.status()
94 )))
95 }
96 }
97}