Skip to content

Commit 404caee

Browse files
committed
refactor: use tracker::Service in StatisticsImporter
Instead of using the API client directly. TrackerService is easier to mock becuase you only need to build simple app structs instead of reqwest responses.
1 parent 63aefcf commit 404caee

File tree

4 files changed

+61
-48
lines changed

4 files changed

+61
-48
lines changed

src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ pub async fn run(configuration: Configuration) -> Running {
4646
let database = Arc::new(connect_database(&database_connect_url).await.expect("Database error."));
4747
let auth = Arc::new(AuthorizationService::new(cfg.clone(), database.clone()));
4848
let tracker_service = Arc::new(Service::new(cfg.clone(), database.clone()).await);
49-
let tracker_statistics_importer = Arc::new(StatisticsImporter::new(cfg.clone(), database.clone()).await);
49+
let tracker_statistics_importer =
50+
Arc::new(StatisticsImporter::new(cfg.clone(), tracker_service.clone(), database.clone()).await);
5051
let mailer_service = Arc::new(MailerService::new(cfg.clone()).await);
5152
let image_cache_service = Arc::new(ImageCacheService::new(cfg.clone()).await);
5253

src/console/commands/import_tracker_statistics.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use text_colorizer::*;
99
use crate::bootstrap::config::init_configuration;
1010
use crate::bootstrap::logging;
1111
use crate::databases::database::connect_database;
12+
use crate::tracker::service::Service;
1213
use crate::tracker::statistics_importer::StatisticsImporter;
1314

1415
const NUMBER_OF_ARGUMENTS: usize = 0;
@@ -76,7 +77,9 @@ pub async fn import(_args: &Arguments) {
7677
.expect("Database error."),
7778
);
7879

79-
let tracker_statistics_importer = Arc::new(StatisticsImporter::new(cfg.clone(), database.clone()).await);
80+
let tracker_service = Arc::new(Service::new(cfg.clone(), database.clone()).await);
81+
let tracker_statistics_importer =
82+
Arc::new(StatisticsImporter::new(cfg.clone(), tracker_service.clone(), database.clone()).await);
8083

8184
tracker_statistics_importer.import_all_torrents_statistics().await.unwrap();
8285
}

src/tracker/service.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,40 @@
11
use std::sync::Arc;
22

3+
use log::error;
4+
use serde::{Deserialize, Serialize};
5+
36
use super::api::{Client, ConnectionInfo};
47
use crate::config::Configuration;
58
use crate::databases::database::Database;
69
use crate::errors::ServiceError;
710
use crate::models::tracker_key::TrackerKey;
811

12+
#[derive(Debug, Serialize, Deserialize)]
13+
pub struct TorrentInfo {
14+
pub info_hash: String,
15+
pub seeders: i64,
16+
pub completed: i64,
17+
pub leechers: i64,
18+
pub peers: Vec<Peer>,
19+
}
20+
21+
#[derive(Debug, Serialize, Deserialize)]
22+
pub struct Peer {
23+
pub peer_id: Option<PeerId>,
24+
pub peer_addr: Option<String>,
25+
pub updated: Option<i64>,
26+
pub uploaded: Option<i64>,
27+
pub downloaded: Option<i64>,
28+
pub left: Option<i64>,
29+
pub event: Option<String>,
30+
}
31+
32+
#[derive(Debug, Serialize, Deserialize)]
33+
pub struct PeerId {
34+
pub id: Option<String>,
35+
pub client: Option<String>,
36+
}
37+
938
pub struct Service {
1039
database: Arc<Box<dyn Database>>,
1140
api_client: Client,
@@ -96,6 +125,27 @@ impl Service {
96125
}
97126
}
98127

