mac download (#77)

* mac download

* clippy
This commit is contained in:
Wyatt Verchere
2023-04-11 07:15:37 -07:00
committed by GitHub
parent d23bc4450d
commit ac6ad0ef2e
10 changed files with 63 additions and 25 deletions

View File

@@ -57,7 +57,6 @@ pub async fn authenticate(
Ok(credentials) Ok(credentials)
} }
/// Refresh some credentials using Hydra, if needed /// Refresh some credentials using Hydra, if needed
/// This is the primary desired way to get credentials, as it will also refresh them. /// This is the primary desired way to get credentials, as it will also refresh them.
#[tracing::instrument] #[tracing::instrument]

View File

@@ -54,8 +54,12 @@ pub async fn get_optimal_jre_key(profile: &Profile) -> crate::Result<String> {
})?; })?;
// Get detailed manifest info from Daedalus // Get detailed manifest info from Daedalus
let version_info = let version_info = download::download_version_info(
download::download_version_info(&state, version, profile.metadata.loader_version.as_ref()).await?; &state,
version,
profile.metadata.loader_version.as_ref(),
)
.await?;
let optimal_key = match version_info let optimal_key = match version_info
.java_version .java_version
.as_ref() .as_ref()

View File

@@ -146,8 +146,12 @@ pub async fn run_credentials(
profile.metadata.game_version profile.metadata.game_version
)) ))
})?; })?;
let version_info = let version_info = download::download_version_info(
download::download_version_info(&state, version, profile.metadata.loader_version.as_ref()).await?; &state,
version,
profile.metadata.loader_version.as_ref(),
)
.await?;
let pre_launch_hooks = let pre_launch_hooks =
&profile.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch; &profile.hooks.as_ref().unwrap_or(&settings.hooks).pre_launch;
for hook in pre_launch_hooks.iter() { for hook in pre_launch_hooks.iter() {

View File

@@ -20,5 +20,6 @@ pub async fn set(settings: Settings) -> crate::Result<()> {
let state = State::get().await?; let state = State::get().await?;
// Replaces the settings struct in the RwLock with the passed argument // Replaces the settings struct in the RwLock with the passed argument
*state.settings.write().await = settings; *state.settings.write().await = settings;
state.reset_semaphore().await; // reset semaphore to new max
Ok(()) Ok(())
} }

View File

@@ -41,7 +41,9 @@ pub struct State {
/// Information on the location of files used in the launcher /// Information on the location of files used in the launcher
pub directories: DirectoryInfo, pub directories: DirectoryInfo,
/// Semaphore used to limit concurrent I/O and avoid errors /// Semaphore used to limit concurrent I/O and avoid errors
pub io_semaphore: Semaphore, pub io_semaphore: RwLock<Semaphore>,
/// Stored maximum number of sempahores of current io_semaphore
pub io_semaphore_max: RwLock<u32>,
/// Launcher metadata /// Launcher metadata
pub metadata: Metadata, pub metadata: Metadata,
// TODO: settings API // TODO: settings API
@@ -80,8 +82,10 @@ impl State {
Settings::init(&directories.settings_file()).await?; Settings::init(&directories.settings_file()).await?;
// Loose initializations // Loose initializations
let io_semaphore_max = settings.max_concurrent_downloads;
let io_semaphore = let io_semaphore =
Semaphore::new(settings.max_concurrent_downloads); RwLock::new(Semaphore::new(io_semaphore_max));
// Launcher data // Launcher data
let (metadata, profiles) = tokio::try_join! { let (metadata, profiles) = tokio::try_join! {
@@ -112,6 +116,7 @@ impl State {
Ok(Arc::new(Self { Ok(Arc::new(Self {
directories, directories,
io_semaphore, io_semaphore,
io_semaphore_max: RwLock::new(io_semaphore_max as u32),
metadata, metadata,
settings: RwLock::new(settings), settings: RwLock::new(settings),
profiles: RwLock::new(profiles), profiles: RwLock::new(profiles),
@@ -158,4 +163,21 @@ impl State {
Ok(()) Ok(())
} }
/// Reset semaphores to default values
/// This will block until all uses of the semaphore are complete, so it should only be called
/// when we are not in the middle of downloading something (ie: changing the settings!)
pub async fn reset_semaphore(&self) {
let settings = self.settings.read().await;
let mut io_semaphore = self.io_semaphore.write().await;
let mut total_permits = self.io_semaphore_max.write().await;
// Wait to get all permits back
let _ = io_semaphore.acquire_many(*total_permits).await;
// Reset the semaphore
io_semaphore.close();
*total_permits = settings.max_concurrent_downloads as u32;
*io_semaphore = Semaphore::new(settings.max_concurrent_downloads);
}
} }

View File

@@ -10,8 +10,8 @@ use std::{
collections::HashMap, collections::HashMap,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use tokio::fs;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use tokio::{fs, sync::RwLock};
const PROFILE_JSON_PATH: &str = "profile.json"; const PROFILE_JSON_PATH: &str = "profile.json";
@@ -119,7 +119,7 @@ impl Profile {
pub async fn set_icon<'a>( pub async fn set_icon<'a>(
&'a mut self, &'a mut self,
cache_dir: &Path, cache_dir: &Path,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
icon: bytes::Bytes, icon: bytes::Bytes,
file_name: &str, file_name: &str,
) -> crate::Result<&'a mut Self> { ) -> crate::Result<&'a mut Self> {
@@ -166,11 +166,11 @@ impl Profiles {
#[tracing::instrument] #[tracing::instrument]
pub async fn init( pub async fn init(
dirs: &DirectoryInfo, dirs: &DirectoryInfo,
io_sempahore: &Semaphore, io_sempahore: &RwLock<Semaphore>,
) -> crate::Result<Self> { ) -> crate::Result<Self> {
let mut profiles = HashMap::new(); let mut profiles = HashMap::new();
fs::create_dir_all(dirs.profiles_dir()).await?;
let mut entries = fs::read_dir(dirs.profiles_dir()).await?; let mut entries = fs::read_dir(dirs.profiles_dir()).await?;
while let Some(entry) = entries.next_entry().await? { while let Some(entry) = entries.next_entry().await? {
let path = entry.path(); let path = entry.path();
if path.is_dir() { if path.is_dir() {

View File

@@ -10,7 +10,7 @@ use sha2::Digest;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::sync::Semaphore; use tokio::sync::{RwLock, Semaphore};
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Project { pub struct Project {
@@ -160,7 +160,7 @@ async fn read_icon_from_file(
icon_path: Option<String>, icon_path: Option<String>,
cache_dir: &Path, cache_dir: &Path,
path: &PathBuf, path: &PathBuf,
io_semaphore: &Semaphore, io_semaphore: &RwLock<Semaphore>,
) -> crate::Result<Option<PathBuf>> { ) -> crate::Result<Option<PathBuf>> {
if let Some(icon_path) = icon_path { if let Some(icon_path) = icon_path {
// we have to repoen the zip twice here :( // we have to repoen the zip twice here :(
@@ -208,7 +208,7 @@ async fn read_icon_from_file(
pub async fn infer_data_from_files( pub async fn infer_data_from_files(
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
cache_dir: PathBuf, cache_dir: PathBuf,
io_semaphore: &Semaphore, io_semaphore: &RwLock<Semaphore>,
) -> crate::Result<HashMap<PathBuf, Project>> { ) -> crate::Result<HashMap<PathBuf, Project>> {
let mut file_path_hashes = HashMap::new(); let mut file_path_hashes = HashMap::new();

View File

@@ -5,7 +5,7 @@ use reqwest::Method;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tokio::sync::Semaphore; use tokio::sync::{RwLock, Semaphore};
use tokio::{ use tokio::{
fs::{self, File}, fs::{self, File},
io::AsyncWriteExt, io::AsyncWriteExt,
@@ -16,7 +16,7 @@ const FETCH_ATTEMPTS: usize = 3;
pub async fn fetch( pub async fn fetch(
url: &str, url: &str,
sha1: Option<&str>, sha1: Option<&str>,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<Bytes> { ) -> crate::Result<Bytes> {
fetch_advanced(Method::GET, url, sha1, semaphore).await fetch_advanced(Method::GET, url, sha1, semaphore).await
} }
@@ -25,7 +25,7 @@ pub async fn fetch_json<T>(
method: Method, method: Method,
url: &str, url: &str,
sha1: Option<&str>, sha1: Option<&str>,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<T> ) -> crate::Result<T>
where where
T: DeserializeOwned, T: DeserializeOwned,
@@ -41,9 +41,10 @@ pub async fn fetch_advanced(
method: Method, method: Method,
url: &str, url: &str,
sha1: Option<&str>, sha1: Option<&str>,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<Bytes> { ) -> crate::Result<Bytes> {
let _permit = semaphore.acquire().await?; let io_semaphore = semaphore.read().await;
let _permit = io_semaphore.acquire().await?;
for attempt in 1..=(FETCH_ATTEMPTS + 1) { for attempt in 1..=(FETCH_ATTEMPTS + 1) {
let result = REQWEST_CLIENT.request(method.clone(), url).send().await; let result = REQWEST_CLIENT.request(method.clone(), url).send().await;
@@ -90,7 +91,7 @@ pub async fn fetch_advanced(
pub async fn fetch_mirrors( pub async fn fetch_mirrors(
mirrors: &[&str], mirrors: &[&str],
sha1: Option<&str>, sha1: Option<&str>,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<Bytes> { ) -> crate::Result<Bytes> {
if mirrors.is_empty() { if mirrors.is_empty() {
return Err(crate::ErrorKind::InputError( return Err(crate::ErrorKind::InputError(
@@ -114,9 +115,11 @@ pub async fn fetch_mirrors(
pub async fn write<'a>( pub async fn write<'a>(
path: &Path, path: &Path,
bytes: &[u8], bytes: &[u8],
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<()> { ) -> crate::Result<()> {
let _permit = semaphore.acquire().await?; let io_semaphore = semaphore.read().await;
let _permit = io_semaphore.acquire().await?;
if let Some(parent) = path.parent() { if let Some(parent) = path.parent() {
fs::create_dir_all(parent).await?; fs::create_dir_all(parent).await?;
} }
@@ -132,7 +135,7 @@ pub async fn write_cached_icon(
icon_path: &str, icon_path: &str,
cache_dir: &Path, cache_dir: &Path,
bytes: Bytes, bytes: Bytes,
semaphore: &Semaphore, semaphore: &RwLock<Semaphore>,
) -> crate::Result<PathBuf> { ) -> crate::Result<PathBuf> {
let extension = Path::new(&icon_path).extension().and_then(OsStr::to_str); let extension = Path::new(&icon_path).extension().and_then(OsStr::to_str);
let hash = sha1_async(bytes.clone()).await?; let hash = sha1_async(bytes.clone()).await?;

View File

@@ -56,7 +56,10 @@ pub async fn profile_run_wait(path: &Path) -> Result<()> {
// for the actual Child in the state. // for the actual Child in the state.
// invoke('profile_run_credentials', {path, credentials})') // invoke('profile_run_credentials', {path, credentials})')
#[tauri::command] #[tauri::command]
pub async fn profile_run_credentials(path: &Path, credentials: Credentials) -> Result<u32> { pub async fn profile_run_credentials(
path: &Path,
credentials: Credentials,
) -> Result<u32> {
let proc_lock = profile::run_credentials(path, &credentials).await?; let proc_lock = profile::run_credentials(path, &credentials).await?;
let pid = proc_lock.read().await.child.id().ok_or_else(|| { let pid = proc_lock.read().await.child.id().ok_or_else(|| {
theseus::Error::from(theseus::ErrorKind::LauncherError( theseus::Error::from(theseus::ErrorKind::LauncherError(

View File

@@ -31,7 +31,9 @@ async fn main() -> theseus::Result<()> {
// Initialize state // Initialize state
let st = State::get().await?; let st = State::get().await?;
st.settings.write().await.max_concurrent_downloads = 10; st.settings.write().await.max_concurrent_downloads = 5;
// Changed the settings, so need to reset the semaphore
st.reset_semaphore().await;
// Clear profiles // Clear profiles
println!("Clearing profiles."); println!("Clearing profiles.");