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
use crate::error::InstallationResult;
use crate::minecraft::InstallOptions;
use crate::minecraft::InstallationUpdate;
use crate::utils::{download, download_progress_channel, Download, DownloadProgress};
use futures::join;
use tokio::sync::mpsc::{Receiver, Sender};

/// Installs the log config file.
///
/// This function provides updates during installation.
#[instrument(
    name = "install_log_config",
    level = "trace",
    skip_all,
    fields(
        version = &options.version_data.id,
        log_configs_path = %options.log_configs_path.display(),
        parallel_downloads = options.parallel_downloads,
        download_retries = options.download_retries,
        verify_downloads = options.verify_downloads,
    )
)]
pub async fn install_log_config(
    options: &InstallOptions,
    update_sender: Sender<InstallationUpdate>,
) -> InstallationResult<()> {
    let logging_info = match &options.version_data.logging {
        Some(info) => info,
        None => {
            debug!("The version data does not contain logging information. Skipping download.");
            return Ok(());
        }
    };

    trace!("Building download for log config");
    let mut config_path = options.log_configs_path.clone();
    config_path.push(
        logging_info
            .client
            .file
            .id
            .as_ref()
            .expect("Logging Info has no ID"),
    );
    let sha1 = hex::decode(&logging_info.client.file.sha1)?;
    let downloads = vec![Download {
        url: logging_info.client.file.url.clone(),
        file: config_path,
        sha1: Some(sha1),
    }];

    trace!("Preparing futures for downloading and channel translation");
    let (tx, rx) = download_progress_channel(500);
    let download_future = download(
        downloads,
        Some(tx),
        options.parallel_downloads,
        options.download_retries,
        options.verify_downloads,
    );
    let map_future = map_progress(update_sender.clone(), rx);

    trace!("Starting downloads");
    join!(download_future, map_future).0?;

    Ok(())
}

async fn map_progress(
    sender: Sender<InstallationUpdate>,
    mut receiver: Receiver<DownloadProgress>,
) {
    while let Some(p) = receiver.recv().await {
        let send_result = sender
            .send(InstallationUpdate::LogConfig(
                LogConfigInstallationUpdate::Downloading(p),
            ))
            .await;

        if send_result.is_err() {
            debug!("Failed to translate DownloadProgress to InstallationUpdate");
            break;
        }
    }
}

/// Update of log config installation
#[derive(Clone, Debug)]
pub enum LogConfigInstallationUpdate {
    /// Download status
    Downloading(DownloadProgress),
}