1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use tokio::task::JoinHandle;
5use tracing::info;
6
7use crate::bootstrap::logging;
8use crate::cache::image::manager::ImageCacheService;
9use crate::common::AppData;
10use crate::config::validator::Validator;
11use crate::config::Configuration;
12use crate::databases::database;
13use crate::services::authentication::{DbUserAuthenticationRepository, JsonWebToken, Service};
14use crate::services::authorization::{CasbinConfiguration, CasbinEnforcer};
15use crate::services::category::{self, DbCategoryRepository};
16use crate::services::tag::{self, DbTagRepository};
17use crate::services::torrent::{
18 DbCanonicalInfoHashGroupRepository, DbTorrentAnnounceUrlRepository, DbTorrentFileRepository, DbTorrentInfoRepository,
19 DbTorrentListingGenerator, DbTorrentRepository, DbTorrentTagRepository,
20};
21use crate::services::user::{self, DbBannedUserList, DbUserProfileRepository, DbUserRepository, Repository};
22use crate::services::{about, authorization, proxy, settings, torrent};
23use crate::tracker::statistics_importer::StatisticsImporter;
24use crate::web::api::server::signals::Halted;
25use crate::web::api::server::v1::auth::Authentication;
26use crate::web::api::Version;
27use crate::{console, mailer, tracker, web};
28
29pub struct Running {
30 pub api_socket_addr: SocketAddr,
31 pub api_server: JoinHandle<std::result::Result<(), std::io::Error>>,
32 pub api_server_halt_task: tokio::sync::oneshot::Sender<Halted>,
33 pub tracker_data_importer_handle: tokio::task::JoinHandle<()>,
34}
35
36#[allow(clippy::too_many_lines)]
42pub async fn run(configuration: Configuration, api_version: &Version) -> Running {
43 let threshold = configuration.settings.read().await.logging.threshold.clone();
44
45 logging::setup(&threshold);
46
47 log_configuration(&configuration).await;
48
49 let configuration = Arc::new(configuration);
50
51 let settings = configuration.settings.read().await;
55
56 settings.validate().expect("invalid settings");
57
58 let database_connect_url = settings.database.connect_url.clone().to_string();
60 let importer_torrent_info_update_interval = settings.tracker_statistics_importer.torrent_info_update_interval;
62 let importer_port = settings.tracker_statistics_importer.port;
63 let config_bind_address = settings.net.bind_address;
65 let opt_net_tsl = settings.net.tsl.clone();
66 let unstable = settings.unstable.clone();
68
69 drop(settings);
72
73 let database = Arc::new(database::connect(&database_connect_url).await.expect("Database error."));
76 let json_web_token = Arc::new(JsonWebToken::new(configuration.clone()));
77 let auth = Arc::new(Authentication::new(json_web_token.clone()));
78
79 let category_repository = Arc::new(DbCategoryRepository::new(database.clone()));
81 let tag_repository = Arc::new(DbTagRepository::new(database.clone()));
82 let user_repository: Arc<Box<dyn Repository>> = Arc::new(Box::new(DbUserRepository::new(database.clone())));
83 let user_authentication_repository = Arc::new(DbUserAuthenticationRepository::new(database.clone()));
84 let user_profile_repository = Arc::new(DbUserProfileRepository::new(database.clone()));
85 let torrent_repository = Arc::new(DbTorrentRepository::new(database.clone()));
86 let canonical_info_hash_group_repository = Arc::new(DbCanonicalInfoHashGroupRepository::new(database.clone()));
87 let torrent_info_repository = Arc::new(DbTorrentInfoRepository::new(database.clone()));
88 let torrent_file_repository = Arc::new(DbTorrentFileRepository::new(database.clone()));
89 let torrent_announce_url_repository = Arc::new(DbTorrentAnnounceUrlRepository::new(database.clone()));
90 let torrent_tag_repository = Arc::new(DbTorrentTagRepository::new(database.clone()));
91 let torrent_listing_generator = Arc::new(DbTorrentListingGenerator::new(database.clone()));
92 let banned_user_list = Arc::new(DbBannedUserList::new(database.clone()));
93 let casbin_enforcer = Arc::new(
94 if let Some(casbin) = unstable
95 .as_ref()
96 .and_then(|u| u.auth.as_ref())
97 .and_then(|auth| auth.casbin.as_ref())
98 {
99 CasbinEnforcer::with_configuration(CasbinConfiguration::new(&casbin.model, &casbin.policy)).await
100 } else {
101 CasbinEnforcer::with_default_configuration().await
102 },
103 );
104
105 let authorization_service = Arc::new(authorization::Service::new(user_repository.clone(), casbin_enforcer.clone()));
107 let tracker_service = Arc::new(tracker::service::Service::new(configuration.clone(), database.clone()).await);
108 let tracker_statistics_importer =
109 Arc::new(StatisticsImporter::new(configuration.clone(), tracker_service.clone(), database.clone()).await);
110 let mailer_service = Arc::new(mailer::Service::new(configuration.clone()).await);
111 let image_cache_service: Arc<ImageCacheService> = Arc::new(ImageCacheService::new(configuration.clone()).await);
112 let category_service = Arc::new(category::Service::new(
113 category_repository.clone(),
114 authorization_service.clone(),
115 ));
116 let tag_service = Arc::new(tag::Service::new(tag_repository.clone(), authorization_service.clone()));
117 let proxy_service = Arc::new(proxy::Service::new(
118 image_cache_service.clone(),
119 authorization_service.clone(),
120 ));
121 let settings_service = Arc::new(settings::Service::new(configuration.clone(), authorization_service.clone()));
122 let torrent_index = Arc::new(torrent::Index::new(
123 configuration.clone(),
124 tracker_statistics_importer.clone(),
125 tracker_service.clone(),
126 user_repository.clone(),
127 category_repository.clone(),
128 torrent_repository.clone(),
129 canonical_info_hash_group_repository.clone(),
130 torrent_info_repository.clone(),
131 torrent_file_repository.clone(),
132 torrent_announce_url_repository.clone(),
133 torrent_tag_repository.clone(),
134 torrent_listing_generator.clone(),
135 authorization_service.clone(),
136 ));
137 let registration_service = Arc::new(user::RegistrationService::new(
138 configuration.clone(),
139 mailer_service.clone(),
140 user_repository.clone(),
141 user_profile_repository.clone(),
142 ));
143 let profile_service = Arc::new(user::ProfileService::new(
144 configuration.clone(),
145 user_authentication_repository.clone(),
146 authorization_service.clone(),
147 ));
148 let ban_service = Arc::new(user::BanService::new(
149 user_profile_repository.clone(),
150 banned_user_list.clone(),
151 authorization_service.clone(),
152 ));
153 let authentication_service = Arc::new(Service::new(
154 configuration.clone(),
155 json_web_token.clone(),
156 user_repository.clone(),
157 user_profile_repository.clone(),
158 user_authentication_repository.clone(),
159 ));
160
161 let about_service = Arc::new(about::Service::new(authorization_service.clone()));
162
163 let app_data = Arc::new(AppData::new(
166 configuration.clone(),
167 database.clone(),
168 json_web_token.clone(),
169 auth.clone(),
170 authentication_service,
171 tracker_service.clone(),
172 tracker_statistics_importer.clone(),
173 mailer_service,
174 image_cache_service,
175 category_repository,
176 tag_repository,
177 user_repository,
178 user_authentication_repository,
179 user_profile_repository,
180 torrent_repository,
181 canonical_info_hash_group_repository,
182 torrent_info_repository,
183 torrent_file_repository,
184 torrent_announce_url_repository,
185 torrent_tag_repository,
186 torrent_listing_generator,
187 banned_user_list,
188 category_service,
189 tag_service,
190 proxy_service,
191 settings_service,
192 torrent_index,
193 registration_service,
194 profile_service,
195 ban_service,
196 about_service,
197 ));
198
199 let tracker_statistics_importer_handle = console::cronjobs::tracker_statistics_importer::start(
202 importer_port,
203 importer_torrent_info_update_interval,
204 &tracker_statistics_importer,
205 );
206
207 let running_api = web::api::start(app_data, config_bind_address, opt_net_tsl, api_version).await;
209
210 Running {
212 api_socket_addr: running_api.socket_addr,
213 api_server: running_api.task,
214 api_server_halt_task: running_api.halt_task,
215 tracker_data_importer_handle: tracker_statistics_importer_handle,
216 }
217}
218
219async fn log_configuration(configuration: &Configuration) {
221 let mut setting = configuration.get_all().await.clone();
222 setting.remove_secrets();
223 info!("Configuration:\n{}", setting.to_json());
224}