-
Notifications
You must be signed in to change notification settings - Fork 19
/
api.rs
115 lines (96 loc) · 3.63 KB
/
api.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::time::Duration;
use reqwest::{Error, Response};
use url::Url;
pub struct ConnectionInfo {
/// The URL of the tracker API. Eg: <https://tracker:1212>.
pub url: Url,
/// The token used to authenticate with the tracker API.
pub token: String,
}
impl ConnectionInfo {
#[must_use]
pub fn new(url: Url, token: String) -> Self {
Self { url, token }
}
}
const TOKEN_PARAM_NAME: &str = "token";
const API_PATH: &str = "api/v1";
const TOTAL_REQUEST_TIMEOUT_IN_SECS: u64 = 5;
pub struct Client {
pub connection_info: ConnectionInfo,
api_base_url: Url,
client: reqwest::Client,
token_param: [(String, String); 1],
}
impl Client {
/// # Errors
///
/// Will fails if it can't build a HTTP client with a timeout.
///
/// # Panics
///
/// Will panic if the API base URL is not valid.
pub fn new(connection_info: ConnectionInfo) -> Result<Self, Error> {
let api_base_url = connection_info.url.join(API_PATH).expect("valid URL API path");
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(TOTAL_REQUEST_TIMEOUT_IN_SECS))
.build()?;
let token_param = [(TOKEN_PARAM_NAME.to_string(), connection_info.token.to_string())];
Ok(Self {
connection_info,
api_base_url,
client,
token_param,
})
}
/// Add a torrent to the tracker whitelist.
///
/// # Errors
///
/// Will return an error if the HTTP request fails.
pub async fn whitelist_torrent(&self, info_hash: &str) -> Result<Response, Error> {
let request_url = format!("{}/whitelist/{}", self.api_base_url, info_hash);
self.client.post(request_url).query(&self.token_param).send().await
}
/// Remove a torrent from the tracker whitelist.
///
/// # Errors
///
/// Will return an error if the HTTP request fails.
pub async fn remove_torrent_from_whitelist(&self, info_hash: &str) -> Result<Response, Error> {
let request_url = format!("{}/whitelist/{}", self.api_base_url, info_hash);
self.client.delete(request_url).query(&self.token_param).send().await
}
/// Retrieve a new tracker key.
///
/// # Errors
///
/// Will return an error if the HTTP request fails.
pub async fn retrieve_new_tracker_key(&self, token_valid_seconds: u64) -> Result<Response, Error> {
let request_url = format!("{}/key/{}", self.api_base_url, token_valid_seconds);
self.client.post(request_url).query(&self.token_param).send().await
}
/// Retrieve the info for one torrent.
///
/// # Errors
///
/// Will return an error if the HTTP request fails.
pub async fn get_torrent_info(&self, info_hash: &str) -> Result<Response, Error> {
let request_url = format!("{}/torrent/{}", self.api_base_url, info_hash);
self.client.get(request_url).query(&self.token_param).send().await
}
/// Retrieve the info for multiple torrents at the same time.
///
/// # Errors
///
/// Will return an error if the HTTP request fails.
pub async fn get_torrents_info(&self, info_hashes: &[String]) -> Result<Response, Error> {
let request_url = format!("{}/torrents", self.api_base_url);
let mut query_params: Vec<(String, String)> = Vec::with_capacity(info_hashes.len() + 1);
query_params.push((TOKEN_PARAM_NAME.to_string(), self.connection_info.token.clone()));
for info_hash in info_hashes {
query_params.push(("info_hash".to_string(), info_hash.clone()));
}
self.client.get(request_url).query(&query_params).send().await
}
}