Skip to content

Commit

Permalink
Merge pull request #68 from Umatriz/downloaders_refactor
Browse files Browse the repository at this point in the history
Forge support
  • Loading branch information
Umatriz authored Aug 8, 2024
2 parents fbd4248 + d37e48f commit a1f50f9
Show file tree
Hide file tree
Showing 23 changed files with 1,343 additions and 103 deletions.
17 changes: 9 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion crates/client/src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ use nomi_core::{
},
game_paths::GamePaths,
instance::{launch::LaunchSettings, Instance},
loaders::{fabric::Fabric, vanilla::Vanilla},
loaders::{
fabric::Fabric,
forge::{Forge, ForgeVersion},
vanilla::Vanilla,
},
repository::java_runner::JavaRunner,
state::get_launcher_manifest,
};
Expand Down Expand Up @@ -58,6 +62,9 @@ async fn try_download_version(profile: Arc<RwLock<ModdedProfile>>, progress_shar
Loader::Fabric { version } => builder.instance(Box::new(
Fabric::new(version_profile.version(), version.as_ref(), game_paths.clone()).await?,
)),
Loader::Forge => builder.instance(Box::new(
Forge::new(version_profile.version(), ForgeVersion::Recommended, game_paths.clone()).await?,
)),
}
.build();

Expand Down
26 changes: 26 additions & 0 deletions crates/client/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,29 @@ where
let _ = tx.send(data);
})
}

// Helper function to center arbitrary widgets. It works by measuring the width of the widgets after rendering, and
// then using that offset on the next frame.
pub fn centerer(ui: &mut eframe::egui::Ui, add_contents: impl FnOnce(&mut eframe::egui::Ui)) {
ui.horizontal(|ui| {
let id = ui.id().with("_centerer");
let last_width: Option<f32> = ui.memory_mut(|mem| mem.data.get_temp(id));
if let Some(last_width) = last_width {
ui.add_space((ui.available_width() - last_width) / 2.0);
}
let res = ui
.scope(|ui| {
add_contents(ui);
})
.response;
let width = res.rect.width();
ui.memory_mut(|mem| mem.data.insert_temp(id, width));

// Repaint if width changed
match last_width {
None => ui.ctx().request_repaint(),
Some(last_width) if last_width != width => ui.ctx().request_repaint(),
Some(_) => {}
}
});
}
3 changes: 3 additions & 0 deletions crates/nomi-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ repository = "https://github.com/Umatriz/nomi"
tokio.workspace = true
tokio-stream.workspace = true
tokio-util.workspace = true

anyhow.workspace = true

serde.workspace = true
serde_json.workspace = true
serde_path_to_error.workspace = true
toml.workspace = true

tracing.workspace = true
Expand Down
6 changes: 6 additions & 0 deletions crates/nomi-core/src/configs/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ pub enum Loader {
Fabric {
version: Option<String>,
},
Forge,
}

impl Display for Loader {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Loader::Vanilla => f.write_str("Vanilla"),
Loader::Fabric { .. } => f.write_str("Fabric"),
Loader::Forge => f.write_str("Forge"),
}
}
}
Expand All @@ -35,6 +37,10 @@ impl Loader {
matches!(*self, Self::Fabric { .. })
}

pub fn is_forge(&self) -> bool {
matches!(*self, Self::Fabric { .. })
}

pub fn is_vanilla(&self) -> bool {
matches!(*self, Self::Vanilla)
}
Expand Down
3 changes: 3 additions & 0 deletions crates/nomi-core/src/downloads/downloaders/libraries.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use itertools::Itertools;
use tracing::debug;

use crate::downloads::{
progress::ProgressSender,
Expand Down Expand Up @@ -48,5 +49,7 @@ impl Downloader for LibrariesDownloader {
}

Box::new(download_set).download(sender).await;

debug!("Finished downloading libraries");
}
}
126 changes: 84 additions & 42 deletions crates/nomi-core/src/downloads/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
pub use downloaders::*;

use std::path::{Path, PathBuf};
use std::{
future::IntoFuture,
path::{Path, PathBuf},
};

use futures_util::stream::StreamExt;
use reqwest::Client;
use reqwest::{Client, RequestBuilder, Response};
use tokio::io::AsyncWriteExt;
use tracing::{error, trace};

use crate::PinnedFutureWithBounds;

pub mod downloaders;
pub mod progress;
pub mod traits;
Expand All @@ -31,57 +36,94 @@ pub enum DownloadError {
AllIterationsFailed,
}

