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
//! It imports statistics for all torrents from the linked tracker.
//!
//! It imports the number of seeders and leechers for all torrents from the
//! associated tracker.
//!
//! You can execute it with: `cargo run --bin import_tracker_statistics`.
//!
//! After running it you will see the following output:
//!
//! ```text
//! Importing statistics from linked tracker ...
//! Loading configuration from config file `./config.toml`
//! Tracker url: udp://localhost:6969
//! ```
//!
//! Statistics are also imported:
//!
//! - Periodically by the importer job. The importer job is executed every hour
//! by default. See [`TrackerStatisticsImporter`](crate::config::TrackerStatisticsImporter)
//! for more details.
//! - When a new torrent is added.
//! - When the API returns data about a torrent statistics are collected from
//! the tracker in real time.
use std::env;
use std::sync::Arc;

use derive_more::{Display, Error};
use text_colorizer::Colorize;

use crate::bootstrap::config::init_configuration;
use crate::bootstrap::logging;
use crate::databases::database;
use crate::tracker::service::Service;
use crate::tracker::statistics_importer::StatisticsImporter;

const NUMBER_OF_ARGUMENTS: usize = 0;

#[derive(Debug, Display, PartialEq, Error)]
#[allow(dead_code)]
pub enum ImportError {
    #[display(fmt = "internal server error")]
    WrongNumberOfArgumentsError,
}

fn parse_args() -> Result<(), ImportError> {
    let args: Vec<String> = env::args().skip(1).collect();

    if args.len() != NUMBER_OF_ARGUMENTS {
        eprintln!(
            "{} wrong number of arguments: expected {}, got {}",
            "Error".red().bold(),
            NUMBER_OF_ARGUMENTS,
            args.len()
        );
        print_usage();
        return Err(ImportError::WrongNumberOfArgumentsError);
    }

    Ok(())
}

fn print_usage() {
    eprintln!(
        "{} - imports torrents statistics from linked tracker.

        cargo run --bin import_tracker_statistics

        ",
        "Tracker Statistics Importer".green()
    );
}

pub async fn run_importer() {
    parse_args().expect("unable to parse command arguments");
    import().await;
}

/// Import Command Arguments
///
/// # Panics
///
/// Panics if `Configuration::load_from_file` has any error.
pub async fn import() {
    println!("Importing statistics from linked tracker ...");

    let configuration = init_configuration().await;

    let log_level = configuration.settings.read().await.log_level.clone();

    logging::setup(&log_level);

    let cfg = Arc::new(configuration);

    let settings = cfg.settings.read().await;

    let tracker_url = settings.tracker.url.clone();

    eprintln!("Tracker url: {}", tracker_url.green());

    let database = Arc::new(
        database::connect(&settings.database.connect_url)
            .await
            .expect("unable to connect to db"),
    );

    let tracker_service = Arc::new(Service::new(cfg.clone(), database.clone()).await);
    let tracker_statistics_importer =
        Arc::new(StatisticsImporter::new(cfg.clone(), tracker_service.clone(), database.clone()).await);

    tracker_statistics_importer
        .import_all_torrents_statistics()
        .await
        .expect("should import all torrents statistics");
}