refactor: remove init_authlib_patching function and update related references

This commit is contained in:
2026-01-28 01:06:48 +03:00
parent 3e5ef753e0
commit eef238c1bb
8 changed files with 210 additions and 402 deletions

View File

@@ -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')
}

View File

@@ -228,7 +228,6 @@ fn main() {
"utils",
InlinedPlugin::new()
.commands(&[
"init_authlib_patching",
"apply_migration_fix",
"init_update_launcher",
"get_os",

View File

@@ -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(

View File

@@ -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> {

View File

@@ -48,7 +48,7 @@
]
},
"productName": "AstralRinth App",
"version": "0.10.2401",
"version": "0.10.2701",
"mainBinaryName": "AstralRinth App",
"identifier": "AstralRinthApp",
"plugins": {

View File

@@ -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 {}",
"[AR] Launching minecraft instance with {}",
path
)
).await;
))
.await;
command.arg(format!("-javaagent:{}=ely.by", path));
}

View File

@@ -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));

View File

@@ -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 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(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));
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
if !local_injectors.is_empty() {
tracing::info!("[AR] • Local versions:");
for (path, mtime) in &local_injectors {
tracing::info!(" • {:?} ({:?})", path.file_name().unwrap(), mtime);
}
}
// 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());
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())
}
};
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);
}
}
let remote_authlib_injector = if !asset_name.is_empty() {
authlib_injector_dir.join(&asset_name)
let remote_path = if !remote_name.is_empty() {
Some(injector_dir.join(&remote_name))
} else {
return Err(crate::ErrorKind::ParseError { reason: "Asset name is empty from metadata".to_string() }.as_error());
None
};
let latest_local_authlib_injector = local_authlib_injectors
.first()
.map(|(p, _)| p.clone());
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);
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 Some(rp) = remote_path else {
return Err(crate::ErrorKind::NetworkErrorOccurred {
error: "No local injector & remote unavailable".to_string(),
}
.as_error());
};
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());
let fname = rp.file_name().unwrap().to_string_lossy();
tracing::info!("[AR] • Downloading: {}", fname);
let _ = emit_info(&format!("[AR] Downloading: {}", fname)).await;
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);
}
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] • 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(),
/// 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(())
}
let url = artifact.url.clone().ok_or_else(|| {
crate::ErrorKind::MinecraftMetadataNotFound {
minecraft_version: minecraft_version.to_string(),
/// 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()
})?;
let path = artifact.path.clone().ok_or_else(|| {
crate::ErrorKind::MinecraftMetadataNotFound {
minecraft_version: minecraft_version.to_string(),
}
.as_error()
})?;
Ok((url, path))
})
}
/// ### 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())
}