diff --git a/.changeset/cool-cooks-call.md b/.changeset/cool-cooks-call.md new file mode 100644 index 0000000..e277a9a --- /dev/null +++ b/.changeset/cool-cooks-call.md @@ -0,0 +1,5 @@ +--- +'@noctisynth/grassator': patch +--- + +Extend `String` to `ErrorPayload` to handle default errors diff --git a/.changeset/early-papayas-melt.md b/.changeset/early-papayas-melt.md new file mode 100644 index 0000000..a30d891 --- /dev/null +++ b/.changeset/early-papayas-melt.md @@ -0,0 +1,5 @@ +--- +'@noctisynth/grassator': patch +--- + +Fix set config arg name to `newConfig` diff --git a/.changeset/hip-sheep-rest.md b/.changeset/hip-sheep-rest.md new file mode 100644 index 0000000..6c33116 --- /dev/null +++ b/.changeset/hip-sheep-rest.md @@ -0,0 +1,6 @@ +--- +'grassator': patch +'@noctisynth/grassator': patch +--- + +Implement config system and auto load on startup diff --git a/.changeset/itchy-lobsters-laugh.md b/.changeset/itchy-lobsters-laugh.md new file mode 100644 index 0000000..3c5e54f --- /dev/null +++ b/.changeset/itchy-lobsters-laugh.md @@ -0,0 +1,5 @@ +--- +'@noctisynth/grassator': patch +--- + +Add global config proxy object diff --git a/.changeset/olive-ways-clean.md b/.changeset/olive-ways-clean.md new file mode 100644 index 0000000..c5d3a5e --- /dev/null +++ b/.changeset/olive-ways-clean.md @@ -0,0 +1,6 @@ +--- +'grassator': patch +'@noctisynth/grassator': patch +--- + +Add config file path to callback data structure diff --git a/cspell.json b/cspell.json index 7041076..0123a82 100644 --- a/cspell.json +++ b/cspell.json @@ -17,7 +17,8 @@ "tauri", "toastservice", "unocss", - "unplugin" + "unplugin", + "usetoast" ], "ignorePaths": [ // Tauri files diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b3553d8..fd62363 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -275,7 +275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" dependencies = [ "serde", - "toml 0.8.2", + "toml 0.8.14", ] [[package]] @@ -665,7 +665,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.8.2", + "toml 0.8.14", "vswhom", "winreg", ] @@ -1106,7 +1106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" dependencies = [ "heck 0.4.1", - "proc-macro-crate 2.0.2", + "proc-macro-crate 2.0.0", "proc-macro-error", "proc-macro2", "quote", @@ -1150,6 +1150,7 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-shell", + "toml 0.8.14", ] [[package]] @@ -2421,11 +2422,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "toml_datetime", "toml_edit 0.20.2", ] @@ -3282,7 +3282,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml 0.8.2", + "toml 0.8.14", "version-compare", ] @@ -3409,7 +3409,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.8.2", + "toml 0.8.14", "walkdir", ] @@ -3467,7 +3467,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.8.2", + "toml 0.8.14", "walkdir", ] @@ -3564,7 +3564,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror", - "toml 0.8.2", + "toml 0.8.14", "url", "urlpattern", "walkdir", @@ -3749,21 +3749,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.22.15", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -3778,7 +3778,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -3786,12 +3786,23 @@ name = "toml_edit" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.13", ] [[package]] @@ -4616,6 +4627,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.52.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c7538f6..b02d3bd 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -20,3 +20,4 @@ tauri-plugin-shell = "2.0.0-beta" serde = { version = "1", features = ["derive"] } serde_json = "1" reqwest = "0.12.5" +toml = "0.8.14" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0e2d3e6..0b94fa7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,10 +1,53 @@ +use models::ErrorPayload; + mod models; mod state; mod utils; #[tauri::command] -fn get_config(config: tauri::State) -> Result { - Ok(config.inner().clone()) +async fn load_config( + app: tauri::AppHandle, + config: tauri::State<'_, state::Config>, +) -> Result { + let config_file_path = utils::get_config_path_buf(&app)?; + let config_data = if !config_file_path.exists() { + let config_data = toml::to_string_pretty(&state::InnerConfig::default()).unwrap(); + println!("{}", config_data); + std::fs::write(&config_file_path, &config_data).unwrap(); + config_data + } else { + std::fs::read_to_string(&config_file_path).unwrap() + }; + let inner_config: state::InnerConfig = toml::from_str(&config_data).unwrap(); + *config.inner().inner.write().await = inner_config.clone(); + Ok(models::ConfigResult { + inner: inner_config, + file_path: config_file_path.to_string_lossy().to_string(), + }) +} + +#[tauri::command] +async fn get_config(config: tauri::State<'_, state::Config>) -> Result { + Ok(config.inner().inner.read().await.clone()) +} + +#[tauri::command] +async fn set_config( + app: tauri::AppHandle, + new_config: state::InnerConfig, + config: tauri::State<'_, state::Config>, +) -> Result { + let config_file_path = utils::get_config_path_buf(&app)?; + let toml = toml::to_string_pretty(&new_config).unwrap(); + if let Err(e) = std::fs::write(&config_file_path, toml) { + return Err(ErrorPayload { + message: format!("Failed to update config file: {}", e), + }); + }; + *config.inner().inner.write().await = new_config; + Ok(models::SetConfigResult { + config_path: config_file_path.to_string_lossy().to_string(), + }) } #[tauri::command] @@ -24,7 +67,7 @@ async fn download_file( output: &str, config: tauri::State<'_, state::Config>, ) -> Result { - match utils::download_file(url, output, &config.inner()).await { + match utils::download_file(url, output, &*config.inner().inner.read().await).await { Ok(_) => Ok(models::DownloadResult { file_path: output.to_string(), error: None, @@ -42,7 +85,9 @@ pub fn run() { .manage(state::Config::default()) .plugin(tauri_plugin_shell::init()) .invoke_handler(tauri::generate_handler![ + load_config, get_config, + set_config, get_file_size, download_file ]) diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index 9fc1f3a..2c2c5bd 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -1,5 +1,7 @@ use serde::{Deserialize, Serialize}; +use crate::state::InnerConfig; + #[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct FileSize { pub(crate) size: u64, @@ -11,3 +13,19 @@ pub(crate) struct DownloadResult { pub(crate) file_path: String, pub(crate) error: Option, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct SetConfigResult { + pub(crate) config_path: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct ConfigResult { + pub(crate) inner: InnerConfig, + pub(crate) file_path: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct ErrorPayload { + pub(crate) message: String, +} diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index d7dd705..f9345bb 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -1,16 +1,29 @@ use serde::{Deserialize, Serialize}; +use tauri::async_runtime::RwLock; #[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct InnerConfig { + pub(crate) preset_file: Option, + pub(crate) num_threads: Option, +} + +impl Default for InnerConfig { + fn default() -> Self { + Self { + preset_file: None, + num_threads: Some(12), + } + } +} + pub(crate) struct Config { - pub(crate) preset_file: String, - pub(crate) num_threads: u32, + pub(crate) inner: RwLock, } impl Default for Config { fn default() -> Self { Self { - preset_file: String::from("presets/default.json"), - num_threads: 7, + inner: RwLock::new(InnerConfig::default()), } } } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 2897117..8b33cec 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -7,6 +7,7 @@ use std::{ use reqwest::header::CONTENT_LENGTH; use reqwest::header::RANGE; use tauri::async_runtime::{spawn, Mutex}; +use tauri::Manager; pub(crate) async fn get_file_size(url: &str) -> Result> { let client = reqwest::Client::new(); @@ -23,7 +24,7 @@ pub(crate) async fn get_file_size(url: &str) -> Result Result> { let output = Arc::new(Mutex::new( OpenOptions::new() @@ -33,13 +34,15 @@ pub(crate) async fn download_file( .unwrap(), )); + let num_threads = config.num_threads.unwrap_or(12); + let file_size = get_file_size(url).await?; let mut handles = Vec::new(); - let chunk_size = file_size / config.num_threads as u64; + let chunk_size = file_size / num_threads as u64; - for i in 0..config.num_threads { + for i in 0..num_threads { let start = i as u64 * chunk_size; - let end = if i == config.num_threads - 1 { + let end = if i == num_threads - 1 { file_size - 1 } else { (i as u64 + 1) * chunk_size - 1 @@ -76,3 +79,22 @@ pub(crate) async fn download_chunk( Ok(()) } + +pub(crate) fn get_config_path_buf( + app: &tauri::AppHandle, +) -> Result { + match app.path().app_config_dir() { + Ok(mut dir) => { + if let Err(e) = std::fs::create_dir_all(&dir) { + return Err(crate::models::ErrorPayload { + message: format!("Failed to create app config directory: {}", e), + }); + }; + dir.push("config.toml"); + Ok(dir) + } + Err(e) => Err(crate::models::ErrorPayload { + message: format!("Failed to get app config directory: {}", e), + }), + } +} diff --git a/src/App.vue b/src/App.vue index 3ed4b37..1aa327f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,4 +1,11 @@ - +