torrust_index_backend/
app.rs

1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use tokio::task::JoinHandle;
5
6use crate::bootstrap::logging;
7use crate::cache::image::manager::ImageCacheService;
8use crate::common::AppData;
9use crate::config::Configuration;
10use crate::databases::database;
11use crate::services::authentication::{DbUserAuthenticationRepository, JsonWebToken, Service};
12use crate::services::category::{self, DbCategoryRepository};
13use crate::services::tag::{self, DbTagRepository};
14use crate::services::torrent::{
15    DbTorrentAnnounceUrlRepository, DbTorrentFileRepository, DbTorrentInfoRepository, DbTorrentListingGenerator,
16    DbTorrentRepository, DbTorrentTagRepository,
17};
18use crate::services::user::{self, DbBannedUserList, DbUserProfileRepository, DbUserRepository};
19use crate::services::{proxy, settings, torrent};
20use crate::tracker::statistics_importer::StatisticsImporter;
21use crate::web::api::v1::auth::Authentication;
22use crate::web::api::{start, Version};
23use crate::{mailer, tracker};
24
25pub struct Running {
26    pub api_socket_addr: SocketAddr,
27    pub api_server: Option<JoinHandle<std::result::Result<(), std::io::Error>>>,
28    pub tracker_data_importer_handle: tokio::task::JoinHandle<()>,
29}
30
31/// Runs the application.
32///
33/// # Panics
34///
35/// It panics if there is an error connecting to the database.
36#[allow(clippy::too_many_lines)]
37pub async fn run(configuration: Configuration, api_version: &Version) -> Running {
38    let log_level = configuration.settings.read().await.log_level.clone();
39
40    logging::setup(&log_level);
41
42    let configuration = Arc::new(configuration);
43
44    // Get configuration settings needed to build the app dependencies and
45    // services: main API server and tracker torrents importer.
46
47    let settings = configuration.settings.read().await;
48
49    let database_connect_url = settings.database.connect_url.clone();
50    let torrent_info_update_interval = settings.tracker_statistics_importer.torrent_info_update_interval;
51    let net_ip = "0.0.0.0".to_string();
52    let net_port = settings.net.port;
53
54    // IMPORTANT: drop settings before starting server to avoid read locks that
55    // leads to requests hanging.
56    drop(settings);
57
58    // Build app dependencies
59
60    let database = Arc::new(database::connect(&database_connect_url).await.expect("Database error."));
61    let json_web_token = Arc::new(JsonWebToken::new(configuration.clone()));
62    let auth = Arc::new(Authentication::new(json_web_token.clone()));
63
64    // Repositories
65    let category_repository = Arc::new(DbCategoryRepository::new(database.clone()));
66    let tag_repository = Arc::new(DbTagRepository::new(database.clone()));
67    let user_repository = Arc::new(DbUserRepository::new(database.clone()));
68    let user_authentication_repository = Arc::new(DbUserAuthenticationRepository::new(database.clone()));
69    let user_profile_repository = Arc::new(DbUserProfileRepository::new(database.clone()));
70    let torrent_repository = Arc::new(DbTorrentRepository::new(database.clone()));
71    let torrent_info_repository = Arc::new(DbTorrentInfoRepository::new(database.clone()));
72    let torrent_file_repository = Arc::new(DbTorrentFileRepository::new(database.clone()));
73    let torrent_announce_url_repository = Arc::new(DbTorrentAnnounceUrlRepository::new(database.clone()));
74    let torrent_tag_repository = Arc::new(DbTorrentTagRepository::new(database.clone()));
75    let torrent_listing_generator = Arc::new(DbTorrentListingGenerator::new(database.clone()));
76    let banned_user_list = Arc::new(DbBannedUserList::new(database.clone()));
77
78    // Services
79    let tracker_service = Arc::new(tracker::service::Service::new(configuration.clone(), database.clone()).await);
80    let tracker_statistics_importer =
81        Arc::new(StatisticsImporter::new(configuration.clone(), tracker_service.clone(), database.clone()).await);
82    let mailer_service = Arc::new(mailer::Service::new(configuration.clone()).await);
83    let image_cache_service: Arc<ImageCacheService> = Arc::new(ImageCacheService::new(configuration.clone()).await);
84    let category_service = Arc::new(category::Service::new(category_repository.clone(), user_repository.clone()));
85    let tag_service = Arc::new(tag::Service::new(tag_repository.clone(), user_repository.clone()));
86    let proxy_service = Arc::new(proxy::Service::new(image_cache_service.clone(), user_repository.clone()));
87    let settings_service = Arc::new(settings::Service::new(configuration.clone(), user_repository.clone()));
88    let torrent_index = Arc::new(torrent::Index::new(
89        configuration.clone(),
90        tracker_statistics_importer.clone(),
91        tracker_service.clone(),
92        user_repository.clone(),
93        category_repository.clone(),
94        torrent_repository.clone(),
95        torrent_info_repository.clone(),
96        torrent_file_repository.clone(),
97        torrent_announce_url_repository.clone(),
98        torrent_tag_repository.clone(),
99        torrent_listing_generator.clone(),
100    ));
101    let registration_service = Arc::new(user::RegistrationService::new(
102        configuration.clone(),
103        mailer_service.clone(),
104        user_repository.clone(),
105        user_profile_repository.clone(),
106    ));
107    let ban_service = Arc::new(user::BanService::new(
108        user_repository.clone(),
109        user_profile_repository.clone(),
110        banned_user_list.clone(),
111    ));
112    let authentication_service = Arc::new(Service::new(
113        configuration.clone(),
114        json_web_token.clone(),
115        user_repository.clone(),
116        user_profile_repository.clone(),
117        user_authentication_repository.clone(),
118    ));
119
120    // Build app container
121
122    let app_data = Arc::new(AppData::new(
123        configuration.clone(),
124        database.clone(),
125        json_web_token.clone(),
126        auth.clone(),
127        authentication_service,
128        tracker_service.clone(),
129        tracker_statistics_importer.clone(),
130        mailer_service,
131        image_cache_service,
132        category_repository,
133        tag_repository,
134        user_repository,
135        user_authentication_repository,
136        user_profile_repository,
137        torrent_repository,
138        torrent_info_repository,
139        torrent_file_repository,
140        torrent_announce_url_repository,
141        torrent_tag_repository,
142        torrent_listing_generator,
143        banned_user_list,
144        category_service,
145        tag_service,
146        proxy_service,
147        settings_service,
148        torrent_index,
149        registration_service,
150        ban_service,
151    ));
152
153    // Start repeating task to import tracker torrent data and updating
154    // seeders and leechers info.
155
156    let weak_tracker_statistics_importer = Arc::downgrade(&tracker_statistics_importer);
157
158    let tracker_statistics_importer_handle = tokio::spawn(async move {
159        let interval = std::time::Duration::from_secs(torrent_info_update_interval);
160        let mut interval = tokio::time::interval(interval);
161        interval.tick().await; // first tick is immediate...
162        loop {
163            interval.tick().await;
164            if let Some(tracker) = weak_tracker_statistics_importer.upgrade() {
165                let _ = tracker.import_all_torrents_statistics().await;
166            } else {
167                break;
168            }
169        }
170    });
171
172    // Start API server
173
174    let running_api = start(app_data, &net_ip, net_port, api_version).await;
175
176    Running {
177        api_socket_addr: running_api.socket_addr,
178        api_server: running_api.api_server,
179        tracker_data_importer_handle: tracker_statistics_importer_handle,
180    }
181}