Skip to content

Commit 5c36968

Browse files
committedJul 24, 2024·
feat: small refactor of the Downloader
1 parent 58e15e0 commit 5c36968

File tree

11 files changed

+102
-162
lines changed

11 files changed

+102
-162
lines changed
 

‎crates/client/src/download.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::{path::PathBuf, sync::Arc};
22

3-
use anyhow::{anyhow, Context};
3+
use anyhow::anyhow;
44
use egui_task_manager::TaskProgressShared;
55
use nomi_core::{
66
configs::profile::{Loader, ProfileState},
77
downloads::{
88
progress::MappedSender,
9-
traits::{DownloadResult, Downloader, DownloaderIO, DownloaderIOExt},
9+
traits::{DownloadResult, Downloader},
1010
AssetsDownloader, DownloadQueue,
1111
},
1212
game_paths::GamePaths,
@@ -76,10 +76,13 @@ async fn try_download_version(profile: Arc<RwLock<ModdedProfile>>, progress_shar
7676
let launch_instance = instance.launch_instance(settings, Some(vec!["-Xms2G".to_string(), "-Xmx4G".to_string()]));
7777

7878
let instance = instance.instance();
79-
instance.get_io_dyn().io().await?;
79+
80+
let io = instance.io();
8081

8182
let downloader: Box<dyn Downloader<Data = DownloadResult>> = instance.into_downloader();
8283

84+
io.await?;
85+
8386
let downloader = DownloadQueue::new().with_downloader_dyn(downloader);
8487

8588
let _ = progress_shared.set_total(downloader.total());
@@ -112,13 +115,15 @@ async fn try_assets(version: String, assets_dir: PathBuf, progress_shared: TaskP
112115
)
113116
.await?;
114117

115-
downloader.get_io().io().await.context("`io` error")?;
118+
let io = downloader.io();
116119

117120
let _ = progress_shared.set_total(downloader.total());
118121

119122
let mapped_sender = MappedSender::new_progress_mapper(Box::new(progress_shared.sender()));
120123

121124
Box::new(downloader).download(&mapped_sender).await;
122125

126+
io.await?;
127+
123128
Ok(())
124129
}

‎crates/client/src/states.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@ use std::{collections::HashSet, path::PathBuf};
22

33
use egui_task_manager::{Caller, Task, TaskManager};
44
use nomi_core::{
5-
downloads::{
6-
java::JavaDownloader,
7-
progress::MappedSender,
8-
traits::{Downloader, DownloaderIO, DownloaderIOExt},
9-
},
5+
downloads::{java::JavaDownloader, progress::MappedSender, traits::Downloader},
106
fs::read_toml_config_sync,
117
DOT_NOMI_JAVA_DIR, DOT_NOMI_JAVA_EXECUTABLE, DOT_NOMI_PROFILES_CONFIG, DOT_NOMI_SETTINGS_CONFIG,
128
};
@@ -88,14 +84,15 @@ impl JavaState {
8884

8985
let _ = progress.set_total(downloader.total());
9086

91-
let io = downloader.get_io();
87+
let io = downloader.io();
9288

9389
let mapped_sender = MappedSender::new_progress_mapper(Box::new(progress.sender()));
9490

9591
Box::new(downloader).download(&mapped_sender).await;
9692

97-
io.io().await.report_error();
93+
io.await.report_error();
9894
});
95+
9996
let task = Task::new("Java downloading", caller);
10097
manager.push_task::<JavaCollection>(task);
10198
}

‎crates/nomi-core/src/downloads/downloaders/assets.rs

+16-28
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ use crate::{
1111
downloaders::file::FileDownloader,
1212
progress::ProgressSender,
1313
set::DownloadSet,
14-
traits::{DownloadResult, Downloadable, Downloader, DownloaderIO, DownloaderIOExt},
14+
traits::{DownloadResult, Downloadable, Downloader},
1515
},
1616
fs::write_json_config,
17+
PinnedFutureWithBounds,
1718
};
1819

