diff --git a/apps/desktop/src/api/commands.rs b/apps/desktop/src/api/commands.rs index 73e25a68..9cfafd37 100644 --- a/apps/desktop/src/api/commands.rs +++ b/apps/desktop/src/api/commands.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use std::str::FromStr; use interpulse::api::minecraft::Version; +use onelauncher::api::logger; use onelauncher::data::{Loader, ManagedPackage, MinecraftCredentials, PackageData, Settings}; use onelauncher::package::content; use onelauncher::store::{Cluster, ClusterPath}; @@ -183,7 +184,11 @@ pub async fn get_cluster(uuid: Uuid) -> Result { #[tauri::command] pub async fn get_cluster_logs(uuid: Uuid) -> Result, String> { let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let logs = cluster::get_logs(&cluster.cluster_path()).await?; + let logs = logger::get_logs(&cluster.cluster_path(), None) + .await? + .iter() + .map(|x| x.log_file.clone()) + .collect(); Ok(logs) } @@ -191,15 +196,19 @@ pub async fn get_cluster_logs(uuid: Uuid) -> Result, String> { #[tauri::command] pub async fn get_cluster_log(uuid: Uuid, log_name: String) -> Result { let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let log = cluster::get_log(&cluster.cluster_path(), log_name).await?; - Ok(log) + let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) + .await?; + Ok(log.0) } #[specta::specta] #[tauri::command] pub async fn upload_log(uuid: Uuid, log_name: String) -> Result { let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let id = cluster::upload_log(&cluster.cluster_path(), log_name).await?; + let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) + .await?; + + let id = logger::upload_log(&cluster.cluster_path(), log).await?; Ok(id) } diff --git a/packages/core/src/api/cluster/mod.rs b/packages/core/src/api/cluster/mod.rs index 76870465..de49ddf2 100644 --- a/packages/core/src/api/cluster/mod.rs +++ b/packages/core/src/api/cluster/mod.rs @@ -8,12 +8,10 @@ use crate::proxy::send::send_cluster; use crate::proxy::ClusterPayloadType; use crate::store::ProcessorChild; -// use crate::package::from::{EnvType, PackDependency, PackFile, PackFileHash, PackFormat}; use crate::prelude::{ClusterPath, JavaVersion, PackagePath}; use crate::store::MinecraftCredentials; pub use crate::store::{Cluster, JavaOptions, State}; -use crate::utils::http; use crate::utils::io::{self, IOError}; use std::collections::HashMap; @@ -240,91 +238,6 @@ pub async fn get_mod_path( .into()) } -/// Get log names for a specific cluster by it's [`ClusterPath`]. -#[tracing::instrument] -pub async fn get_logs(path: &ClusterPath) -> crate::Result> { - let logs_dir = path.full_path().await?.join("logs"); - let mut logs = io::read_dir(logs_dir).await?; - let mut log_names: Vec = vec![]; - - while let Some(log) = logs.next_entry().await? { - if log.file_type().await?.is_file() { - let file_name = log.file_name().to_string_lossy().to_string(); - - if file_name == "latest.log" { - log_names.insert(0, file_name); - continue; - } - - log_names.push(file_name); - } - } - - Ok(log_names) -} - -/// Get a log for a specific cluster by it's [`ClusterPath`] and log [`PathBuf`]. -#[tracing::instrument] -pub async fn get_log(path: &ClusterPath, log_name: String) -> crate::Result { - let log_path = path.full_path().await?.join("logs").join(log_name); - - if !log_path.exists() { - return Err(anyhow::anyhow!( - "failed to get log at path {}", - log_path.display() - ) - .into()); - } - - if let Some(ext) = log_path.extension() { - if ext == "gz" { - let log = io::read_gz_to_string(&log_path).await?; - return Ok(log); - } - } - - let log = io::read_to_string(&log_path).await?; - Ok(log) -} - -/// Upload a log to https://mclo.gs/. If successful, it returns the log id -#[tracing::instrument] -pub async fn upload_log(path: &ClusterPath, log_name: String) -> crate::Result { - let log = get_log(path, log_name).await?; - - let mut form = HashMap::new(); - form.insert("content", log); - - #[derive(serde::Deserialize)] - struct ResponseBody { - pub success: bool, - #[serde(default)] - pub id: Option, - #[serde(default)] - pub error: Option - } - - let parsed = serde_json::from_slice::( - &http::REQWEST_CLIENT.post(format!("{}/log", crate::constants::MCLOGS_API_URL)) - .header("Content-Type", "application/x-www-form-urlencoded") - .form(&form) - .send() - .await? - .bytes() - .await? - )?; - - if parsed.success { - if let Some(id) = parsed.id { - Ok(id) - } else { - Err(anyhow::anyhow!("failed to get log id from mclo.gs").into()) - } - } else { - Err(anyhow::anyhow!("failed to upload log to mclo.gs: {}", parsed.error.unwrap_or_default()).into()) - } -} - /// edit a cluster with an async closure and it's [`ClusterPath`] pub async fn edit( path: &ClusterPath, diff --git a/packages/core/src/api/logger.rs b/packages/core/src/api/logger.rs index a7cc8bd7..0c3464dc 100644 --- a/packages/core/src/api/logger.rs +++ b/packages/core/src/api/logger.rs @@ -2,9 +2,11 @@ use crate::data::{Credentials, Directories, MinecraftCredentials}; use crate::prelude::ClusterPath; +use crate::utils::http; use crate::utils::io::{self, IOError}; use futures::TryFutureExt; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use std::io::Read; use std::time::SystemTime; use tokio::io::{AsyncReadExt, AsyncSeekExt}; @@ -94,14 +96,12 @@ pub async fn get_logs_by_type( /// Get all [`LogManager`]s in the global [`State`]. pub async fn get_logs( - cluster_path: ClusterPath, + cluster_path: &ClusterPath, clear: Option, ) -> crate::Result> { - let cluster_path = cluster_path.cluster_path().await?; - let mut logs = Vec::new(); - get_logs_by_type(&cluster_path, LogType::Info, clear, &mut logs).await?; - get_logs_by_type(&cluster_path, LogType::Crash, clear, &mut logs).await?; + get_logs_by_type(cluster_path, LogType::Info, clear, &mut logs).await?; + get_logs_by_type(cluster_path, LogType::Crash, clear, &mut logs).await?; let mut logs = logs .into_iter() @@ -302,7 +302,7 @@ pub struct LogCursor { /// The log output, a wrapper around [`String`], with utilities for parsing and censoring log contents. #[derive(Serialize, Debug)] #[serde(transparent)] -pub struct LogOutput(String); +pub struct LogOutput(pub String); impl LogOutput { /// Censor user secrets because sometimes mclogs misses them, including username, realname and minecraft credentials. @@ -328,3 +328,40 @@ impl LogOutput { Self(output) } } + +/// Upload a log to https://mclo.gs/. If successful, it returns the log id +#[tracing::instrument] +pub async fn upload_log(path: &ClusterPath, log: LogOutput) -> crate::Result { + let log = log.0; + let mut form = HashMap::new(); + form.insert("content", log); + + #[derive(serde::Deserialize)] + struct ResponseBody { + pub success: bool, + #[serde(default)] + pub id: Option, + #[serde(default)] + pub error: Option + } + + let parsed = serde_json::from_slice::( + &http::REQWEST_CLIENT.post(format!("{}/log", crate::constants::MCLOGS_API_URL)) + .header("Content-Type", "application/x-www-form-urlencoded") + .form(&form) + .send() + .await? + .bytes() + .await? + )?; + + if parsed.success { + if let Some(id) = parsed.id { + Ok(id) + } else { + Err(anyhow::anyhow!("failed to get log id from mclo.gs").into()) + } + } else { + Err(anyhow::anyhow!("failed to upload log to mclo.gs: {}", parsed.error.unwrap_or_default()).into()) + } +}