torrust-actix 4.1.2

A rich, fast and efficient Bittorrent Tracker.
//! Core TorrentTracker initialization and construction.
//!
//! Contains the main constructor for creating a new tracker instance
//! with all required subsystems initialized.

use crate::cache::structs::cache_connector::CacheConnector;
use crate::config::structs::configuration::Configuration;
use crate::database::structs::database_connector::DatabaseConnector;
use crate::ssl::certificate_store::CertificateStore;
use crate::stats::structs::stats_atomics::StatsAtomics;
use crate::tracker::structs::torrent_tracker::TorrentTracker;
use chrono::Utc;
use log::{info, warn};
use parking_lot::RwLock;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::sync::atomic::{AtomicBool, AtomicI64};
use std::sync::Arc;

impl TorrentTracker {
    /// Creates a new TorrentTracker instance with all subsystems initialized.
    ///
    /// This is the main constructor for the tracker. It initializes:
    /// - Database connection (SQLite, MySQL, or PostgreSQL)
    /// - Optional cache connection (Redis or Memcache)
    /// - SSL certificate store
    /// - Sharded torrent storage (256 shards)
    /// - Statistics counters
    /// - Update queues for batched database writes
    ///
    /// # Arguments
    ///
    /// * `config` - Shared configuration containing all tracker settings
    /// * `create_database` - If true, creates database tables if they don't exist
    ///
    /// # Returns
    ///
    /// A fully initialized `TorrentTracker` instance ready to handle requests.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// use std::sync::Arc;
    /// use torrust_actix::config::structs::configuration::Configuration;
    /// use torrust_actix::tracker::structs::torrent_tracker::TorrentTracker;
    ///
    /// let config = Arc::new(Configuration::default());
    /// let tracker = TorrentTracker::new(config, true).await;
    /// ```
    #[tracing::instrument(level = "debug")]
    pub async fn new(config: Arc<Configuration>, create_database: bool) -> TorrentTracker
    {
        let tracker_config = &config.tracker_config;
        let cache = if let Some(ref cache_config) = config.cache {
            if cache_config.enabled {
                match CacheConnector::new(cache_config).await {
                    Ok(connector) => {
                        info!("[Cache] Successfully connected to {} cache", match cache_config.engine {
                            crate::cache::enums::cache_engine::CacheEngine::redis => "Redis",
                            crate::cache::enums::cache_engine::CacheEngine::memcache => "Memcache",
                        });
                        Some(connector)
                    }
                    Err(e) => {
                        warn!("[Cache] Failed to connect to cache: {}. Continuing without cache.", e);
                        None
                    }
                }
            } else {
                info!("[Cache] Cache is disabled in configuration");
                None
            }
        } else {
            None
        };
        TorrentTracker {
            config: config.clone(),
            cache,
            certificate_store: Arc::new(CertificateStore::new()),
            torrents_sharding: Arc::new(Default::default()),
            torrents_updates: Arc::new(RwLock::new(HashMap::new())),
            torrents_whitelist: Arc::new(RwLock::new(HashSet::new())),
            torrents_whitelist_updates: Arc::new(RwLock::new(HashMap::new())),
            torrents_blacklist: Arc::new(RwLock::new(HashSet::new())),
            torrents_blacklist_updates: Arc::new(RwLock::new(HashMap::new())),
            keys: Arc::new(RwLock::new(BTreeMap::new())),
            keys_updates: Arc::new(RwLock::new(HashMap::new())),
            stats: Arc::new(StatsAtomics {
                started: AtomicI64::new(Utc::now().timestamp()),
                timestamp_run_save: AtomicI64::new(0),
                timestamp_run_timeout: AtomicI64::new(0),
                timestamp_run_console: AtomicI64::new(0),
                timestamp_run_keys_timeout: AtomicI64::new(0),
                torrents: AtomicI64::new(0),
                torrents_updates: AtomicI64::new(0),
                users: AtomicI64::new(0),
                users_updates: AtomicI64::new(0),
                seeds: AtomicI64::new(0),
                peers: AtomicI64::new(0),
                completed: AtomicI64::new(0),
                whitelist_enabled: AtomicBool::new(tracker_config.whitelist_enabled),
                whitelist: AtomicI64::new(0),
                whitelist_updates: AtomicI64::new(0),
                blacklist_enabled: AtomicBool::new(tracker_config.blacklist_enabled),
                blacklist: AtomicI64::new(0),
                blacklist_updates: AtomicI64::new(0),
                keys_enabled: AtomicBool::new(tracker_config.keys_enabled),
                keys: AtomicI64::new(0),
                keys_updates: AtomicI64::new(0),
                tcp4_connections_handled: AtomicI64::new(0),
                tcp4_api_handled: AtomicI64::new(0),
                tcp4_announces_handled: AtomicI64::new(0),
                tcp4_scrapes_handled: AtomicI64::new(0),
                tcp4_not_found: AtomicI64::new(0),
                tcp4_failure: AtomicI64::new(0),
                tcp6_connections_handled: AtomicI64::new(0),
                tcp6_api_handled: AtomicI64::new(0),
                tcp6_announces_handled: AtomicI64::new(0),
                tcp6_scrapes_handled: AtomicI64::new(0),
                tcp6_not_found: AtomicI64::new(0),
                tcp6_failure: AtomicI64::new(0),
                udp4_invalid_request: AtomicI64::new(0),
                udp4_bad_request: AtomicI64::new(0),
                udp4_connections_handled: AtomicI64::new(0),
                udp4_announces_handled: AtomicI64::new(0),
                udp4_scrapes_handled: AtomicI64::new(0),
                udp6_invalid_request: AtomicI64::new(0),
                udp6_bad_request: AtomicI64::new(0),
                udp6_connections_handled: AtomicI64::new(0),
                udp6_announces_handled: AtomicI64::new(0),
                udp6_scrapes_handled: AtomicI64::new(0),
                udp_queue_len: AtomicI64::new(0),
                ws_connections_active: AtomicI64::new(0),
                ws_requests_sent: AtomicI64::new(0),
                ws_requests_received: AtomicI64::new(0),
                ws_responses_sent: AtomicI64::new(0),
                ws_responses_received: AtomicI64::new(0),
                ws_timeouts: AtomicI64::new(0),
                ws_reconnects: AtomicI64::new(0),
                ws_auth_success: AtomicI64::new(0),
                ws_auth_failed: AtomicI64::new(0),
            }),
            users: Arc::new(RwLock::new(BTreeMap::new())),
            users_updates: Arc::new(RwLock::new(HashMap::new())),
            sqlx: DatabaseConnector::new(config.clone(), create_database).await,
        }
    }
}