pub(crate) async fn download_file(path: impl AsRef<Path>, url: impl Into<String>) -> Result<(), DownloadError> {
pub(crate) fn download_file(path: impl AsRef<Path>, url: impl Into<String>) -> Downloader {
let url = url.into();
let path = path.as_ref();
let path = path.as_ref().to_path_buf();

if let Some(path) = path.parent() {
tokio::fs::create_dir_all(path).await.map_err(|err| DownloadError::Error {
url: url.clone(),
path: path.to_path_buf(),
error: err.to_string(),
})?;
Downloader {
url,
path,
client: None,
request_injection: Box::new(|r| r),
}
}

let client = Client::new();
let res = client.get(&url).send().await.map_err(|err| DownloadError::Error {
url: url.clone(),
path: path.to_path_buf(),
error: err.to_string(),
})?;

let mut file = tokio::fs::File::create(path).await.map_err(|err| {
error!("Error occurred during file creating\nPath: {}\nError: {}", path.to_string_lossy(), err);
DownloadError::Error {
url: url.clone(),
path: path.to_path_buf(),
error: err.to_string(),
}
})?;
pub struct Downloader {
url: String,
path: PathBuf,
client: Option<Client>,
request_injection: Box<dyn FnOnce(RequestBuilder) -> RequestBuilder + Send>,
}

let mut stream = res.bytes_stream();
impl Downloader {
#[must_use]
pub fn with_client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}

while let Some(item) = stream.next().await {
let chunk = item.map_err(|err| {
error!("Error occurred during file downloading\nError: {}", err);
DownloadError::Error {
url: url.clone(),
path: path.to_path_buf(),
error: err.to_string(),
}
})?;
#[must_use]
pub fn with_request_injection(mut self, injection: impl FnOnce(RequestBuilder) -> RequestBuilder + Send + 'static) -> Self {
self.request_injection = Box::new(injection);
self
}

file.write_all(&chunk).await.map_err(|err| {
error!("Error occurred during writing to file\nError: {}", err);
async fn download(self) -> Result<(), DownloadError> {
let download_error = |error| -> DownloadError {
DownloadError::Error {
url: url.clone(),
path: path.to_path_buf(),
error: err.to_string(),
url: self.url.clone(),
path: self.path.clone(),
error,
}
};

if let Some(path) = self.path.parent() {
tokio::fs::create_dir_all(path).await.map_err(|err| download_error(err.to_string()))?;
}

let client = self.client.unwrap_or_default();
let request = (self.request_injection)(client.get(&self.url));
let res = request
.send()
.await
.and_then(Response::error_for_status)
.map_err(|err| download_error(err.to_string()))?;

let mut file = tokio::fs::File::create(&self.path).await.map_err(|err| {
error!(
"Error occurred during file creating\nPath: {}\nError: {}",
self.path.to_string_lossy(),
err
);
download_error(err.to_string())
})?;

let mut stream = res.bytes_stream();

while let Some(item) = stream.next().await {
let chunk = item.map_err(|err| {
error!("Error occurred during file downloading\nError: {}", err);
download_error(err.to_string())
})?;

file.write_all(&chunk).await.map_err(|err| {
error!("Error occurred during writing to file\nError: {}", err);
download_error(err.to_string())
})?;
}

trace!("Downloaded successfully {}", self.path.to_string_lossy());

Ok(())
}
}

trace!("Downloaded successfully {}", path.to_string_lossy());
impl IntoFuture for Downloader {
type Output = Result<(), DownloadError>;

Ok(())
type IntoFuture = PinnedFutureWithBounds<Self::Output>;

fn into_future(self) -> Self::IntoFuture {
Box::pin(self.download())
}
}
1 change: 0 additions & 1 deletion crates/nomi-core/src/downloads/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use egui_task_manager::Progress;

#[async_trait::async_trait]
pub trait ProgressSender<P: Send>: Sync + Send {
/// It can technically return error but we will ignore them.
async fn update(&self, data: P);
}

Expand Down
13 changes: 13 additions & 0 deletions crates/nomi-core/src/game_paths.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
use std::path::PathBuf;

use crate::MINECRAFT_DIR;

#[derive(Debug, Clone)]
pub struct GamePaths {
pub game: PathBuf,
pub assets: PathBuf,
pub version: PathBuf,
pub libraries: PathBuf,
}

impl Default for GamePaths {
fn default() -> Self {
Self {
game: MINECRAFT_DIR.into(),
assets: PathBuf::from(MINECRAFT_DIR).join("assets"),
version: PathBuf::from(MINECRAFT_DIR).join("versions").join("NOMI_DEFAULT"),
libraries: PathBuf::from(MINECRAFT_DIR).join("libraries"),
}
}
}
8 changes: 7 additions & 1 deletion crates/nomi-core/src/instance/builder_ext.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::loaders::{fabric::Fabric, vanilla::Vanilla};
use crate::loaders::{fabric::Fabric, forge::Forge, vanilla::Vanilla};

use super::launch::{LaunchInstanceBuilder, LaunchSettings};

Expand All @@ -19,3 +19,9 @@ impl LaunchInstanceBuilderExt for Fabric {
builder.profile(self.to_profile())
}
}

impl LaunchInstanceBuilderExt for Forge {
fn insert(&self, builder: LaunchInstanceBuilder<LaunchSettings>) -> LaunchInstanceBuilder<LaunchSettings> {
builder.profile(self.to_profile())
}
}
Loading

0 comments on commit a1f50f9

Please sign in to comment.