1920
use super::DownloadQueue;
2021

21-
#[derive(Serialize, Deserialize, Debug)]
22+
#[derive(Serialize, Deserialize, Debug, Clone)]
2223
pub struct Assets {
2324
pub objects: HashMap<String, AssetInformation>,
2425
}
@@ -113,32 +114,6 @@ impl AssetsDownloader {
113114
}
114115
}
115116

116-
impl<'a> DownloaderIOExt<'a> for AssetsDownloader {
117-
type IO = AssetsDownloaderIo<'a>;
118-
119-
fn get_io(&'a self) -> AssetsDownloaderIo<'a> {
120-
AssetsDownloaderIo {
121-
assets: &self.assets,
122-
indexes: self.indexes.clone(),
123-
id: self.id.clone(),
124-
}
125-
}
126-
}
127-
128-
pub struct AssetsDownloaderIo<'a> {
129-
assets: &'a Assets,
130-
indexes: PathBuf,
131-
id: String,
132-
}
133-
134-
#[async_trait::async_trait]
135-
impl DownloaderIO for AssetsDownloaderIo<'_> {
136-
async fn io(&self) -> anyhow::Result<()> {
137-
let path = self.indexes.join(format!("{}.json", self.id));
138-
write_json_config(&self.assets, path).await
139-
}
140-
}
141-
142117
#[async_trait::async_trait]
143118
impl Downloader for AssetsDownloader {
144119
type Data = DownloadResult;
@@ -151,4 +126,17 @@ impl Downloader for AssetsDownloader {
151126
async fn download(self: Box<Self>, sender: &dyn ProgressSender<Self::Data>) {
152127
Box::new(self.queue).download(sender).await;
153128
}
129+
130+
fn io(&self) -> PinnedFutureWithBounds<anyhow::Result<()>> {
131+
let id = self.id.clone();
132+
let indexes = self.indexes.clone();
133+
let assets = self.assets.clone();
134+
135+
let fut = async move {
136+
let path = indexes.join(format!("{id}.json"));
137+
write_json_config(&assets, path).await
138+
};
139+
140+
Box::pin(fut)
141+
}
154142
}

‎crates/nomi-core/src/downloads/downloaders/java.rs

+20-31
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::{
55
use thiserror::Error;
66
use tracing::error;
77

8-
use crate::{downloads::progress::ProgressSender, DOT_NOMI_TEMP_DIR};
8+
use crate::{downloads::progress::ProgressSender, PinnedFutureWithBounds, DOT_NOMI_TEMP_DIR};
99

1010
use super::{
11-
super::traits::{DownloadResult, Downloader, DownloaderIO, DownloaderIOExt},
11+
super::traits::{DownloadResult, Downloader},
1212
FileDownloader,
1313
};
1414

@@ -85,20 +85,27 @@ impl Downloader for JavaDownloader {
8585

8686
Box::new(downloader).download(sender).await;
8787
}
88-
}
8988

90-
impl<'a> DownloaderIOExt<'a> for JavaDownloader {
91-
type IO = JavaDownloaderIO;
89+
fn io(&self) -> PinnedFutureWithBounds<anyhow::Result<()>> {
90+
let target_directory = self.target_directory.clone();
9291

93-
fn get_io(&'a self) -> Self::IO {
94-
JavaDownloaderIO {
95-
target_directory: self.target_directory.clone(),
96-
}
97-
}
98-
}
92+
let fut = async move {
93+
let path = PathBuf::from(DOT_NOMI_TEMP_DIR).join(consts::ARCHIVE_FILENAME);
94+
if !check_hash(path.clone(), consts::SHA256)? {
95+
return Err(JavaDownloaderError::HashDoesNotMatch.into());
96+
}
9997

100-
pub struct JavaDownloaderIO {
101-
target_directory: PathBuf,
98+
let file = File::open(&path)?;
99+
100+
extract(file, &target_directory)?;
101+
102+
tokio::fs::remove_file(&path).await?;
103+
104+
Ok(())
105+
};
106+
107+
Box::pin(fut)
108+
}
102109
}
103110

104111
#[cfg(target_os = "windows")]
@@ -117,24 +124,6 @@ fn extract(archive: std::fs::File, target_path: &Path) -> anyhow::Result<()> {
117124
archive.unpack(target_path).map_err(Into::into)
118125
}
119126

120-
#[async_trait::async_trait]
121-
impl DownloaderIO for JavaDownloaderIO {
122-
async fn io(&self) -> anyhow::Result<()> {
123-
let path = PathBuf::from(DOT_NOMI_TEMP_DIR).join(consts::ARCHIVE_FILENAME);
124-
if !check_hash(path.clone(), consts::SHA256)? {
125-
return Err(JavaDownloaderError::HashDoesNotMatch.into());
126-
}
127-
128-
let file = File::open(&path)?;
129-
130-
extract(file, &self.target_directory)?;
131-
132-
tokio::fs::remove_file(&path).await?;
133-
134-
Ok(())
135-
}
136-
}
137-
138127
#[derive(Error, Debug)]
139128
enum JavaDownloaderError {
140129
#[error("Hash does not match")]

‎crates/nomi-core/src/downloads/traits.rs

+9-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use egui_task_manager::Progress;
22

3-
use super::{downloaders::assets::AssetsDownloaderIo, progress::ProgressSender, DownloadError};
3+
use crate::PinnedFutureWithBounds;
4+
5+
use super::{progress::ProgressSender, DownloadError};
46

57
#[derive(Debug, Clone)]
68
pub struct DownloadResult(pub Result<DownloadStatus, DownloadError>);
@@ -41,7 +43,13 @@ pub trait Downloader: Send + Sync {
4143

4244
/// Returns the number of items to download
4345
fn total(&self) -> u32;
46+
4447
async fn download(self: Box<Self>, sender: &dyn ProgressSender<Self::Data>);
48+
49+
/// This method must return a pinned future that does not borrow any values from `Self`
50+
fn io(&self) -> PinnedFutureWithBounds<anyhow::Result<()>> {
51+
Box::pin(async { Ok(()) })
52+
}
4553
}
4654

4755
const _: Option<Box<dyn Downloader<Data = DownloadResult>>> = None;
@@ -62,31 +70,3 @@ where
6270
sender.update(result).await;
6371
}
6472
}
65-
66-
#[async_trait::async_trait]
67-
pub trait DownloaderIO {
68-
async fn io(&self) -> anyhow::Result<()>;
69-
}
70-
71-
const _: Option<Box<dyn DownloaderIO>> = None;
72-
73-
pub trait DownloaderIOExt<'a> {
74-
type IO: DownloaderIO;
75-
76-
fn get_io(&'a self) -> Self::IO;
77-
}
78-
79-
const _: Option<Box<dyn DownloaderIOExt<'_, IO = AssetsDownloaderIo<'_>>>> = None;
80-
81-
pub trait ObjectSafeDownloaderIOExt<'a> {
82-
fn get_io_dyn(&'a self) -> Box<dyn DownloaderIO + Send + 'a>;
83-
}
84-
85-
impl<'a, T: DownloaderIOExt<'a>> ObjectSafeDownloaderIOExt<'a> for T
86-
where
87-
T::IO: Send,
88-
{
89-
fn get_io_dyn(&'a self) -> Box<dyn DownloaderIO + Send + 'a> {
90-
Box::new(self.get_io())
91-
}
92-
}

‎crates/nomi-core/src/instance/version_marker.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
use std::fmt::Debug;
22

3-
use crate::downloads::traits::{DownloadResult, Downloader, ObjectSafeDownloaderIOExt};
3+
use crate::downloads::traits::{DownloadResult, Downloader};
44

55
use super::builder_ext::LaunchInstanceBuilderExt;
66

7-
pub trait Version:
8-
LaunchInstanceBuilderExt + Downloader<Data = DownloadResult> + for<'a> ObjectSafeDownloaderIOExt<'a> + Debug + Send + Sync
9-
{
7+
pub trait Version: LaunchInstanceBuilderExt + Downloader<Data = DownloadResult> + Debug + Send + Sync {
108
fn into_downloader(self: Box<Self>) -> Box<dyn Downloader<Data = DownloadResult>>;
119
}
1210

1311
impl<T> Version for T
1412
where
15-
T: LaunchInstanceBuilderExt + Downloader<Data = DownloadResult> + for<'a> ObjectSafeDownloaderIOExt<'a> + Debug + Send + Sync + 'static,
13+
T: LaunchInstanceBuilderExt + Downloader<Data = DownloadResult> + Debug + Send + Sync + 'static,
1614
{
1715
fn into_downloader(self: Box<Self>) -> Box<dyn Downloader<Data = DownloadResult>> {
1816
self

‎crates/nomi-core/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ pub mod state;
1919

2020
pub mod consts;
2121

22+
use std::{future::Future, pin::Pin};
23+
2224
pub use consts::*;
2325

2426
pub use regex;
2527
use sha1::Digest;
2628
pub use uuid::Uuid;
2729

30+
type PinnedFutureWithBounds<T> = Pin<Box<dyn Future<Output = T> + Send>>;
31+
2832
pub fn calculate_sha1(data: impl AsRef<[u8]>) -> String {
2933
let value = sha1::Sha1::digest(data);
3034
base16ct::lower::encode_string(&value)

‎crates/nomi-core/src/loaders/fabric.rs

+16-27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::path::{Path, PathBuf};
1+
use std::path::PathBuf;
22

33
use itertools::Itertools;
44
use reqwest::Client;
@@ -11,7 +11,7 @@ use crate::{
1111
libraries::{LibrariesDownloader, LibrariesMapper},
1212
},
1313
progress::ProgressSender,
14-
traits::{DownloadResult, Downloader, DownloaderIO, DownloaderIOExt},
14+
traits::{DownloadResult, Downloader},
1515
},
1616
fs::write_to_file,
1717
game_paths::GamePaths,
@@ -24,6 +24,7 @@ use crate::{
2424
simple_lib::SimpleLib,
2525
},
2626
state::get_launcher_manifest,
27+
PinnedFutureWithBounds,
2728
};
2829

2930
#[derive(Debug)]
@@ -105,23 +106,6 @@ impl Fabric {
105106
}
106107
}
107108

108-
#[allow(clippy::module_name_repetitions)]
109-
pub struct FabricIO<'a> {
110-
profile: &'a FabricProfile,
111-
version_path: &'a Path,
112-
}
113-
114-
#[async_trait::async_trait]
115-
impl<'a> DownloaderIO for FabricIO<'a> {
116-
async fn io(&self) -> anyhow::Result<()> {
117-
let path = self.version_path.join(format!("{}.json", self.profile.id));
118-
119-
let body = serde_json::to_string_pretty(&self.profile)?;
120-
121-
write_to_file(body.as_bytes(), &path).await
122-
}
123-
}
124-
125109
struct FabricLibrariesMapper {
126110
libraries: PathBuf,
127111
}
@@ -146,15 +130,20 @@ impl Downloader for Fabric {
146130
async fn download(self: Box<Self>, sender: &dyn ProgressSender<Self::Data>) {
147131
Box::new(self.libraries_downloader).download(sender).await;
148132
}
149-
}
150133

151-
impl<'a> DownloaderIOExt<'a> for Fabric {
152-
type IO = FabricIO<'a>;
134+
fn io(&self) -> PinnedFutureWithBounds<anyhow::Result<()>> {
135+
let version_path = self.game_paths.version.clone();
136+
let profile = self.profile.clone();
137+
let id = self.profile.id.clone();
153138

154-
fn get_io(&'a self) -> FabricIO<'a> {
155-
FabricIO {
156-
profile: &self.profile,
157-
version_path: &self.game_paths.version,
158-
}
139+
let fut = async move {
140+
let path = version_path.join(format!("{id}.json"));
141+
142+
let body = serde_json::to_string_pretty(&profile)?;
143+
144+
write_to_file(body.as_bytes(), &path).await
145+
};
146+
147+
Box::pin(fut)
159148
}
160149
}

‎crates/nomi-core/src/loaders/vanilla.rs

+15-26
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ use crate::{
1111
libraries::{LibrariesDownloader, LibrariesMapper},
1212
},
1313
progress::ProgressSender,
14-
traits::{DownloadResult, Downloader, DownloaderIO, DownloaderIOExt},
14+
traits::{DownloadResult, Downloader},
1515
DownloadQueue,
1616
},
1717
fs::write_to_file,
1818
game_paths::GamePaths,
1919
repository::manifest::{Classifiers, DownloadFile, Library, Manifest},
2020
state::get_launcher_manifest,
21+
PinnedFutureWithBounds,
2122
};
2223

2324
#[derive(Debug)]
@@ -108,23 +109,6 @@ impl LibrariesMapper<Library> for VanillaNativeLibrariesMapper<'_> {
108109
}
109110
}
110111

