You've already forked AstralRinth
forked from didirus/AstralRinth
Add method of storing launcher data, fix forge 1.17+, add launcher settings
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
use crate::data::DataError;
|
||||
use once_cell::sync;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
const META_FILE: &str = "meta.json";
|
||||
const META_URL: &str = "https://meta.modrinth.com/gamedata";
|
||||
|
||||
static METADATA: sync::OnceCell<RwLock<Metadata>> = sync::OnceCell::new();
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Metadata {
|
||||
pub minecraft: daedalus::minecraft::VersionManifest,
|
||||
pub forge: daedalus::modded::Manifest,
|
||||
pub fabric: daedalus::modded::Manifest,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub async fn init() -> Result<(), DataError> {
|
||||
let meta_path = crate::LAUNCHER_WORK_DIR.join(META_FILE);
|
||||
|
||||
if meta_path.exists() {
|
||||
let meta_data = std::fs::read_to_string(meta_path)
|
||||
.map(|x| serde_json::from_str::<Metadata>(&*x).ok())
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
if let Some(metadata) = meta_data {
|
||||
METADATA.get_or_init(|| RwLock::new(metadata));
|
||||
}
|
||||
}
|
||||
|
||||
let future = async {
|
||||
for attempt in 0..=3 {
|
||||
let res = async {
|
||||
let new = Self::fetch().await?;
|
||||
|
||||
std::fs::write(
|
||||
crate::LAUNCHER_WORK_DIR.join(META_FILE),
|
||||
&*serde_json::to_string(&new)?,
|
||||
)?;
|
||||
|
||||
if let Some(metadata) = METADATA.get() {
|
||||
*metadata.write().await = new;
|
||||
} else {
|
||||
METADATA.get_or_init(|| RwLock::new(new));
|
||||
}
|
||||
|
||||
Ok::<(), DataError>(())
|
||||
}
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(_) => {
|
||||
break;
|
||||
}
|
||||
Err(_) if attempt <= 3 => continue,
|
||||
Err(err) => {
|
||||
log::warn!("Unable to fetch launcher metadata: {}", err)
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if METADATA.get().is_some() {
|
||||
tokio::task::spawn(future);
|
||||
} else {
|
||||
future.await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fetch() -> Result<Self, DataError> {
|
||||
let (game, forge, fabric) = futures::future::join3(
|
||||
daedalus::minecraft::fetch_version_manifest(Some(&*format!(
|
||||
"{}/minecraft/v0/manifest.json",
|
||||
META_URL
|
||||
))),
|
||||
daedalus::modded::fetch_manifest(&*format!("{}/forge/v0/manifest.json", META_URL)),
|
||||
daedalus::modded::fetch_manifest(&*format!("{}/fabric/v0/manifest.json", META_URL)),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self {
|
||||
minecraft: game?,
|
||||
forge: forge?,
|
||||
fabric: fabric?,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get<'a>() -> Result<RwLockReadGuard<'a, Self>, DataError> {
|
||||
Ok(METADATA
|
||||
.get()
|
||||
.ok_or_else(|| DataError::InitializedError("metadata".to_string()))?
|
||||
.read()
|
||||
.await)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use std::io;
|
||||
|
||||
pub use meta::Metadata;
|
||||
pub use settings::Settings;
|
||||
|
||||
mod meta;
|
||||
mod settings;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum DataError {
|
||||
#[error("I/O error while reading data: {0}")]
|
||||
IOError(#[from] io::Error),
|
||||
|
||||
#[error("Daedalus error: {0}")]
|
||||
DaedalusError(#[from] daedalus::Error),
|
||||
|
||||
#[error("Attempted to access {0} without initializing it!")]
|
||||
InitializedError(String),
|
||||
|
||||
#[error("Error while serializing/deserializing data")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
use crate::data::DataError;
|
||||
use once_cell::sync;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
const SETTINGS_FILE: &str = "settings.json";
|
||||
|
||||
static SETTINGS: sync::OnceCell<RwLock<Settings>> = sync::OnceCell::new();
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Settings {
|
||||
pub memory: i32,
|
||||
pub game_resolution: (i32, i32),
|
||||
pub custom_java_args: String,
|
||||
pub java_8_path: Option<String>,
|
||||
pub java_17_path: Option<String>,
|
||||
pub wrapper_command: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
memory: 2048,
|
||||
game_resolution: (854, 480),
|
||||
custom_java_args: "".to_string(),
|
||||
java_8_path: None,
|
||||
java_17_path: None,
|
||||
wrapper_command: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub async fn init() -> Result<(), DataError> {
|
||||
let settings_path = crate::LAUNCHER_WORK_DIR.join(SETTINGS_FILE);
|
||||
|
||||
if settings_path.exists() {
|
||||
let settings_data = std::fs::read_to_string(settings_path)
|
||||
.map(|x| serde_json::from_str::<Settings>(&*x).ok())
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
if let Some(settings) = settings_data {
|
||||
SETTINGS.get_or_init(|| RwLock::new(settings));
|
||||
}
|
||||
}
|
||||
|
||||
if SETTINGS.get().is_none() {
|
||||
let new = Self::default();
|
||||
|
||||
std::fs::write(
|
||||
crate::LAUNCHER_WORK_DIR.join(SETTINGS_FILE),
|
||||
&*serde_json::to_string(&new)?,
|
||||
)?;
|
||||
|
||||
SETTINGS.get_or_init(|| RwLock::new(new));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn load() -> Result<(), DataError> {
|
||||
let new = serde_json::from_str::<Settings>(&*std::fs::read_to_string(
|
||||
crate::LAUNCHER_WORK_DIR.join(SETTINGS_FILE),
|
||||
)?)?;
|
||||
|
||||
let write = &mut *SETTINGS
|
||||
.get()
|
||||
.ok_or_else(|| DataError::InitializedError("settings".to_string()))?
|
||||
.write()
|
||||
.await;
|
||||
|
||||
*write = new;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn save() -> Result<(), DataError> {
|
||||
let settings = Self::get().await?;
|
||||
|
||||
std::fs::write(
|
||||
crate::LAUNCHER_WORK_DIR.join(SETTINGS_FILE),
|
||||
&*serde_json::to_string(&*settings)?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get<'a>() -> Result<RwLockReadGuard<'a, Self>, DataError> {
|
||||
Ok(SETTINGS
|
||||
.get()
|
||||
.ok_or_else(|| DataError::InitializedError("settings".to_string()))?
|
||||
.read()
|
||||
.await)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user