cobble_core/minecraft/install/
client.rs

1use crate::error::InstallationResult;
2use crate::minecraft::InstallOptions;
3use crate::minecraft::InstallationUpdate;
4use crate::utils::{download, download_progress_channel, Download, DownloadProgress};
5use futures::join;
6use tokio::sync::mpsc::{Receiver, Sender};
7
8/// Installs the client file.
9///
10/// This function provides updates during installation.
11#[instrument(
12    name = "install_client",
13    level = "trace",
14    skip_all,
15    fields(
16        version = &options.version_data.id,
17        minecraft_path = %options.minecraft_path.display(),
18        parallel_downloads = options.parallel_downloads,
19        download_retries = options.download_retries,
20        verify_downloads = options.verify_downloads,
21    )
22)]
23pub async fn install_client(
24    options: &InstallOptions,
25    update_sender: Sender<InstallationUpdate>,
26) -> InstallationResult<()> {
27    let downloads = match &options.version_data.downloads {
28        Some(downloads) => downloads,
29        None => {
30            debug!("The version data does not contain download information. Skipping download.");
31            return Ok(());
32        }
33    };
34
35    trace!("Building download for client");
36    let mut minecraft_path = options.minecraft_path.clone();
37    minecraft_path.push("bin");
38    minecraft_path.push(format!("minecraft-{}-client.jar", &options.version_data.id));
39
40    let sha1 = hex::decode(&downloads.client.sha1)?;
41    let downloads = vec![Download {
42        url: downloads.client.url.clone(),
43        file: minecraft_path,
44        sha1: Some(sha1),
45    }];
46
47    trace!("Preparing futures for downloading and channel translation");
48    let (tx, rx) = download_progress_channel(500);
49    let download_future = download(
50        downloads,
51        Some(tx),
52        options.parallel_downloads,
53        options.download_retries,
54        options.verify_downloads,
55    );
56    let map_future = map_progress(update_sender.clone(), rx);
57
58    trace!("Starting downloads");
59    join!(download_future, map_future).0?;
60
61    Ok(())
62}
63
64async fn map_progress(
65    sender: Sender<InstallationUpdate>,
66    mut receiver: Receiver<DownloadProgress>,
67) {
68    while let Some(p) = receiver.recv().await {
69        let send_result = sender
70            .send(InstallationUpdate::Client(
71                ClientInstallationUpdate::Downloading(p),
72            ))
73            .await;
74
75        if send_result.is_err() {
76            debug!("Failed to translate DownloadProgress to InstallationUpdate");
77            break;
78        }
79    }
80}
81
82/// Update of client installation
83#[derive(Clone, Debug)]
84pub enum ClientInstallationUpdate {
85    /// Download status
86    Downloading(DownloadProgress),
87}