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 })
|
||||
}
|
||||
|
||||
// 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() {
|
||||
return await invoke('plugin:utils|is_network_metered')
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@ fn main() {
|
||||
"utils",
|
||||
InlinedPlugin::new()
|
||||
.commands(&[
|
||||
"init_authlib_patching",
|
||||
"apply_migration_fix",
|
||||
"init_update_launcher",
|
||||
"get_os",
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.build()
|
||||
}
|
||||
|
||||
/// ### AR • Feature
|
||||
/// This code is modified by AstralRinth
|
||||
/// Create new offline user
|
||||
#[tauri::command]
|
||||
pub async fn offline_login(name: &str) -> Result<Credentials> {
|
||||
@@ -29,7 +29,7 @@ pub async fn offline_login(name: &str) -> Result<Credentials> {
|
||||
Ok(credentials)
|
||||
}
|
||||
|
||||
/// ### AR • Feature
|
||||
/// This code is modified by AstralRinth
|
||||
/// Create new Ely.by user
|
||||
#[tauri::command]
|
||||
pub async fn elyby_login(
|
||||
@@ -41,7 +41,7 @@ pub async fn elyby_login(
|
||||
Ok(credentials)
|
||||
}
|
||||
|
||||
/// ### AR • Feature
|
||||
/// This code is modified by AstralRinth
|
||||
/// Authenticate Ely.by user
|
||||
#[tauri::command]
|
||||
pub async fn elyby_auth_authenticate(
|
||||
|
||||
@@ -16,7 +16,6 @@ use url::Url;
|
||||
pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("utils")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
init_authlib_patching,
|
||||
apply_migration_fix,
|
||||
init_update_launcher,
|
||||
get_os,
|
||||
@@ -31,17 +30,6 @@ pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
.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
|
||||
#[tauri::command]
|
||||
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
]
|
||||
},
|
||||
"productName": "AstralRinth App",
|
||||
"version": "0.10.2401",
|
||||
"version": "0.10.2701",
|
||||
"mainBinaryName": "AstralRinth App",
|
||||
"identifier": "AstralRinthApp",
|
||||
"plugins": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Logic for launching Minecraft
|
||||
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::launcher::download::download_log_config;
|
||||
use crate::launcher::io::IOError;
|
||||
@@ -11,8 +11,8 @@ use crate::profile::QuickPlayType;
|
||||
use crate::state::{
|
||||
AccountType, Credentials, JavaVersion, ProcessMetadata, ProfileInstallStage,
|
||||
};
|
||||
use crate::util::{io, utils};
|
||||
use crate::util::rpc::RpcServerBuilder;
|
||||
use crate::util::{io, utils};
|
||||
use crate::{State, get_resource_file, process, state as st};
|
||||
use chrono::Utc;
|
||||
use daedalus as d;
|
||||
@@ -671,30 +671,33 @@ pub async fn launch_minecraft(
|
||||
if version_jar == "1.16.4" || version_jar == "1.16.5" {
|
||||
let invalid_url = "https://invalid.invalid";
|
||||
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
|
||||
)
|
||||
).await;
|
||||
command.arg("-Dminecraft.api.env=custom");
|
||||
command.arg(format!("-Dminecraft.api.auth.host={}", invalid_url));
|
||||
command.arg(format!("-Dminecraft.api.account.host={}", invalid_url));
|
||||
command.arg(format!("-Dminecraft.api.session.host={}", invalid_url));
|
||||
command.arg(format!("-Dminecraft.api.services.host={}", invalid_url));
|
||||
command
|
||||
.arg(format!("-Dminecraft.api.account.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()
|
||||
{
|
||||
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
|
||||
)
|
||||
).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 _ = emit_info(&format!(
|
||||
"[AR] • Launching minecraft instance with {}",
|
||||
let _ = emit_info(&format!(
|
||||
"[AR] Launching minecraft instance with {}",
|
||||
path
|
||||
)
|
||||
).await;
|
||||
))
|
||||
.await;
|
||||
command.arg(format!("-javaagent:{}=ely.by", path));
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ impl DiscordGuard {
|
||||
.large_image("astralrinth_logo")
|
||||
.large_text(&build_info)
|
||||
.small_image("astralrinth_logo")
|
||||
.small_text(&build_download),
|
||||
.small_text(build_download),
|
||||
)
|
||||
.timestamps(Timestamps::new().start(time));
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use crate::api::update;
|
||||
use crate::state::db;
|
||||
///
|
||||
/// 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 serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
@@ -16,301 +19,123 @@ const PACKAGE_JSON_CONTENT: &str =
|
||||
// include_str!("../../../../apps/app-frontend/package.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
|
||||
pub fn read_package_json() -> io::Result<Launcher> {
|
||||
let launcher: Launcher = serde_json::from_str(PACKAGE_JSON_CONTENT)?;
|
||||
Ok(launcher)
|
||||
}
|
||||
|
||||
/// ### AR • Ely.by Injector
|
||||
/// Returns the PathBuf to the Ely.by AuthLib Injector
|
||||
/// If resource doesn't exist or outdated, it will be downloaded from Git Astralium.
|
||||
pub async fn get_or_download_elyby_injector() -> Result<PathBuf> {
|
||||
tracing::info!("[AR] • Initializing state for Ely.by AuthLib Injector...");
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Launcher {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
/// 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 libraries_dir = state.directories.libraries_dir();
|
||||
|
||||
// Stores the local authlib injectors from `libraries/astralrinth/authlib_injectors/` directory.
|
||||
let mut local_authlib_injectors = Vec::new();
|
||||
validate_library_dir(&libraries_dir, "authlib_injector/").await?;
|
||||
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 astralrinth_dir = libraries_dir.join("astralrinth/");
|
||||
let authlib_injector_dir = astralrinth_dir.join("authlib_injector/");
|
||||
let mut authlib_injector_dir_data = fs::read_dir(&authlib_injector_dir).await?;
|
||||
|
||||
// Get all local authlib injectors
|
||||
while let Some(entry) = authlib_injector_dir_data.next_entry().await? {
|
||||
let path = entry.path();
|
||||
if let Some(file_name) = path.file_name().and_then(|s| s.to_str()) {
|
||||
if file_name.starts_with("authlib-injector") {
|
||||
let metadata = entry.metadata().await?;
|
||||
let modified = metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH);
|
||||
local_authlib_injectors.push((path.clone(), modified));
|
||||
let mut local_injectors = Vec::new();
|
||||
if let Ok(mut entries) = fs::read_dir(&injector_dir).await {
|
||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||
let path = entry.path();
|
||||
if let (Some(name), Ok(meta)) = (
|
||||
path.file_name().and_then(|s| s.to_str()),
|
||||
entry.metadata().await,
|
||||
) {
|
||||
if name.starts_with("authlib-injector") {
|
||||
local_injectors.push((
|
||||
path,
|
||||
meta.modified().unwrap_or(SystemTime::UNIX_EPOCH),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
local_injectors.sort_by(|a, b| b.1.cmp(&a.1)); // newest first
|
||||
|
||||
// Get information about latest authlib injector from remote repository
|
||||
let (asset_name, download_url) = match extract_elyby_authlib_metadata("authlib-injector").await {
|
||||
Ok(data) => data,
|
||||
Err(err) => {
|
||||
if let Some((local_path, _)) = local_authlib_injectors
|
||||
.iter()
|
||||
.max_by(|a, b| a.1.cmp(&b.1))
|
||||
{
|
||||
tracing::info!("[AR] • Found local AuthLib Injector(s):");
|
||||
for (path, time) in &local_authlib_injectors {
|
||||
tracing::info!("• {:?} (modified: {:?})", path.file_name().unwrap(), time);
|
||||
}
|
||||
tracing::warn!("[AR] • Failed to get latest AuthLib Injector from remote, using latest local version: {}", local_path.display());
|
||||
return Ok(local_path.clone());
|
||||
} else {
|
||||
tracing::error!("[AR] • Failed to get AuthLib Injector from remote and no local copy found.");
|
||||
return Err(crate::ErrorKind::NetworkErrorOccurred { error: format!("Failed to fetch authlib-injector metadata and no local version available: {}", err) }.as_error());
|
||||
if !local_injectors.is_empty() {
|
||||
tracing::info!("[AR] • Local versions:");
|
||||
for (path, mtime) in &local_injectors {
|
||||
tracing::info!(" • {:?} ({:?})", path.file_name().unwrap(), mtime);
|
||||
}
|
||||
}
|
||||
|
||||
let latest_local = local_injectors.first().cloned();
|
||||
// let latest_local_name = latest_local.as_ref().map(|p| p.0.file_name().unwrap().to_string_lossy().to_string());
|
||||
|
||||
// Remote (fallback to empty strings)
|
||||
let (remote_name, remote_url) =
|
||||
match extract_metadata_from_elyby_file("authlib-injector").await {
|
||||
Ok(data) => {
|
||||
tracing::info!("[AR] • Remote: {} ({})", data.0, data.1);
|
||||
data
|
||||
}
|
||||
}
|
||||
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() {
|
||||
local_authlib_injectors.sort_by(|a, b| a.1.cmp(&b.1));
|
||||
tracing::info!("[AR] • Found local AuthLib Injector(s):");
|
||||
for (path, time) in &local_authlib_injectors {
|
||||
tracing::info!("• {:?} (modified: {:?})", path.file_name().unwrap(), time);
|
||||
if let Some(local_path) = &latest_local {
|
||||
let local_name = local_path.0.file_name().unwrap().to_string_lossy();
|
||||
if let Some(rp) = &remote_path {
|
||||
let remote_name = rp.file_name().unwrap().to_string_lossy();
|
||||
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() {
|
||||
authlib_injector_dir.join(&asset_name)
|
||||
} else {
|
||||
return Err(crate::ErrorKind::ParseError { reason: "Asset name is empty from metadata".to_string() }.as_error());
|
||||
let Some(rp) = remote_path else {
|
||||
return Err(crate::ErrorKind::NetworkErrorOccurred {
|
||||
error: "No local injector & remote unavailable".to_string(),
|
||||
}
|
||||
.as_error());
|
||||
};
|
||||
|
||||
let latest_local_authlib_injector = local_authlib_injectors
|
||||
.first()
|
||||
.map(|(p, _)| p.clone());
|
||||
let fname = rp.file_name().unwrap().to_string_lossy();
|
||||
tracing::info!("[AR] • Downloading: {}", fname);
|
||||
let _ = emit_info(&format!("[AR] Downloading: {}", fname)).await;
|
||||
|
||||
let latest_local_authlib_injector_full_path_buf = match latest_local_authlib_injector {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
tracing::info!("[AR] • No local version found, will download from remote: {}", remote_authlib_injector.display());
|
||||
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);
|
||||
}
|
||||
};
|
||||
let bytes = fetch_bytes_from_url(&remote_url).await?;
|
||||
let rel_path = rp
|
||||
.strip_prefix(&libraries_dir)?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
write_file_to_libraries(&rel_path, &bytes).await?;
|
||||
|
||||
tracing::info!("[AR] • Remote Asset name: {}", asset_name);
|
||||
tracing::info!("[AR] • Remote Download URL: {}", download_url);
|
||||
tracing::info!("[AR] • Latest local AuthLib Injector: {}", latest_local_authlib_injector_full_path_buf.file_name().unwrap().to_string_lossy());
|
||||
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);
|
||||
}
|
||||
tracing::info!("[AR] • Saved: {}", rp.display());
|
||||
let _ = emit_info(&format!("[AR] Saved: {}", rp.display())).await;
|
||||
Ok(rp.to_path_buf())
|
||||
}
|
||||
|
||||
/// ### 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.
|
||||
async fn extract_elyby_authlib_metadata(
|
||||
authlib_fullname: &str,
|
||||
async fn extract_metadata_from_elyby_file(
|
||||
file_name: &str,
|
||||
) -> Result<(String, String)> {
|
||||
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| {
|
||||
a.get("name")
|
||||
.and_then(|n| n.as_str())
|
||||
.map(|n| n.contains(authlib_fullname))
|
||||
.map(|n| n.contains(file_name))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
crate::ErrorKind::ParseError {
|
||||
reason: format!(
|
||||
"No matching asset for {} in ElyIntegration JSON response.",
|
||||
authlib_fullname
|
||||
file_name
|
||||
),
|
||||
}
|
||||
.as_error()
|
||||
@@ -389,49 +214,104 @@ async fn extract_elyby_authlib_metadata(
|
||||
Ok((asset_name, download_url))
|
||||
}
|
||||
|
||||
/// ### AR • AuthLib (Ely.by)
|
||||
/// Extracts the artifact URL and Path from the library structure.
|
||||
///
|
||||
/// Returns a tuple of references to the URL and path strings,
|
||||
/// or an error if the required metadata is missing.
|
||||
fn extract_minecraft_local_download_info(
|
||||
minecraft_library_metadata: &Library,
|
||||
minecraft_version: &str,
|
||||
) -> Result<(String, String)> {
|
||||
let artifact = minecraft_library_metadata
|
||||
.downloads
|
||||
.as_ref()
|
||||
.and_then(|d| d.artifact.as_ref())
|
||||
.ok_or_else(|| {
|
||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
||||
minecraft_version: minecraft_version.to_string(),
|
||||
}
|
||||
.as_error()
|
||||
})?;
|
||||
|
||||
let url = artifact.url.clone().ok_or_else(|| {
|
||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
||||
minecraft_version: minecraft_version.to_string(),
|
||||
}
|
||||
.as_error()
|
||||
})?;
|
||||
|
||||
let path = artifact.path.clone().ok_or_else(|| {
|
||||
crate::ErrorKind::MinecraftMetadataNotFound {
|
||||
minecraft_version: minecraft_version.to_string(),
|
||||
}
|
||||
.as_error()
|
||||
})?;
|
||||
|
||||
Ok((url, path))
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// 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(())
|
||||
}
|
||||
|
||||
/// 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.
|
||||
async fn fetch_bytes_from_url(url: &str) -> Result<bytes::Bytes> {
|
||||
// Create client instance with request timeout.
|
||||
let client = reqwest::Client::new();
|
||||
const TIMEOUT_SECONDS: u64 = 15;
|
||||
const TIMEOUT_SECONDS: u64 = 5;
|
||||
|
||||
let response = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(TIMEOUT_SECONDS),
|
||||
@@ -476,60 +356,3 @@ async fn fetch_bytes_from_url(url: &str) -> Result<bytes::Bytes> {
|
||||
.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