128+
/// Get torrent info from tracker.
129+
///
130+
/// # Errors
131+
///
132+
/// Will return an error if the HTTP request to get torrent info fails or
133+
/// if the response cannot be parsed.
134+
pub async fn get_torrent_info(&self, info_hash: &str) -> Result<TorrentInfo, ServiceError> {
135+
let response = self
136+
.api_client
137+
.get_torrent_info(info_hash)
138+
.await
139+
.map_err(|_| ServiceError::InternalServerError)?;
140+
141+
if let Ok(torrent_info) = response.json::<TorrentInfo>().await {
142+
Ok(torrent_info)
143+
} else {
144+
error!("Failed to parse torrent info from tracker response");
145+
Err(ServiceError::InternalServerError)
146+
}
147+
}
148+
99149
/// It builds the announce url appending the user tracker key.
100150
/// Eg: <https://tracker:7070/USER_TRACKER_KEY>
101151
fn announce_url_with_key(&self, tracker_key: &TrackerKey) -> String {

src/tracker/statistics_importer.rs

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,26 @@
11
use std::sync::Arc;
22

33
use log::{error, info};
4-
use serde::{Deserialize, Serialize};
54

6-
use super::api::{Client, ConnectionInfo};
5+
use super::service::{Service, TorrentInfo};
76
use crate::config::Configuration;
87
use crate::databases::database::{Database, DatabaseError};
98
use crate::errors::ServiceError;
109

11-
// If `TorrentInfo` struct is used in the future for other purposes, it should
12-
// be moved to a separate file. Maybe a `ClientWrapper` struct which returns
13-
// `TorrentInfo` and `TrackerKey` structs instead of `Response` structs.
14-
15-
#[derive(Debug, Serialize, Deserialize)]
16-
pub struct TorrentInfo {
17-
pub info_hash: String,
18-
pub seeders: i64,
19-
pub completed: i64,
20-
pub leechers: i64,
21-
pub peers: Vec<Peer>,
22-
}
23-
24-
#[derive(Debug, Serialize, Deserialize)]
25-
pub struct Peer {
26-
pub peer_id: Option<PeerId>,
27-
pub peer_addr: Option<String>,
28-
pub updated: Option<i64>,
29-
pub uploaded: Option<i64>,
30-
pub downloaded: Option<i64>,
31-
pub left: Option<i64>,
32-
pub event: Option<String>,
33-
}
34-
35-
#[derive(Debug, Serialize, Deserialize)]
36-
pub struct PeerId {
37-
pub id: Option<String>,
38-
pub client: Option<String>,
39-
}
40-
4110
pub struct StatisticsImporter {
4211
database: Arc<Box<dyn Database>>,
43-
api_client: Client,
12+
tracker_service: Arc<Service>,
4413
tracker_url: String,
4514
}
4615

4716
impl StatisticsImporter {
48-
pub async fn new(cfg: Arc<Configuration>, database: Arc<Box<dyn Database>>) -> Self {
17+
pub async fn new(cfg: Arc<Configuration>, tracker_service: Arc<Service>, database: Arc<Box<dyn Database>>) -> Self {
4918
let settings = cfg.settings.read().await;
50-
let api_client = Client::new(ConnectionInfo::new(
51-
settings.tracker.api_url.clone(),
52-
settings.tracker.token.clone(),
53-
));
5419
let tracker_url = settings.tracker.url.clone();
5520
drop(settings);
5621
Self {
5722
database,
58-
api_client,
23+
tracker_service,
5924
tracker_url,
6025
}
6126
}
@@ -102,13 +67,7 @@ impl StatisticsImporter {
10267
/// Will return an error if the HTTP request failed or the torrent is not
10368
/// found.
10469
pub async fn import_torrent_statistics(&self, torrent_id: i64, info_hash: &str) -> Result<TorrentInfo, ServiceError> {
105-
let response = self
106-
.api_client
107-
.get_torrent_info(info_hash)
108-
.await
109-
.map_err(|_| ServiceError::InternalServerError)?;
110-
111-
if let Ok(torrent_info) = response.json::<TorrentInfo>().await {
70+
if let Ok(torrent_info) = self.tracker_service.get_torrent_info(info_hash).await {
11271
let _ = self
11372
.database
11473
.update_tracker_info(torrent_id, &self.tracker_url, torrent_info.seeders, torrent_info.leechers)

0 commit comments

Comments
 (0)