agent_twitter_client/api/
client.rs

1use 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(&params);
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}