You've already forked AstralRinth
forked from didirus/AstralRinth
@@ -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]
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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?;
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
Reference in New Issue
Block a user