diff --git a/.github/workflows/theseus-build.yml b/.github/workflows/theseus-build.yml index 287f5b6de..550f402f6 100644 --- a/.github/workflows/theseus-build.yml +++ b/.github/workflows/theseus-build.yml @@ -19,7 +19,7 @@ on: sign-windows-binaries: description: Sign Windows binaries type: boolean - default: true + default: false required: false jobs: @@ -40,33 +40,48 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - name: 📥 Check out code + - name: Check out code uses: actions/checkout@v4 with: fetch-depth: 0 - - name: 🧰 Setup Rust toolchain + - name: Setup Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: rustflags: '' target: ${{ startsWith(matrix.platform, 'macos') && 'x86_64-apple-darwin' || '' }} - - name: 🧰 Install pnpm + - name: Install pnpm uses: pnpm/action-setup@v4 - - name: 🧰 Setup Node.js + - name: Setup Node.js uses: actions/setup-node@v4 with: node-version-file: .nvmrc cache: pnpm - - name: 🧰 Install Linux build dependencies + - name: Generate tauri-dev.conf.json + shell: bash + run: | + GIT_HASH=$(git rev-parse --short HEAD) + cat > apps/app/tauri-dev.conf.json < theseus::Result { async fn main() -> theseus::Result<()> { println!("Starting."); - let _log_guard = theseus::start_logger(); + let _log_guard = theseus::start_logger("ModrinthApp"); // Initialize state - State::init().await?; + State::init("ModrinthApp".to_owned()).await?; let worlds = get_recent_worlds(4, EnumSet::all()).await?; for world in worlds { diff --git a/apps/app/src/api/settings.rs b/apps/app/src/api/settings.rs index 7a184536c..ccfcdf38a 100644 --- a/apps/app/src/api/settings.rs +++ b/apps/app/src/api/settings.rs @@ -29,6 +29,9 @@ pub async fn settings_set(settings: Settings) -> Result<()> { #[tauri::command] pub async fn cancel_directory_change() -> Result<()> { - settings::cancel_directory_change().await?; + let state = State::get().await?; + let identifier = &state.app_identifier; + + settings::cancel_directory_change(identifier).await?; Ok(()) } diff --git a/apps/app/src/api/utils.rs b/apps/app/src/api/utils.rs index 1f7195a4e..6487d259a 100644 --- a/apps/app/src/api/utils.rs +++ b/apps/app/src/api/utils.rs @@ -107,10 +107,12 @@ pub async fn open_path(app: tauri::AppHandle, path: PathBuf) { #[tauri::command] pub async fn show_launcher_logs_folder(app: tauri::AppHandle) { - let path = DirectoryInfo::launcher_logs_dir().unwrap_or_default(); - // failure to get folder just opens filesystem - // (ie: if in debug mode only and launcher_logs never created) - open_path(app, path).await; + if let Some(d) = DirectoryInfo::global_handle_if_ready() { + let path = d.launcher_logs_dir().unwrap_or_default(); + // failure to get folder just opens filesystem + // (ie: if in debug mode only and launcher_logs never created) + open_path(app, path).await; + } } // Get opening command diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index 663a04c82..4b59e6969 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -28,7 +28,7 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> { theseus::EventState::init(app.clone()).await?; tracing::info!("Initializing app state..."); - State::init().await?; + State::init(app.config().identifier.clone()).await?; let state = State::get().await?; app.asset_protocol_scope() @@ -110,7 +110,10 @@ fn main() { RUST_LOG="theseus=trace" {run command} */ - let _log_guard = theseus::start_logger(); + + let tauri_context = tauri::generate_context!(); + + let _log_guard = theseus::start_logger(&tauri_context.config().identifier); tracing::info!("Initialized tracing subscriber. Loading Modrinth App!"); @@ -243,7 +246,7 @@ fn main() { ]); tracing::info!("Initializing app..."); - let app = builder.build(tauri::generate_context!()); + let app = builder.build(tauri_context); match app { Ok(app) => { diff --git a/packages/app-lib/src/api/settings.rs b/packages/app-lib/src/api/settings.rs index 761959683..b79e2e524 100644 --- a/packages/app-lib/src/api/settings.rs +++ b/packages/app-lib/src/api/settings.rs @@ -23,10 +23,12 @@ pub async fn set(settings: Settings) -> crate::Result<()> { } #[tracing::instrument] -pub async fn cancel_directory_change() -> crate::Result<()> { +pub async fn cancel_directory_change( + app_identifier: &str, +) -> crate::Result<()> { // This is called to handle state initialization errors due to folder migrations // failing, so fetching a DB connection pool from `State::get` is not reliable here - let pool = crate::state::db::connect().await?; + let pool = crate::state::db::connect(app_identifier).await?; let mut settings = Settings::get(&pool).await?; if let Some(prev_custom_dir) = settings.prev_custom_dir { diff --git a/packages/app-lib/src/logger.rs b/packages/app-lib/src/logger.rs index 5efcdc098..fa3d6c6d7 100644 --- a/packages/app-lib/src/logger.rs +++ b/packages/app-lib/src/logger.rs @@ -18,7 +18,7 @@ // Handling for the live development logging // This will log to the console, and will not log to a file #[cfg(debug_assertions)] -pub fn start_logger() -> Option<()> { +pub fn start_logger(_app_identifier: &str) -> Option<()> { use tracing_subscriber::prelude::*; let filter = tracing_subscriber::EnvFilter::try_from_default_env() @@ -36,7 +36,7 @@ pub fn start_logger() -> Option<()> { // Handling for the live production logging // This will log to a file in the logs directory, and will not show any logs in the console #[cfg(not(debug_assertions))] -pub fn start_logger() -> Option<()> { +pub fn start_logger(app_identifier: &str) -> Option<()> { use crate::prelude::DirectoryInfo; use chrono::Local; use std::fs::OpenOptions; @@ -44,7 +44,9 @@ pub fn start_logger() -> Option<()> { use tracing_subscriber::prelude::*; // Initialize and get logs directory path - let logs_dir = if let Some(d) = DirectoryInfo::launcher_logs_dir() { + let logs_dir = if let Some(d) = + DirectoryInfo::launcher_logs_dir_path(app_identifier) + { d } else { eprintln!("Could not start logger"); diff --git a/packages/app-lib/src/state/db.rs b/packages/app-lib/src/state/db.rs index de5464c4c..b2a180560 100644 --- a/packages/app-lib/src/state/db.rs +++ b/packages/app-lib/src/state/db.rs @@ -6,12 +6,13 @@ use sqlx::{Pool, Sqlite}; use std::str::FromStr; use std::time::Duration; -pub(crate) async fn connect() -> crate::Result> { - let settings_dir = DirectoryInfo::get_initial_settings_dir().ok_or( - crate::ErrorKind::FSError( +pub(crate) async fn connect( + app_identifier: &str, +) -> crate::Result> { + let settings_dir = DirectoryInfo::initial_settings_dir_path(app_identifier) + .ok_or(crate::ErrorKind::FSError( "Could not find valid config dir".to_string(), - ), - )?; + ))?; if !settings_dir.exists() { crate::util::io::create_dir_all(&settings_dir).await?; diff --git a/packages/app-lib/src/state/dirs.rs b/packages/app-lib/src/state/dirs.rs index 1f577f7c4..b098dbcac 100644 --- a/packages/app-lib/src/state/dirs.rs +++ b/packages/app-lib/src/state/dirs.rs @@ -1,6 +1,7 @@ //! Theseus directory information use crate::LoadingBarType; use crate::event::emit::{emit_loading, init_loading}; +use crate::state::LAUNCHER_STATE; use crate::state::{JavaVersion, Profile, Settings}; use crate::util::fetch::IoSemaphore; use dashmap::DashSet; @@ -17,24 +18,35 @@ pub const METADATA_FOLDER_NAME: &str = "meta"; pub struct DirectoryInfo { pub settings_dir: PathBuf, // Base settings directory- app database pub config_dir: PathBuf, // Base config directory- instances, minecraft downloads, etc. Changeable as a setting. + pub app_identifier: String, } impl DirectoryInfo { + pub fn global_handle_if_ready() -> Option<&'static Self> { + LAUNCHER_STATE.get().map(|x| &x.directories) + } + + pub fn get_initial_settings_dir(&self) -> Option { + Self::initial_settings_dir_path(&self.app_identifier) + } + // Get the settings directory // init() is not needed for this function - pub fn get_initial_settings_dir() -> Option { + pub fn initial_settings_dir_path(app_identifier: &str) -> Option { Self::env_path("THESEUS_CONFIG_DIR") - .or_else(|| Some(dirs::data_dir()?.join("ModrinthApp"))) + .or_else(|| Some(dirs::data_dir()?.join(app_identifier))) } /// Get all paths needed for Theseus to operate properly #[tracing::instrument] - pub async fn init(config_dir: Option) -> crate::Result { - let settings_dir = Self::get_initial_settings_dir().ok_or( - crate::ErrorKind::FSError( + pub async fn init( + config_dir: Option, + app_identifier: &str, + ) -> crate::Result { + let settings_dir = Self::initial_settings_dir_path(app_identifier) + .ok_or(crate::ErrorKind::FSError( "Could not find valid settings dir".to_string(), - ), - )?; + ))?; fs::create_dir_all(&settings_dir).await.map_err(|err| { crate::ErrorKind::FSError(format!( @@ -48,6 +60,7 @@ impl DirectoryInfo { Ok(Self { settings_dir, config_dir, + app_identifier: app_identifier.to_owned(), }) } @@ -154,8 +167,14 @@ impl DirectoryInfo { } #[inline] - pub fn launcher_logs_dir() -> Option { - Self::get_initial_settings_dir() + pub fn launcher_logs_dir(&self) -> Option { + self.get_initial_settings_dir() + .map(|d| d.join(LAUNCHER_LOGS_FOLDER_NAME)) + } + + #[inline] + pub fn launcher_logs_dir_path(app_identifier: &str) -> Option { + Self::initial_settings_dir_path(app_identifier) .map(|d| d.join(LAUNCHER_LOGS_FOLDER_NAME)) } @@ -176,15 +195,15 @@ impl DirectoryInfo { settings: &mut Settings, exec: E, io_semaphore: &IoSemaphore, + app_identifier: &str, ) -> crate::Result<()> where E: sqlx::Executor<'a, Database = sqlx::Sqlite> + Copy, { - let app_dir = DirectoryInfo::get_initial_settings_dir().ok_or( - crate::ErrorKind::FSError( + let app_dir = DirectoryInfo::initial_settings_dir_path(app_identifier) + .ok_or(crate::ErrorKind::FSError( "Could not find valid config dir".to_string(), - ), - )?; + ))?; if let Some(ref prev_custom_dir) = settings.prev_custom_dir { let prev_dir = PathBuf::from(prev_custom_dir); diff --git a/packages/app-lib/src/state/mod.rs b/packages/app-lib/src/state/mod.rs index 7666218c0..6c3a69126 100644 --- a/packages/app-lib/src/state/mod.rs +++ b/packages/app-lib/src/state/mod.rs @@ -71,6 +71,9 @@ pub struct State { /// Process manager pub process_manager: ProcessManager, + /// App identifier string (like com.modrinth.ModrinthApp) + pub app_identifier: String, + /// Friends socket pub friends_socket: FriendsSocket, @@ -80,9 +83,9 @@ pub struct State { } impl State { - pub async fn init() -> crate::Result<()> { + pub async fn init(app_identifier: String) -> crate::Result<()> { let state = LAUNCHER_STATE - .get_or_try_init(Self::initialize_state) + .get_or_try_init(move || Self::initialize_state(app_identifier)) .await?; tokio::task::spawn(async move { @@ -132,9 +135,11 @@ impl State { } #[tracing::instrument] - async fn initialize_state() -> crate::Result> { + async fn initialize_state( + app_identifier: String, + ) -> crate::Result> { tracing::info!("Connecting to app database"); - let pool = db::connect().await?; + let pool = db::connect(&app_identifier).await?; legacy_converter::migrate_legacy_data(&pool).await?; @@ -153,9 +158,12 @@ impl State { &mut settings, &pool, &io_semaphore, + &app_identifier, ) .await?; - let directories = DirectoryInfo::init(settings.custom_dir).await?; + + let directories = + DirectoryInfo::init(settings.custom_dir, &app_identifier).await?; let discord_rpc = DiscordGuard::init()?; @@ -177,6 +185,7 @@ impl State { friends_socket, pool, file_watcher, + app_identifier, })) } }