111-
#[allow(clippy::module_name_repetitions)]
112-
pub struct VanillaIO<'a> {
113-
manifest: &'a Manifest,
114-
version_path: &'a Path,
115-
}
116-
117-
#[async_trait::async_trait]
118-
impl DownloaderIO for VanillaIO<'_> {
119-
async fn io(&self) -> anyhow::Result<()> {
120-
let path = self.version_path.join(format!("{}.json", self.manifest.id));
121-
122-
let body = serde_json::to_string_pretty(&self.manifest)?;
123-
124-
write_to_file(body.as_bytes(), &path).await
125-
}
126-
}
127-
128112
#[async_trait::async_trait]
129113
impl Downloader for Vanilla {
130114
type Data = DownloadResult;
@@ -136,15 +120,20 @@ impl Downloader for Vanilla {
136120
async fn download(self: Box<Self>, sender: &dyn ProgressSender<Self::Data>) {
137121
Box::new(self.queue).download(sender).await;
138122
}
139-
}
140123

141-
impl<'a> DownloaderIOExt<'a> for Vanilla {
142-
type IO = VanillaIO<'a>;
124+
fn io(&self) -> PinnedFutureWithBounds<anyhow::Result<()>> {
125+
let versions_path = self.game_paths.version.clone();
126+
let manifest_id = self.manifest.id.clone();
127+
let manifest_res = serde_json::to_string_pretty(&self.manifest);
143128

144-
fn get_io(&'a self) -> VanillaIO<'a> {
145-
VanillaIO {
146-
manifest: &self.manifest,
147-
version_path: &self.game_paths.version,
148-
}
129+
let fut = async move {
130+
let path = versions_path.join(format!("{manifest_id}.json"));
131+
132+
let body = manifest_res?;
133+
134+
write_to_file(body.as_bytes(), &path).await
135+
};
136+
137+
Box::pin(fut)
149138
}
150139
}

‎crates/nomi-core/tests/download_test.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@ async fn download_test() {
2525
Box::new(instance.assets().await.unwrap()).download(&tx).await;
2626

2727
let version = instance.instance();
28-
{
29-
let io = version.get_io_dyn();
30-
io.io().await.unwrap();
31-
}
3228

29+
let fut = version.io();
3330
version.download(&tx).await;
31+
32+
fut.await.unwrap();
3433
}

‎crates/nomi-core/tests/full_fabric_test.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ async fn full_fabric_test() {
5252
Box::new(instance.assets().await.unwrap()).download(&tx).await;
5353

5454
let instance = instance.instance();
55-
instance.get_io_dyn().io().await.unwrap();
55+
let ui_fut = instance.io();
5656

5757
instance.download(&tx).await;
5858

59+
ui_fut.await.unwrap();
60+
5961
let profile = VersionProfile::builder()
6062
.id(1)
6163
.name("Full-fabric-test".into())

0 commit comments

Comments
 (0)
Please sign in to comment.