You've already forked AstralRinth
forked from xxxOFFxxx/AstralRinth
refactor: remove init_authlib_patching function and update related references
This commit is contained in:
@@ -38,11 +38,6 @@ export async function applyMigrationFix(eol) {
|
|||||||
return await invoke('plugin:utils|apply_migration_fix', { eol })
|
return await invoke('plugin:utils|apply_migration_fix', { eol })
|
||||||
}
|
}
|
||||||
|
|
||||||
// This code is modified by AstralRinth
|
|
||||||
export async function initAuthlibPatching(minecraftVersion, isMojang) {
|
|
||||||
return await invoke('plugin:utils|init_authlib_patching', { minecraftVersion, isMojang })
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function isNetworkMetered() {
|
export async function isNetworkMetered() {
|
||||||
return await invoke('plugin:utils|is_network_metered')
|
return await invoke('plugin:utils|is_network_metered')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,6 @@ fn main() {
|
|||||||
"utils",
|
"utils",
|
||||||
InlinedPlugin::new()
|
InlinedPlugin::new()
|
||||||
.commands(&[
|
.commands(&[
|
||||||
"init_authlib_patching",
|
|
||||||
"apply_migration_fix",
|
"apply_migration_fix",
|
||||||
"init_update_launcher",
|
"init_update_launcher",
|
||||||
"get_os",
|
"get_os",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Feature
|
/// This code is modified by AstralRinth
|
||||||
/// Create new offline user
|
/// Create new offline user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn offline_login(name: &str) -> Result<Credentials> {
|
pub async fn offline_login(name: &str) -> Result<Credentials> {
|
||||||
@@ -29,7 +29,7 @@ pub async fn offline_login(name: &str) -> Result<Credentials> {
|
|||||||
Ok(credentials)
|
Ok(credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Feature
|
/// This code is modified by AstralRinth
|
||||||
/// Create new Ely.by user
|
/// Create new Ely.by user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn elyby_login(
|
pub async fn elyby_login(
|
||||||
@@ -41,7 +41,7 @@ pub async fn elyby_login(
|
|||||||
Ok(credentials)
|
Ok(credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Feature
|
/// This code is modified by AstralRinth
|
||||||
/// Authenticate Ely.by user
|
/// Authenticate Ely.by user
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn elyby_auth_authenticate(
|
pub async fn elyby_auth_authenticate(
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use url::Url;
|
|||||||
pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||||
tauri::plugin::Builder::new("utils")
|
tauri::plugin::Builder::new("utils")
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
init_authlib_patching,
|
|
||||||
apply_migration_fix,
|
apply_migration_fix,
|
||||||
init_update_launcher,
|
init_update_launcher,
|
||||||
get_os,
|
get_os,
|
||||||
@@ -31,17 +30,6 @@ pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This code is modified by AstralRinth
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn init_authlib_patching(
|
|
||||||
minecraft_version: &str,
|
|
||||||
is_mojang: bool,
|
|
||||||
) -> Result<bool> {
|
|
||||||
let result =
|
|
||||||
utils::init_authlib_patching(minecraft_version, is_mojang).await?;
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This code is modified by AstralRinth
|
// This code is modified by AstralRinth
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"productName": "AstralRinth App",
|
"productName": "AstralRinth App",
|
||||||
"version": "0.10.2401",
|
"version": "0.10.2701",
|
||||||
"mainBinaryName": "AstralRinth App",
|
"mainBinaryName": "AstralRinth App",
|
||||||
"identifier": "AstralRinthApp",
|
"identifier": "AstralRinthApp",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! Logic for launching Minecraft
|
//! Logic for launching Minecraft
|
||||||
use crate::data::ModLoader;
|
use crate::data::ModLoader;
|
||||||
use crate::event::emit::{emit_loading, emit_info, init_or_edit_loading};
|
use crate::event::emit::{emit_info, emit_loading, init_or_edit_loading};
|
||||||
use crate::event::{LoadingBarId, LoadingBarType};
|
use crate::event::{LoadingBarId, LoadingBarType};
|
||||||
use crate::launcher::download::download_log_config;
|
use crate::launcher::download::download_log_config;
|
||||||
use crate::launcher::io::IOError;
|
use crate::launcher::io::IOError;
|
||||||
@@ -11,8 +11,8 @@ use crate::profile::QuickPlayType;
|
|||||||
use crate::state::{
|
use crate::state::{
|
||||||
AccountType, Credentials, JavaVersion, ProcessMetadata, ProfileInstallStage,
|
AccountType, Credentials, JavaVersion, ProcessMetadata, ProfileInstallStage,
|
||||||
};
|
};
|
||||||
use crate::util::{io, utils};
|
|
||||||
use crate::util::rpc::RpcServerBuilder;
|
use crate::util::rpc::RpcServerBuilder;
|
||||||
|
use crate::util::{io, utils};
|
||||||
use crate::{State, get_resource_file, process, state as st};
|
use crate::{State, get_resource_file, process, state as st};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use daedalus as d;
|
use daedalus as d;
|
||||||
@@ -671,30 +671,33 @@ pub async fn launch_minecraft(
|
|||||||
if version_jar == "1.16.4" || version_jar == "1.16.5" {
|
if version_jar == "1.16.4" || version_jar == "1.16.5" {
|
||||||
let invalid_url = "https://invalid.invalid";
|
let invalid_url = "https://invalid.invalid";
|
||||||
let _ = emit_info(&format!(
|
let _ = emit_info(&format!(
|
||||||
"[AR] • Detected launch of {} on the offline account. Applying 1.16.4/5 multiplayer fixes.",
|
"[AR] Detected launch of {} on the offline account. Applying 1.16.4/5 multiplayer fixes.",
|
||||||
version_jar
|
version_jar
|
||||||
)
|
)
|
||||||
).await;
|
).await;
|
||||||
command.arg("-Dminecraft.api.env=custom");
|
command.arg("-Dminecraft.api.env=custom");
|
||||||
command.arg(format!("-Dminecraft.api.auth.host={}", invalid_url));
|
command.arg(format!("-Dminecraft.api.auth.host={}", invalid_url));
|
||||||
command.arg(format!("-Dminecraft.api.account.host={}", invalid_url));
|
command
|
||||||
command.arg(format!("-Dminecraft.api.session.host={}", invalid_url));
|
.arg(format!("-Dminecraft.api.account.host={}", invalid_url));
|
||||||
command.arg(format!("-Dminecraft.api.services.host={}", invalid_url));
|
command
|
||||||
|
.arg(format!("-Dminecraft.api.session.host={}", invalid_url));
|
||||||
|
command
|
||||||
|
.arg(format!("-Dminecraft.api.services.host={}", invalid_url));
|
||||||
}
|
}
|
||||||
} else if credentials.account_type == AccountType::ElyBy.as_lowercase_str()
|
} else if credentials.account_type == AccountType::ElyBy.as_lowercase_str()
|
||||||
{
|
{
|
||||||
let _ = emit_info(&format!(
|
let _ = emit_info(&format!(
|
||||||
"[AR] • Detected launch of {} on the Ely.by account. Loading Ely.by AuthLib Injector...",
|
"[AR] Detected launch of {} on the Ely.by account. Loading Ely.by AuthLib Injector...",
|
||||||
version_jar
|
version_jar
|
||||||
)
|
)
|
||||||
).await;
|
).await;
|
||||||
let path_buf = utils::get_or_download_elyby_injector().await?;
|
let path_buf = utils::get_elyby_injector_library().await?;
|
||||||
let path = path_buf.to_str().unwrap();
|
let path = path_buf.to_str().unwrap();
|
||||||
let _ = emit_info(&format!(
|
let _ = emit_info(&format!(
|
||||||
"[AR] • Launching minecraft instance with {}",
|
"[AR] Launching minecraft instance with {}",
|
||||||
path
|
path
|
||||||
)
|
))
|
||||||
).await;
|
.await;
|
||||||
command.arg(format!("-javaagent:{}=ely.by", path));
|
command.arg(format!("-javaagent:{}=ely.by", path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl DiscordGuard {
|
|||||||
.large_image("astralrinth_logo")
|
.large_image("astralrinth_logo")
|
||||||
.large_text(&build_info)
|
.large_text(&build_info)
|
||||||
.small_image("astralrinth_logo")
|
.small_image("astralrinth_logo")
|
||||||
.small_text(&build_download),
|
.small_text(build_download),
|
||||||
)
|
)
|
||||||
.timestamps(Timestamps::new().start(time));
|
.timestamps(Timestamps::new().start(time));
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use crate::api::update;
|
|
||||||
use crate::state::db;
|
|
||||||
///
|
///
|
||||||
/// This code is modified by AstralRinth
|
/// This code is modified by AstralRinth
|
||||||
///
|
///
|
||||||
/// Version: 0.1.1
|
/// Version: 0.1.2
|
||||||
///
|
///
|
||||||
|
///
|
||||||
|
use crate::api::update;
|
||||||
|
use crate::event::emit::emit_info;
|
||||||
|
use crate::state::db;
|
||||||
use crate::{Result, State};
|
use crate::{Result, State};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
@@ -16,301 +19,123 @@ const PACKAGE_JSON_CONTENT: &str =
|
|||||||
// include_str!("../../../../apps/app-frontend/package.json");
|
// include_str!("../../../../apps/app-frontend/package.json");
|
||||||
include_str!("../../../../apps/app/tauri.conf.json");
|
include_str!("../../../../apps/app/tauri.conf.json");
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct Launcher {
|
|
||||||
pub version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct Artifact {
|
|
||||||
path: Option<String>,
|
|
||||||
sha1: Option<String>,
|
|
||||||
url: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct Downloads {
|
|
||||||
artifact: Option<Artifact>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct Library {
|
|
||||||
name: String,
|
|
||||||
downloads: Option<Downloads>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct VersionJson {
|
|
||||||
libraries: Vec<Library>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialize the content of package.json into a Launcher struct
|
/// Deserialize the content of package.json into a Launcher struct
|
||||||
pub fn read_package_json() -> io::Result<Launcher> {
|
pub fn read_package_json() -> io::Result<Launcher> {
|
||||||
let launcher: Launcher = serde_json::from_str(PACKAGE_JSON_CONTENT)?;
|
let launcher: Launcher = serde_json::from_str(PACKAGE_JSON_CONTENT)?;
|
||||||
Ok(launcher)
|
Ok(launcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Ely.by Injector
|
#[derive(Serialize, Deserialize)]
|
||||||
/// Returns the PathBuf to the Ely.by AuthLib Injector
|
pub struct Launcher {
|
||||||
/// If resource doesn't exist or outdated, it will be downloaded from Git Astralium.
|
pub version: String,
|
||||||
pub async fn get_or_download_elyby_injector() -> Result<PathBuf> {
|
}
|
||||||
tracing::info!("[AR] • Initializing state for Ely.by AuthLib Injector...");
|
|
||||||
|
/// Fetches or updates the Ely.by AuthLib Injector library.
|
||||||
|
pub async fn get_elyby_injector_library() -> Result<PathBuf> {
|
||||||
|
tracing::info!("[AR] • Initializing Ely.by AuthLib Injector...");
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let libraries_dir = state.directories.libraries_dir();
|
let libraries_dir = state.directories.libraries_dir();
|
||||||
|
|
||||||
// Stores the local authlib injectors from `libraries/astralrinth/authlib_injectors/` directory.
|
validate_library_dir(&libraries_dir, "authlib_injector/").await?;
|
||||||
let mut local_authlib_injectors = Vec::new();
|
let injector_dir = libraries_dir.join("astralrinth/authlib_injector/");
|
||||||
|
fs::create_dir_all(&injector_dir).await?;
|
||||||
|
|
||||||
validate_astralrinth_library_dir(&libraries_dir, "authlib_injector/").await?;
|
let mut local_injectors = Vec::new();
|
||||||
let astralrinth_dir = libraries_dir.join("astralrinth/");
|
if let Ok(mut entries) = fs::read_dir(&injector_dir).await {
|
||||||
let authlib_injector_dir = astralrinth_dir.join("authlib_injector/");
|
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||||
let mut authlib_injector_dir_data = fs::read_dir(&authlib_injector_dir).await?;
|
let path = entry.path();
|
||||||
|
if let (Some(name), Ok(meta)) = (
|
||||||
// Get all local authlib injectors
|
path.file_name().and_then(|s| s.to_str()),
|
||||||
while let Some(entry) = authlib_injector_dir_data.next_entry().await? {
|
entry.metadata().await,
|
||||||
let path = entry.path();
|
) {
|
||||||
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
if name.starts_with("authlib-injector") {
|
||||||
if file_name.starts_with("authlib-injector") {
|
local_injectors.push((
|
||||||
let metadata = entry.metadata().await?;
|
path,
|
||||||
let modified = metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH);
|
meta.modified().unwrap_or(SystemTime::UNIX_EPOCH),
|
||||||
local_authlib_injectors.push((path.clone(), modified));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
local_injectors.sort_by(|a, b| b.1.cmp(&a.1)); // newest first
|
||||||
|
|
||||||
// Get information about latest authlib injector from remote repository
|
if !local_injectors.is_empty() {
|
||||||
let (asset_name, download_url) = match extract_elyby_authlib_metadata("authlib-injector").await {
|
tracing::info!("[AR] • Local versions:");
|
||||||
Ok(data) => data,
|
for (path, mtime) in &local_injectors {
|
||||||
Err(err) => {
|
tracing::info!(" • {:?} ({:?})", path.file_name().unwrap(), mtime);
|
||||||
if let Some((local_path, _)) = local_authlib_injectors
|
}
|
||||||
.iter()
|
}
|
||||||
.max_by(|a, b| a.1.cmp(&b.1))
|
|
||||||
{
|
let latest_local = local_injectors.first().cloned();
|
||||||
tracing::info!("[AR] • Found local AuthLib Injector(s):");
|
// let latest_local_name = latest_local.as_ref().map(|p| p.0.file_name().unwrap().to_string_lossy().to_string());
|
||||||
for (path, time) in &local_authlib_injectors {
|
|
||||||
tracing::info!("• {:?} (modified: {:?})", path.file_name().unwrap(), time);
|
// Remote (fallback to empty strings)
|
||||||
}
|
let (remote_name, remote_url) =
|
||||||
tracing::warn!("[AR] • Failed to get latest AuthLib Injector from remote, using latest local version: {}", local_path.display());
|
match extract_metadata_from_elyby_file("authlib-injector").await {
|
||||||
return Ok(local_path.clone());
|
Ok(data) => {
|
||||||
} else {
|
tracing::info!("[AR] • Remote: {} ({})", data.0, data.1);
|
||||||
tracing::error!("[AR] • Failed to get AuthLib Injector from remote and no local copy found.");
|
data
|
||||||
return Err(crate::ErrorKind::NetworkErrorOccurred { error: format!("Failed to fetch authlib-injector metadata and no local version available: {}", err) }.as_error());
|
|
||||||
}
|
}
|
||||||
}
|
Err(e) => {
|
||||||
|
tracing::warn!("[AR] • Remote failed: {}, using local", e);
|
||||||
|
("".to_string(), "".to_string())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let remote_path = if !remote_name.is_empty() {
|
||||||
|
Some(injector_dir.join(&remote_name))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if !local_authlib_injectors.is_empty() {
|
if let Some(local_path) = &latest_local {
|
||||||
local_authlib_injectors.sort_by(|a, b| a.1.cmp(&b.1));
|
let local_name = local_path.0.file_name().unwrap().to_string_lossy();
|
||||||
tracing::info!("[AR] • Found local AuthLib Injector(s):");
|
if let Some(rp) = &remote_path {
|
||||||
for (path, time) in &local_authlib_injectors {
|
let remote_name = rp.file_name().unwrap().to_string_lossy();
|
||||||
tracing::info!("• {:?} (modified: {:?})", path.file_name().unwrap(), time);
|
if local_name == remote_name {
|
||||||
|
tracing::info!("[AR] • Versions match: {}", local_name);
|
||||||
|
return Ok(local_path.0.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::info!(
|
||||||
|
"[AR] • No remote info, using local: {}",
|
||||||
|
local_name
|
||||||
|
);
|
||||||
|
let _ = emit_info(&format!(
|
||||||
|
"[AR] No remote info, using local: {}",
|
||||||
|
local_name
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
return Ok(local_path.0.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote_authlib_injector = if !asset_name.is_empty() {
|
let Some(rp) = remote_path else {
|
||||||
authlib_injector_dir.join(&asset_name)
|
return Err(crate::ErrorKind::NetworkErrorOccurred {
|
||||||
} else {
|
error: "No local injector & remote unavailable".to_string(),
|
||||||
return Err(crate::ErrorKind::ParseError { reason: "Asset name is empty from metadata".to_string() }.as_error());
|
}
|
||||||
|
.as_error());
|
||||||
};
|
};
|
||||||
|
|
||||||
let latest_local_authlib_injector = local_authlib_injectors
|
let fname = rp.file_name().unwrap().to_string_lossy();
|
||||||
.first()
|
tracing::info!("[AR] • Downloading: {}", fname);
|
||||||
.map(|(p, _)| p.clone());
|
let _ = emit_info(&format!("[AR] Downloading: {}", fname)).await;
|
||||||
|
|
||||||
let latest_local_authlib_injector_full_path_buf = match latest_local_authlib_injector {
|
let bytes = fetch_bytes_from_url(&remote_url).await?;
|
||||||
Some(path) => path,
|
let rel_path = rp
|
||||||
None => {
|
.strip_prefix(&libraries_dir)?
|
||||||
tracing::info!("[AR] • No local version found, will download from remote: {}", remote_authlib_injector.display());
|
.to_string_lossy()
|
||||||
let bytes = fetch_bytes_from_url(download_url.as_str()).await?;
|
.into_owned();
|
||||||
write_file_to_libraries(&remote_authlib_injector.to_string_lossy(), &bytes).await?;
|
write_file_to_libraries(&rel_path, &bytes).await?;
|
||||||
tracing::info!("[AR] • Successfully saved AuthLib Injector to {}", remote_authlib_injector.display());
|
|
||||||
return Ok(remote_authlib_injector);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tracing::info!("[AR] • Remote Asset name: {}", asset_name);
|
tracing::info!("[AR] • Saved: {}", rp.display());
|
||||||
tracing::info!("[AR] • Remote Download URL: {}", download_url);
|
let _ = emit_info(&format!("[AR] Saved: {}", rp.display())).await;
|
||||||
tracing::info!("[AR] • Latest local AuthLib Injector: {}", latest_local_authlib_injector_full_path_buf.file_name().unwrap().to_string_lossy());
|
Ok(rp.to_path_buf())
|
||||||
tracing::info!("[AR] • Comparing local version {} with parsed remote version {}", latest_local_authlib_injector_full_path_buf.display(), remote_authlib_injector.display());
|
|
||||||
|
|
||||||
if remote_authlib_injector == latest_local_authlib_injector_full_path_buf {
|
|
||||||
tracing::info!("[AR] • Remote version is the same as local version, using local copy.");
|
|
||||||
return Ok(latest_local_authlib_injector_full_path_buf);
|
|
||||||
} else {
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • Doesn't exist or outdated, attempting to download latest AuthLib Injector from URL: {}",
|
|
||||||
download_url
|
|
||||||
);
|
|
||||||
let bytes = fetch_bytes_from_url(download_url.as_str()).await?;
|
|
||||||
write_file_to_libraries(&remote_authlib_injector.to_string_lossy(), &bytes).await?;
|
|
||||||
tracing::info!("[AR] • Successfully saved AuthLib Injector to {}", remote_authlib_injector.display());
|
|
||||||
return Ok(remote_authlib_injector);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Migration. Patch
|
|
||||||
/// Applying migration fix for SQLite database.
|
|
||||||
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
|
||||||
tracing::info!("[AR] • Attempting to apply migration fix");
|
|
||||||
let patched = db::apply_migration_fix(eol).await?;
|
|
||||||
if patched {
|
|
||||||
tracing::info!("[AR] • Successfully applied migration fix");
|
|
||||||
} else {
|
|
||||||
tracing::error!("[AR] • Failed to apply migration fix");
|
|
||||||
}
|
|
||||||
Ok(patched)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • Feature. Updater
|
|
||||||
/// Initialize the update launcher.
|
|
||||||
pub async fn init_update_launcher(
|
|
||||||
download_url: &str,
|
|
||||||
local_filename: &str,
|
|
||||||
os_type: &str,
|
|
||||||
auto_update_supported: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
tracing::info!("[AR] • Initialize downloading from • {:?}", download_url);
|
|
||||||
tracing::info!("[AR] • Save local file name • {:?}", local_filename);
|
|
||||||
tracing::info!("[AR] • OS type • {}", os_type);
|
|
||||||
tracing::info!("[AR] • Auto update supported • {}", auto_update_supported);
|
|
||||||
|
|
||||||
if let Err(e) = update::get_resource(
|
|
||||||
download_url,
|
|
||||||
local_filename,
|
|
||||||
os_type,
|
|
||||||
auto_update_supported,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
eprintln!(
|
|
||||||
"[AR] • An error occurred! Failed to download the file: {}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
println!("[AR] • Code finishes without errors.");
|
|
||||||
process::exit(0)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • AuthLib (Ely.by)
|
|
||||||
/// Initializes the AuthLib patching process.
|
|
||||||
///
|
|
||||||
/// Returns `true` if the authlib patched successfully.
|
|
||||||
pub async fn init_authlib_patching(
|
|
||||||
minecraft_version: &str,
|
|
||||||
is_mojang: bool,
|
|
||||||
) -> Result<bool> {
|
|
||||||
let minecraft_library_metadata =
|
|
||||||
get_minecraft_library_metadata(minecraft_version).await?;
|
|
||||||
// Parses the AuthLib version from string
|
|
||||||
// Example output: "com.mojang:authlib:6.0.58" -> "6.0.58"
|
|
||||||
let authlib_version = minecraft_library_metadata
|
|
||||||
.name
|
|
||||||
.split(':')
|
|
||||||
.nth(2)
|
|
||||||
.unwrap_or("unknown");
|
|
||||||
let authlib_fullname_string = format!("authlib-{}.jar", authlib_version);
|
|
||||||
let authlib_fullname_str = authlib_fullname_string.as_str();
|
|
||||||
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • Attempting to download AuthLib -> {}.",
|
|
||||||
authlib_fullname_string
|
|
||||||
);
|
|
||||||
|
|
||||||
download_authlib(
|
|
||||||
&minecraft_library_metadata,
|
|
||||||
authlib_fullname_str,
|
|
||||||
minecraft_version,
|
|
||||||
is_mojang,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • Universal Write (IO) Function.
|
|
||||||
/// Validating the `astralrinth/{target_directory}/` directory exists inside the libraries/astralrinth directory.
|
|
||||||
async fn validate_astralrinth_library_dir(
|
|
||||||
libraries_dir: &PathBuf,
|
|
||||||
validation_directory: &str
|
|
||||||
) -> Result<()> {
|
|
||||||
let astralrinth_path = libraries_dir.join(format!("astralrinth/{}", validation_directory));
|
|
||||||
if !astralrinth_path.exists() {
|
|
||||||
tokio::fs::create_dir_all(&astralrinth_path)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
tracing::error!(
|
|
||||||
"[AR] • Failed to create {} directory: {:?}",
|
|
||||||
astralrinth_path.display(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
crate::ErrorKind::IOErrorOccurred {
|
|
||||||
error: format!(
|
|
||||||
"Failed to create {} directory: {}",
|
|
||||||
astralrinth_path.display(),
|
|
||||||
e
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.as_error()
|
|
||||||
})?;
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • Created missing {} directory",
|
|
||||||
astralrinth_path.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • Universal Write (IO) Function
|
|
||||||
/// Saves the downloaded bytes to the `libraries` directory using the given relative path.
|
|
||||||
async fn write_file_to_libraries(
|
|
||||||
relative_path: &str,
|
|
||||||
bytes: &bytes::Bytes,
|
|
||||||
) -> Result<()> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
let output_path = state.directories.libraries_dir().join(relative_path);
|
|
||||||
|
|
||||||
fs::write(&output_path, bytes).await.map_err(|e| {
|
|
||||||
tracing::error!("[AR] • Failed to save file: {:?}", e);
|
|
||||||
crate::ErrorKind::IOErrorOccurred {
|
|
||||||
error: format!("Failed to save file: {e}"),
|
|
||||||
}
|
|
||||||
.as_error()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • AuthLib (Ely.by)
|
|
||||||
/// Downloads the AuthLib file from Mojang libraries or Git Astralium services.
|
|
||||||
async fn download_authlib(
|
|
||||||
minecraft_library_metadata: &Library,
|
|
||||||
authlib_fullname: &str,
|
|
||||||
minecraft_version: &str,
|
|
||||||
is_mojang: bool,
|
|
||||||
) -> Result<bool> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
let (mut url, path) = extract_minecraft_local_download_info(
|
|
||||||
minecraft_library_metadata,
|
|
||||||
minecraft_version,
|
|
||||||
)?;
|
|
||||||
let full_path = state.directories.libraries_dir().join(path);
|
|
||||||
|
|
||||||
if !is_mojang {
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • Attempting to download AuthLib from Git Astralium"
|
|
||||||
);
|
|
||||||
(_, url) = extract_elyby_authlib_metadata(authlib_fullname).await?;
|
|
||||||
}
|
|
||||||
tracing::info!("[AR] • Downloading AuthLib from URL: {}", url);
|
|
||||||
let bytes = fetch_bytes_from_url(&url).await?;
|
|
||||||
tracing::info!("[AR] • Will save to path: {}", full_path.to_str().unwrap());
|
|
||||||
write_file_to_libraries(full_path.to_str().unwrap(), &bytes).await?;
|
|
||||||
tracing::info!("[AR] • Successfully saved AuthLib to {:?}", full_path);
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ### AR • AuthLib (Ely.by)
|
|
||||||
/// Parses the ElyIntegration release JSON and returns the download URL for the given AuthLib version.
|
/// Parses the ElyIntegration release JSON and returns the download URL for the given AuthLib version.
|
||||||
async fn extract_elyby_authlib_metadata(
|
async fn extract_metadata_from_elyby_file(
|
||||||
authlib_fullname: &str,
|
file_name: &str,
|
||||||
) -> Result<(String, String)> {
|
) -> Result<(String, String)> {
|
||||||
const URL: &str = "https://git.astralium.su/api/v1/repos/didirus/ElyIntegration/releases/latest";
|
const URL: &str = "https://git.astralium.su/api/v1/repos/didirus/ElyIntegration/releases/latest";
|
||||||
|
|
||||||
@@ -351,14 +176,14 @@ async fn extract_elyby_authlib_metadata(
|
|||||||
.find(|a| {
|
.find(|a| {
|
||||||
a.get("name")
|
a.get("name")
|
||||||
.and_then(|n| n.as_str())
|
.and_then(|n| n.as_str())
|
||||||
.map(|n| n.contains(authlib_fullname))
|
.map(|n| n.contains(file_name))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
crate::ErrorKind::ParseError {
|
crate::ErrorKind::ParseError {
|
||||||
reason: format!(
|
reason: format!(
|
||||||
"No matching asset for {} in ElyIntegration JSON response.",
|
"No matching asset for {} in ElyIntegration JSON response.",
|
||||||
authlib_fullname
|
file_name
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
.as_error()
|
.as_error()
|
||||||
@@ -389,49 +214,104 @@ async fn extract_elyby_authlib_metadata(
|
|||||||
Ok((asset_name, download_url))
|
Ok((asset_name, download_url))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • AuthLib (Ely.by)
|
/// Applying migration fix for SQLite database.
|
||||||
/// Extracts the artifact URL and Path from the library structure.
|
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||||
///
|
tracing::info!("[AR] • Attempting to apply migration fix");
|
||||||
/// Returns a tuple of references to the URL and path strings,
|
let patched = db::apply_migration_fix(eol).await?;
|
||||||
/// or an error if the required metadata is missing.
|
if patched {
|
||||||
fn extract_minecraft_local_download_info(
|
tracing::info!("[AR] • Successfully applied migration fix");
|
||||||
minecraft_library_metadata: &Library,
|
} else {
|
||||||
minecraft_version: &str,
|
tracing::error!("[AR] • Failed to apply migration fix");
|
||||||
) -> Result<(String, String)> {
|
}
|
||||||
let artifact = minecraft_library_metadata
|
Ok(patched)
|
||||||
.downloads
|
}
|
||||||
.as_ref()
|
|
||||||
.and_then(|d| d.artifact.as_ref())
|
/// Initialize the update launcher.
|
||||||
.ok_or_else(|| {
|
pub async fn init_update_launcher(
|
||||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
download_url: &str,
|
||||||
minecraft_version: minecraft_version.to_string(),
|
local_filename: &str,
|
||||||
}
|
os_type: &str,
|
||||||
.as_error()
|
auto_update_supported: bool,
|
||||||
})?;
|
) -> Result<()> {
|
||||||
|
tracing::info!("[AR] • Initialize downloading from • {:?}", download_url);
|
||||||
let url = artifact.url.clone().ok_or_else(|| {
|
tracing::info!("[AR] • Save local file name • {:?}", local_filename);
|
||||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
tracing::info!("[AR] • OS type • {}", os_type);
|
||||||
minecraft_version: minecraft_version.to_string(),
|
tracing::info!("[AR] • Auto update supported • {}", auto_update_supported);
|
||||||
}
|
|
||||||
.as_error()
|
if let Err(e) = update::get_resource(
|
||||||
})?;
|
download_url,
|
||||||
|
local_filename,
|
||||||
let path = artifact.path.clone().ok_or_else(|| {
|
os_type,
|
||||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
auto_update_supported,
|
||||||
minecraft_version: minecraft_version.to_string(),
|
)
|
||||||
}
|
.await
|
||||||
.as_error()
|
{
|
||||||
})?;
|
eprintln!(
|
||||||
|
"[AR] • An error occurred! Failed to download the file: {}",
|
||||||
Ok((url, path))
|
e
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("[AR] • Code finishes without errors.");
|
||||||
|
process::exit(0)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validating the `astralrinth/{target_directory}/` directory exists inside the libraries/astralrinth directory.
|
||||||
|
async fn validate_library_dir(
|
||||||
|
libraries_dir: &PathBuf,
|
||||||
|
validation_directory: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let astralrinth_path =
|
||||||
|
libraries_dir.join(format!("astralrinth/{}", validation_directory));
|
||||||
|
if !astralrinth_path.exists() {
|
||||||
|
tokio::fs::create_dir_all(&astralrinth_path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
tracing::error!(
|
||||||
|
"[AR] • Failed to create {} directory: {:?}",
|
||||||
|
astralrinth_path.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
crate::ErrorKind::IOErrorOccurred {
|
||||||
|
error: format!(
|
||||||
|
"Failed to create {} directory: {}",
|
||||||
|
astralrinth_path.display(),
|
||||||
|
e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.as_error()
|
||||||
|
})?;
|
||||||
|
tracing::info!(
|
||||||
|
"[AR] • Created missing {} directory",
|
||||||
|
astralrinth_path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saves the downloaded bytes to the `libraries` directory using the given relative path.
|
||||||
|
async fn write_file_to_libraries(
|
||||||
|
relative_path: &str,
|
||||||
|
bytes: &bytes::Bytes,
|
||||||
|
) -> Result<()> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let output_path = state.directories.libraries_dir().join(relative_path);
|
||||||
|
|
||||||
|
fs::write(&output_path, bytes).await.map_err(|e| {
|
||||||
|
tracing::error!("[AR] • Failed to save file: {:?}", e);
|
||||||
|
crate::ErrorKind::IOErrorOccurred {
|
||||||
|
error: format!("Failed to save file: {e}"),
|
||||||
|
}
|
||||||
|
.as_error()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • Universal Fetch Bytes (IO)
|
|
||||||
/// Downloads bytes from the provided URL with a 15 second timeout.
|
/// Downloads bytes from the provided URL with a 15 second timeout.
|
||||||
async fn fetch_bytes_from_url(url: &str) -> Result<bytes::Bytes> {
|
async fn fetch_bytes_from_url(url: &str) -> Result<bytes::Bytes> {
|
||||||
// Create client instance with request timeout.
|
// Create client instance with request timeout.
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
const TIMEOUT_SECONDS: u64 = 15;
|
const TIMEOUT_SECONDS: u64 = 5;
|
||||||
|
|
||||||
let response = tokio::time::timeout(
|
let response = tokio::time::timeout(
|
||||||
std::time::Duration::from_secs(TIMEOUT_SECONDS),
|
std::time::Duration::from_secs(TIMEOUT_SECONDS),
|
||||||
@@ -476,60 +356,3 @@ async fn fetch_bytes_from_url(url: &str) -> Result<bytes::Bytes> {
|
|||||||
.as_error()
|
.as_error()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### AR • AuthLib (Ely.by)
|
|
||||||
/// Gets the Minecraft library metadata from the local libraries directory.
|
|
||||||
async fn get_minecraft_library_metadata(
|
|
||||||
minecraft_version: &str,
|
|
||||||
) -> Result<Library> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
|
|
||||||
let path = state
|
|
||||||
.directories
|
|
||||||
.version_dir(minecraft_version)
|
|
||||||
.join(format!("{}.json", minecraft_version));
|
|
||||||
if !path.exists() {
|
|
||||||
tracing::error!("[AR] • File not found: {:#?}", path);
|
|
||||||
return Err(crate::ErrorKind::InvalidMinecraftVersion {
|
|
||||||
minecraft_version: minecraft_version.to_string(),
|
|
||||||
}
|
|
||||||
.as_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = fs::read_to_string(&path).await?;
|
|
||||||
let version_data: VersionJson = serde_json::from_str(&content)?;
|
|
||||||
|
|
||||||
for lib in version_data.libraries {
|
|
||||||
if lib.name.contains("com.mojang:authlib") {
|
|
||||||
if let Some(downloads) = &lib.downloads {
|
|
||||||
if let Some(artifact) = &downloads.artifact {
|
|
||||||
if artifact.path.is_some()
|
|
||||||
&& artifact.url.is_some()
|
|
||||||
&& artifact.sha1.is_some()
|
|
||||||
{
|
|
||||||
tracing::info!("[AR] • Found AuthLib: {}", lib.name);
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • Path: {}",
|
|
||||||
artifact.path.as_ref().unwrap()
|
|
||||||
);
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • URL: {}",
|
|
||||||
artifact.url.as_ref().unwrap()
|
|
||||||
);
|
|
||||||
tracing::info!(
|
|
||||||
"[AR] • SHA1: {}",
|
|
||||||
artifact.sha1.as_ref().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
return Ok(lib);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(crate::ErrorKind::MinecraftMetadataNotFound {
|
|
||||||
minecraft_version: minecraft_version.to_string(),
|
|
||||||
}
|
|
||||||
.as_error())
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user