use reqwest::{multipart::Form, Error, Response};
use serde_json::Value;
use std::time::Duration;
use twapi_oauth::oauth1_authorization_header;
pub struct Client {
consumer_key: String,
consumer_secret: String,
access_key: String,
access_secret: String,
timeout_sec: Option<Duration>,
}
impl Client {
pub fn new(
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Self {
Self {
consumer_key: consumer_key.to_owned(),
consumer_secret: consumer_secret.to_owned(),
access_key: access_key.to_owned(),
access_secret: access_secret.to_owned(),
timeout_sec,
}
}
pub fn new_by_env() -> Result<Self, std::env::VarError> {
Ok(Self {
consumer_key: std::env::var("CONSUMER_KEY")?,
consumer_secret: std::env::var("CONSUMER_SECRET")?,
access_key: std::env::var("ACCESS_KEY")?,
access_secret: std::env::var("ACCESS_SECRET")?,
timeout_sec: None,
})
}
fn calc_oauth(&self, method: &str, url: &str, query_options: &Vec<(&str, &str)>) -> String {
oauth1_authorization_header(
&self.consumer_key,
&self.consumer_secret,
&self.access_key,
&self.access_secret,
method,
url,
&query_options,
)
}
pub async fn get(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
) -> Result<Response, Error> {
let authorization = self.calc_oauth("GET", url, &query_options);
crate::raw::get(url, query_options, &authorization, self.timeout_sec).await
}
pub async fn post(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
form_options: &Vec<(&str, &str)>,
) -> Result<Response, Error> {
let mut merged_options = query_options.clone();
for option in form_options {
merged_options.push(*option);
}
let authorization = self.calc_oauth("POST", url, &merged_options);
crate::raw::post(
url,
query_options,
form_options,
&authorization,
self.timeout_sec,
)
.await
}
pub async fn json(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
data: &Value,
) -> Result<Response, Error> {
let authorization = self.calc_oauth("POST", url, &query_options);
crate::raw::json(url, query_options, data, &authorization, self.timeout_sec).await
}
pub async fn put(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
) -> Result<Response, Error> {
let authorization = self.calc_oauth("PUT", url, &query_options);
crate::raw::put(url, query_options, &authorization, self.timeout_sec).await
}
pub async fn delete(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
) -> Result<Response, Error> {
let authorization = self.calc_oauth("DELETE", url, &query_options);
crate::raw::delete(url, query_options, &authorization, self.timeout_sec).await
}
pub async fn multipart(
&self,
url: &str,
query_options: &Vec<(&str, &str)>,
data: Form,
) -> Result<Response, Error> {
let authorization = self.calc_oauth("POST", url, &query_options);
crate::raw::multipart(url, query_options, data, &authorization, self.timeout_sec).await
}
}
pub async fn get(
url: &str,
query_options: &Vec<(&str, &str)>,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.get(url, query_options).await
}
pub async fn post(
url: &str,
query_options: &Vec<(&str, &str)>,
form_options: &Vec<(&str, &str)>,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.post(url, query_options, form_options).await
}
pub async fn json(
url: &str,
query_options: &Vec<(&str, &str)>,
data: &Value,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.json(url, query_options, data).await
}
pub async fn put(
url: &str,
query_options: &Vec<(&str, &str)>,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.put(url, query_options).await
}
pub async fn delete(
url: &str,
query_options: &Vec<(&str, &str)>,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.delete(url, query_options).await
}
pub async fn multipart(
url: &str,
query_options: &Vec<(&str, &str)>,
data: Form,
consumer_key: &str,
consumer_secret: &str,
access_key: &str,
access_secret: &str,
timeout_sec: Option<Duration>,
) -> Result<Response, Error> {
let client = Client::new(
consumer_key,
consumer_secret,
access_key,
access_secret,
timeout_sec,
);
client.multipart(url, query_options, data).await
}
#[cfg(test)]
mod tests {
use crate::*;
use serde_json::Value;
use std::env;
#[tokio::test]
async fn test_api() {
let consumer_key = env::var("CONSUMER_KEY").unwrap();
let consumer_secret = env::var("CONSUMER_SECRET").unwrap();
let access_key = env::var("ACCESS_KEY").unwrap();
let access_secret = env::var("ACCESS_SECRET").unwrap();
let url = "https://api.twitter.com/1.1/search/tweets.json";
let query_options = vec![("q", "*abc"), ("count", "2")];
let res: Value = v1::get(
url,
&query_options,
&consumer_key,
&consumer_secret,
&access_key,
&access_secret,
None,
)
.await
.unwrap()
.json()
.await
.unwrap();
println!("{:?}", res);
let url = "https://api.twitter.com/1.1/statuses/home_timeline.json";
let query_options = vec![("count", "2")];
let res: Value = v1::get(
url,
&query_options,
&consumer_key,
&consumer_secret,
&access_key,
&access_secret,
None,
)
.await
.unwrap()
.json()
.await
.unwrap();
println!("{:?}", res);
}
}