From 3aa9680baedf850d7d576d0df28ce50cf2124ebe Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sat, 18 Nov 2023 15:17:56 -0500 Subject: [PATCH] Add multi-profile per-game functionality for #82, change to JSON to RON format --- backend/Cargo.lock | 26 ++++- backend/Cargo.toml | 1 + backend/src/api/general.rs | 24 ++++- backend/src/api/handler.rs | 26 ++--- backend/src/consts.rs | 1 + backend/src/main.rs | 12 ++- backend/src/persist/error.rs | 35 ++++++- backend/src/persist/file.rs | 62 +++++++++++ backend/src/persist/general.rs | 50 +-------- backend/src/persist/mod.rs | 6 +- backend/src/settings/detect/auto_detect.rs | 13 ++- backend/src/settings/detect/limits_worker.rs | 6 +- backend/src/settings/driver.rs | 10 +- backend/src/settings/general.rs | 102 +++++++++---------- backend/src/settings/traits.rs | 10 +- backend/src/utility.rs | 17 ++-- src/backend.ts | 9 +- src/index.tsx | 2 +- 18 files changed, 253 insertions(+), 159 deletions(-) create mode 100644 backend/src/persist/file.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 04fb53e..bea6ffb 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -153,7 +153,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -175,6 +175,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -599,7 +608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bytes", "headers-core", "http", @@ -1059,6 +1068,7 @@ dependencies = [ "limits_core", "log", "regex", + "ron", "serde", "serde_json", "simplelog", @@ -1161,6 +1171,18 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.2", + "bitflags 2.4.1", + "serde", + "serde_derive", +] + [[package]] name = "rustc-demangle" version = "0.1.23" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 382f3de..3fa7e57 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -15,6 +15,7 @@ readme = "../README.md" usdpl-back = { version = "0.10.1", features = ["blocking"] }#, path = "../../usdpl-rs/usdpl-back"} serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +ron = "0.8" sysfuss = { version = "0.2", features = ["derive"] }#,path = "../../sysfs-nav"} # async diff --git a/backend/src/api/general.rs b/backend/src/api/general.rs index 9cda1c2..73cb706 100644 --- a/backend/src/api/general.rs +++ b/backend/src/api/general.rs @@ -55,18 +55,34 @@ pub fn load_settings( sender: Sender, ) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType { let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety - let setter = move |path: u64, name: String| { + let setter = move |id: u64, name: String, variant: u64, variant_name: Option| { sender .lock() .unwrap() - .send(ApiMessage::LoadSettings(path, name)) + .send(ApiMessage::LoadSettings(id, name, variant, variant_name.unwrap_or_else(|| crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned()))) .expect("load_settings send failed") }; move |params_in: super::ApiParameterType| { if let Some(Primitive::String(id)) = params_in.get(0) { if let Some(Primitive::String(name)) = params_in.get(1) { - setter(id.parse().unwrap_or_default(), name.to_owned()); - vec![true.into()] + if let Some(Primitive::F64(variant_id)) = params_in.get(2) { + if let Some(Primitive::String(variant_name)) = params_in.get(3) { + setter(id.parse().unwrap_or_default(), + name.to_owned(), + *variant_id as _, + Some(variant_name.to_owned())); + vec![true.into()] + } else { + setter(id.parse().unwrap_or_default(), + name.to_owned(), + *variant_id as _, + None); + vec![true.into()] + } + } else { + log::warn!("load_settings missing variant id parameter"); + vec!["load_settings missing variant id parameter".into()] + } } else { log::warn!("load_settings missing name parameter"); vec!["load_settings missing name parameter".into()] diff --git a/backend/src/api/handler.rs b/backend/src/api/handler.rs index 60316c9..56b2177 100644 --- a/backend/src/api/handler.rs +++ b/backend/src/api/handler.rs @@ -5,7 +5,6 @@ use crate::persist::SettingsJson; use crate::settings::{ MinMax, OnPowerEvent, OnResume, OnSet, PowerMode, Settings, TBattery, TCpus, TGeneral, TGpu, }; -use crate::utility::unwrap_maybe_fatal; type Callback = Box; @@ -23,7 +22,7 @@ pub enum ApiMessage { OnChargeChange(f64), // battery fill amount: 0 = empty, 1 = full PowerVibeCheck, WaitForEmptyQueue(Callback<()>), - LoadSettings(u64, String), // (path, name) + LoadSettings(u64, String, u64, String), // (path, name, variant, variant name) LoadMainSettings, LoadSystemSettings, GetLimits(Callback), @@ -287,21 +286,14 @@ impl ApiMessageHandler { log::debug!("api_worker is saving..."); let is_persistent = *settings.general.persistent(); let save_path = - crate::utility::settings_dir().join(settings.general.get_path().clone()); + crate::utility::settings_dir().join(settings.general.get_path()); if is_persistent { let settings_clone = settings.json(); let save_json: SettingsJson = settings_clone.into(); - unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings"); - if let Some(event) = &settings.general.on_event().on_save { - if !event.is_empty() { - unwrap_maybe_fatal( - std::process::Command::new("/bin/bash") - .args(&["-c", event]) - .spawn(), - "Failed to start on_save event command", - ); - } + if let Err(e) = crate::persist::FileJson::update_variant_or_create(&save_path, save_json, settings.general.get_name().to_owned()) { + log::error!("Failed to create/update settings file {}: {}", save_path.display(), e); } + //unwrap_maybe_fatal(save_json.save(&save_path), "Failed to save settings"); log::debug!("Saved settings to {}", save_path.display()); if let Err(e) = crate::utility::chown_settings_dir() { log::error!("Failed to change config dir permissions: {}", e); @@ -375,9 +367,9 @@ impl ApiMessageHandler { self.on_empty.push(callback); false } - ApiMessage::LoadSettings(id, name) => { + ApiMessage::LoadSettings(id, name, variant_id, variant_name) => { let path = format!("{}.json", id); - match settings.load_file(path.into(), name, false) { + match settings.load_file(path.into(), name, variant_id, variant_name, false) { Ok(success) => log::info!("Loaded settings file? {}", success), Err(e) => log::warn!("Load file err: {}", e), } @@ -387,6 +379,8 @@ impl ApiMessageHandler { match settings.load_file( crate::consts::DEFAULT_SETTINGS_FILE.into(), crate::consts::DEFAULT_SETTINGS_NAME.to_owned(), + 0, + crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(), true, ) { Ok(success) => log::info!("Loaded main settings file? {}", success), @@ -395,7 +389,7 @@ impl ApiMessageHandler { true } ApiMessage::LoadSystemSettings => { - settings.load_system_default(settings.general.get_name().to_owned()); + settings.load_system_default(settings.general.get_name().to_owned(), settings.general.get_variant_id(), settings.general.get_variant_name().to_owned()); true } ApiMessage::GetLimits(cb) => { diff --git a/backend/src/consts.rs b/backend/src/consts.rs index 7b6eb5b..ec650fe 100644 --- a/backend/src/consts.rs +++ b/backend/src/consts.rs @@ -5,6 +5,7 @@ pub const PACKAGE_VERSION: &'static str = env!("CARGO_PKG_VERSION"); pub const DEFAULT_SETTINGS_FILE: &str = "default_settings.json"; pub const DEFAULT_SETTINGS_NAME: &str = "Main"; +pub const DEFAULT_SETTINGS_VARIANT_NAME: &str = "Primary"; pub const LIMITS_FILE: &str = "limits_cache.json"; pub const LIMITS_OVERRIDE_FILE: &str = "limits_override.json"; diff --git a/backend/src/main.rs b/backend/src/main.rs index 6eb6d99..0c94237 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -75,12 +75,20 @@ fn main() -> Result<(), ()> { let _limits_handle = crate::settings::limits_worker_spawn(); let mut loaded_settings = - persist::SettingsJson::open(utility::settings_dir().join(DEFAULT_SETTINGS_FILE)) - .map(|settings| settings::Settings::from_json(settings, DEFAULT_SETTINGS_FILE.into())) + persist::FileJson::open(utility::settings_dir().join(DEFAULT_SETTINGS_FILE)) + .map(|mut file| file.variants.remove("0") + .map(|settings| settings::Settings::from_json(DEFAULT_SETTINGS_NAME.into(), settings, DEFAULT_SETTINGS_FILE.into())) + .unwrap_or_else(|| settings::Settings::system_default( + DEFAULT_SETTINGS_FILE.into(), + DEFAULT_SETTINGS_NAME.into(), + 0, + DEFAULT_SETTINGS_VARIANT_NAME.into()))) .unwrap_or_else(|_| { settings::Settings::system_default( DEFAULT_SETTINGS_FILE.into(), DEFAULT_SETTINGS_NAME.into(), + 0, + DEFAULT_SETTINGS_VARIANT_NAME.into(), ) }); diff --git a/backend/src/persist/error.rs b/backend/src/persist/error.rs index 2dcb6fa..502d199 100644 --- a/backend/src/persist/error.rs +++ b/backend/src/persist/error.rs @@ -1,10 +1,10 @@ #[derive(Debug)] -pub enum JsonError { - Serde(serde_json::Error), +pub enum SerdeError { + Serde(RonError), Io(std::io::Error), } -impl std::fmt::Display for JsonError { +impl std::fmt::Display for SerdeError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Serde(e) => (e as &dyn std::fmt::Display).fmt(f), @@ -12,3 +12,32 @@ impl std::fmt::Display for JsonError { } } } + +impl std::error::Error for SerdeError {} + +#[derive(Debug)] +pub enum RonError { + General(ron::error::Error), + Spanned(ron::error::SpannedError), +} + +impl std::fmt::Display for RonError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::General(e) => (e as &dyn std::fmt::Display).fmt(f), + Self::Spanned(e) => (e as &dyn std::fmt::Display).fmt(f), + } + } +} + +impl From for RonError { + fn from(value: ron::error::Error) -> Self { + Self::General(value) + } +} + +impl From for RonError { + fn from(value: ron::error::SpannedError) -> Self { + Self::Spanned(value) + } +} diff --git a/backend/src/persist/file.rs b/backend/src/persist/file.rs new file mode 100644 index 0000000..be575f4 --- /dev/null +++ b/backend/src/persist/file.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use super::SerdeError; +use super::SettingsJson; + +#[derive(Serialize, Deserialize)] +pub struct FileJson { + pub version: u64, + pub name: String, + pub variants: HashMap, +} + +impl FileJson { + pub fn save>(&self, path: P) -> Result<(), SerdeError> { + let path = path.as_ref(); + + if !self.variants.is_empty() { + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).map_err(SerdeError::Io)?; + } + let mut file = std::fs::File::create(path).map_err(SerdeError::Io)?; + ron::ser::to_writer_pretty(&mut file, &self, crate::utility::ron_pretty_config()).map_err(|e| SerdeError::Serde(e.into())) + } else { + if path.exists() { + // remove settings file when persistence is turned off, to prevent it from be loaded next time. + std::fs::remove_file(path).map_err(SerdeError::Io) + } else { + Ok(()) + } + } + } + + pub fn open>(path: P) -> Result { + let mut file = std::fs::File::open(path).map_err(SerdeError::Io)?; + ron::de::from_reader(&mut file).map_err(|e| SerdeError::Serde(e.into())) + } + + pub fn update_variant_or_create>(path: P, setting: SettingsJson, given_name: String) -> Result<(), SerdeError> { + if !setting.persistent { + return Ok(()) + } + let path = path.as_ref(); + + let file = if path.exists() { + let mut file = Self::open(path)?; + file.variants.insert(setting.variant.to_string(), setting); + file + } else { + let mut setting_variants = HashMap::with_capacity(1); + setting_variants.insert(setting.variant.to_string(), setting); + Self { + version: 0, + name: given_name, + variants: setting_variants, + } + }; + + file.save(path) + } +} diff --git a/backend/src/persist/general.rs b/backend/src/persist/general.rs index 58497ec..9809403 100644 --- a/backend/src/persist/general.rs +++ b/backend/src/persist/general.rs @@ -2,38 +2,18 @@ use std::default::Default; use serde::{Deserialize, Serialize}; -use super::JsonError; use super::{BatteryJson, CpuJson, DriverJson, GpuJson}; -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct OnEventJson { - pub on_save: Option, - pub on_load: Option, - pub on_set: Option, - pub on_resume: Option, -} - -impl Default for OnEventJson { - fn default() -> Self { - Self { - on_save: None, - on_load: None, - on_set: None, - on_resume: None, - } - } -} - #[derive(Serialize, Deserialize)] pub struct SettingsJson { pub version: u64, pub name: String, + pub variant: u64, pub persistent: bool, pub cpus: Vec, pub gpu: GpuJson, pub battery: BatteryJson, pub provider: Option, - pub events: Option, } impl Default for SettingsJson { @@ -41,42 +21,16 @@ impl Default for SettingsJson { Self { version: 0, name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(), + variant: 0, persistent: false, cpus: Vec::with_capacity(8), gpu: GpuJson::default(), battery: BatteryJson::default(), provider: None, - events: None, } } } -impl SettingsJson { - pub fn save>(&self, path: P) -> Result<(), JsonError> { - let path = path.as_ref(); - - if self.persistent { - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent).map_err(JsonError::Io)?; - } - let mut file = std::fs::File::create(path).map_err(JsonError::Io)?; - serde_json::to_writer_pretty(&mut file, &self).map_err(JsonError::Serde) - } else { - if path.exists() { - // remove settings file when persistence is turned off, to prevent it from be loaded next time. - std::fs::remove_file(path).map_err(JsonError::Io) - } else { - Ok(()) - } - } - } - - pub fn open>(path: P) -> Result { - let mut file = std::fs::File::open(path).map_err(JsonError::Io)?; - serde_json::from_reader(&mut file).map_err(JsonError::Serde) - } -} - #[derive(Serialize, Deserialize, Clone)] pub struct MinMaxJson { pub max: Option, diff --git a/backend/src/persist/mod.rs b/backend/src/persist/mod.rs index 17dfa35..4c9a31b 100644 --- a/backend/src/persist/mod.rs +++ b/backend/src/persist/mod.rs @@ -2,13 +2,15 @@ mod battery; mod cpu; mod driver; mod error; +mod file; mod general; mod gpu; pub use battery::{BatteryEventJson, BatteryJson}; pub use cpu::CpuJson; pub use driver::DriverJson; -pub use general::{MinMaxJson, OnEventJson, SettingsJson}; +pub use file::FileJson; +pub use general::{MinMaxJson, SettingsJson}; pub use gpu::GpuJson; -pub use error::JsonError; +pub use error::{SerdeError, RonError}; diff --git a/backend/src/settings/detect/auto_detect.rs b/backend/src/settings/detect/auto_detect.rs index 1d46c44..e7b8ded 100644 --- a/backend/src/settings/detect/auto_detect.rs +++ b/backend/src/settings/detect/auto_detect.rs @@ -10,7 +10,7 @@ use crate::settings::{Driver, General, TBattery, TCpus, TGeneral, TGpu, Provider fn get_limits() -> limits_core::json_v2::Base { let limits_path = super::utility::limits_path(); match File::open(&limits_path) { - Ok(f) => match serde_json::from_reader(f) { + Ok(f) => match ron::de::from_reader(f) { Ok(lim) => lim, Err(e) => { log::warn!( @@ -35,7 +35,7 @@ fn get_limits() -> limits_core::json_v2::Base { fn get_limits_overrides() -> Option { let limits_override_path = super::utility::limits_override_path(); match File::open(&limits_override_path) { - Ok(f) => match serde_json::from_reader(f) { + Ok(f) => match ron::de::from_reader(f) { Ok(lim) => Some(lim), Err(e) => { log::warn!( @@ -63,6 +63,8 @@ pub fn auto_detect_provider() -> DriverJson { None, crate::utility::settings_dir().join("autodetect.json"), "".to_owned(), + 0, + crate::consts::DEFAULT_SETTINGS_VARIANT_NAME.to_owned(), ) .battery .provider(); @@ -72,16 +74,19 @@ pub fn auto_detect_provider() -> DriverJson { /// Device detection logic pub fn auto_detect0( - settings_opt: Option, + settings_opt: Option<&SettingsJson>, json_path: std::path::PathBuf, name: String, + variant_id: u64, + variant_name: String, ) -> Driver { let mut general_driver = Box::new(General { persistent: false, path: json_path, name, + variant_id, + variant_name, driver: DriverJson::AutoDetect, - events: Default::default(), }); let cpu_info: String = usdpl_back::api::files::read_single("/proc/cpuinfo").unwrap_or_default(); diff --git a/backend/src/settings/detect/limits_worker.rs b/backend/src/settings/detect/limits_worker.rs index c3dbd0e..ad10f56 100644 --- a/backend/src/settings/detect/limits_worker.rs +++ b/backend/src/settings/detect/limits_worker.rs @@ -15,7 +15,7 @@ pub fn spawn() -> JoinHandle<()> { // try to load limits from file, fallback to built-in default let base = if limits_path.exists() { match std::fs::File::open(&limits_path) { - Ok(f) => match serde_json::from_reader(f) { + Ok(f) => match ron::de::from_reader(f) { Ok(b) => b, Err(e) => { log::error!("Cannot parse {}: {}", limits_path.display(), e); @@ -72,7 +72,7 @@ pub fn get_limits_cached() -> Base { let limits_path = super::utility::limits_path(); if limits_path.is_file() { match std::fs::File::open(&limits_path) { - Ok(f) => match serde_json::from_reader(f) { + Ok(f) => match ron::de::from_reader(f) { Ok(b) => b, Err(e) => { log::error!("Cannot parse {}: {}", limits_path.display(), e); @@ -93,7 +93,7 @@ pub fn get_limits_cached() -> Base { fn save_base(new_base: &Base, path: impl AsRef) { let limits_path = path.as_ref(); match std::fs::File::create(&limits_path) { - Ok(f) => match serde_json::to_writer_pretty(f, &new_base) { + Ok(f) => match ron::ser::to_writer_pretty(f, &new_base, crate::utility::ron_pretty_config()) { Ok(_) => log::info!("Successfully saved new limits to {}", limits_path.display()), Err(e) => log::error!( "Failed to save limits json to file `{}`: {}", diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index 90a3b7f..1aa005e 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -10,15 +10,17 @@ pub struct Driver { impl Driver { pub fn init( - settings: SettingsJson, + name: String, + settings: &SettingsJson, json_path: std::path::PathBuf, ) -> Self { let name_bup = settings.name.clone(); - auto_detect0(Some(settings), json_path, name_bup) + let id_bup = settings.variant; + auto_detect0(Some(settings), json_path, name, id_bup, name_bup) } - pub fn system_default(json_path: std::path::PathBuf, name: String) -> Self { - auto_detect0(None, json_path, name) + pub fn system_default(json_path: std::path::PathBuf, name: String, variant_id: u64, variant_name: String) -> Self { + auto_detect0(None, json_path, name, variant_id, variant_name) } } diff --git a/backend/src/settings/general.rs b/backend/src/settings/general.rs index a4b7844..a2f729f 100644 --- a/backend/src/settings/general.rs +++ b/backend/src/settings/general.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; //use super::{Battery, Cpus, Gpu}; use super::{OnResume, OnSet, SettingError}; use super::{TBattery, TCpus, TGeneral, TGpu}; -use crate::persist::SettingsJson; +use crate::persist::{SettingsJson, FileJson}; //use crate::utility::unwrap_lock; const LATEST_VERSION: u64 = 0; @@ -33,44 +33,19 @@ pub struct General { pub persistent: bool, pub path: PathBuf, pub name: String, + pub variant_id: u64, + pub variant_name: String, pub driver: crate::persist::DriverJson, - pub events: crate::persist::OnEventJson, } impl OnSet for General { fn on_set(&mut self) -> Result<(), Vec> { - if let Some(event) = &self.events.on_set { - if !event.is_empty() { - std::process::Command::new("/bin/bash") - .args(&["-c", event]) - .spawn() - .map_err(|e| { - vec![SettingError { - msg: format!("on_set event command error: {}", e), - setting: SettingVariant::General, - }] - })?; - } - } Ok(()) } } impl OnResume for General { fn on_resume(&self) -> Result<(), Vec> { - if let Some(event) = &self.events.on_resume { - if !event.is_empty() { - std::process::Command::new("/bin/bash") - .args(&["-c", event]) - .spawn() - .map_err(|e| { - vec![SettingError { - msg: format!("on_resume event command error: {}", e), - setting: SettingVariant::General, - }] - })?; - } - } Ok(()) } } @@ -106,12 +81,24 @@ impl TGeneral for General { self.name = name; } - fn provider(&self) -> crate::persist::DriverJson { - self.driver.clone() + fn get_variant_id(&self) -> u64 { + self.variant_id } - fn on_event(&self) -> &crate::persist::OnEventJson { - &self.events + fn variant_id(&mut self, id: u64) { + self.variant_id = id; + } + + fn get_variant_name(&self) -> &'_ str { + &self.variant_name + } + + fn variant_name(&mut self, name: String) { + self.variant_name = name; + } + + fn provider(&self) -> crate::persist::DriverJson { + self.driver.clone() } } @@ -155,8 +142,8 @@ impl OnSet for Settings { impl Settings { #[inline] - pub fn from_json(other: SettingsJson, json_path: PathBuf) -> Self { - let x = super::Driver::init(other, json_path.clone()); + pub fn from_json(name: String, other: SettingsJson, json_path: PathBuf) -> Self { + let x = super::Driver::init(name, &other, json_path.clone()); log::info!( "Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", x.general.provider(), @@ -172,8 +159,8 @@ impl Settings { } } - pub fn system_default(json_path: PathBuf, name: String) -> Self { - let driver = super::Driver::system_default(json_path, name); + pub fn system_default(json_path: PathBuf, name: String, variant_id: u64, variant_name: String) -> Self { + let driver = super::Driver::system_default(json_path, name, variant_id, variant_name); Self { general: driver.general, cpus: driver.cpus, @@ -182,26 +169,40 @@ impl Settings { } } - pub fn load_system_default(&mut self, name: String) { - let driver = super::Driver::system_default(self.general.get_path().to_owned(), name); + pub fn load_system_default(&mut self, name: String, variant_id: u64, variant_name: String) { + let driver = super::Driver::system_default(self.general.get_path().to_owned(), name, variant_id, variant_name); self.cpus = driver.cpus; self.gpu = driver.gpu; self.battery = driver.battery; self.general = driver.general; } + pub fn get_variant<'a>(settings_file: &'a FileJson, variant_id: u64, variant_name: String) -> Result<&'a SettingsJson, SettingError> { + if let Some(variant) = settings_file.variants.get(&variant_id.to_string()) { + Ok(variant) + } else { + Err(SettingError { + msg: format!("Cannot get non-existent variant `{}` (id:{})", variant_name, variant_id), + setting: SettingVariant::General, + }) + } + } + pub fn load_file( &mut self, filename: PathBuf, name: String, + variant: u64, + variant_name: String, system_defaults: bool, ) -> Result { let json_path = crate::utility::settings_dir().join(&filename); if json_path.exists() { - let settings_json = SettingsJson::open(&json_path).map_err(|e| SettingError { - msg: e.to_string(), + let file_json = FileJson::open(&json_path).map_err(|e| SettingError { + msg: format!("Failed to open settings {}: {}", json_path.display(), e), setting: SettingVariant::General, })?; + let settings_json = Self::get_variant(&file_json, variant, variant_name)?; if !settings_json.persistent { log::warn!( "Loaded persistent config `{}` ({}) with persistent=false", @@ -211,7 +212,7 @@ impl Settings { *self.general.persistent() = false; self.general.name(name); } else { - let x = super::Driver::init(settings_json, json_path.clone()); + let x = super::Driver::init(name, settings_json, json_path.clone()); log::info!("Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", x.general.provider(), x.cpus.provider(), x.gpu.provider(), x.battery.provider()); self.general = x.general; self.cpus = x.cpus; @@ -220,24 +221,15 @@ impl Settings { } } else { if system_defaults { - self.load_system_default(name); + self.load_system_default(name, variant, variant_name); } else { self.general.name(name); + self.general.variant_name(variant_name); } *self.general.persistent() = false; } self.general.path(filename); - if let Some(event) = &self.general.on_event().on_load { - if !event.is_empty() { - std::process::Command::new("/bin/bash") - .args(&["-c", event]) - .spawn() - .map_err(|e| SettingError { - msg: format!("on_save event command error: {}", e), - setting: SettingVariant::General, - })?; - } - } + self.general.variant_id(variant); Ok(*self.general.persistent()) } @@ -275,13 +267,13 @@ impl Settings { pub fn json(&self) -> SettingsJson { SettingsJson { version: LATEST_VERSION, - name: self.general.get_name().to_owned(), + name: self.general.get_variant_name().to_owned(), + variant: self.general.get_variant_id(), persistent: self.general.get_persistent(), cpus: self.cpus.json(), gpu: self.gpu.json(), battery: self.battery.json(), provider: Some(self.general.provider()), - events: Some(self.general.on_event().clone()), } } } diff --git a/backend/src/settings/traits.rs b/backend/src/settings/traits.rs index 990984d..8d93c55 100644 --- a/backend/src/settings/traits.rs +++ b/backend/src/settings/traits.rs @@ -109,9 +109,15 @@ pub trait TGeneral: OnSet + OnResume + OnPowerEvent + Debug + Send { fn name(&mut self, name: String); - fn provider(&self) -> crate::persist::DriverJson; + fn get_variant_id(&self) -> u64; - fn on_event(&self) -> &'_ crate::persist::OnEventJson; + fn variant_id(&mut self, id: u64); + + fn get_variant_name(&self) -> &'_ str; + + fn variant_name(&mut self, name: String); + + fn provider(&self) -> crate::persist::DriverJson; } pub trait TBattery: OnSet + OnResume + OnPowerEvent + Debug + Send { diff --git a/backend/src/utility.rs b/backend/src/utility.rs index 742cd32..62d6909 100644 --- a/backend/src/utility.rs +++ b/backend/src/utility.rs @@ -1,19 +1,8 @@ -use std::fmt::Display; //use std::sync::{LockResult, MutexGuard}; //use std::fs::{Permissions, metadata}; use std::io::{Read, Write}; use std::os::unix::fs::PermissionsExt; -pub fn unwrap_maybe_fatal(result: Result, message: &str) -> T { - match result { - Ok(x) => x, - Err(e) => { - log::error!("{}: {}", message, e); - panic!("{}: {}", message, e); - } - } -} - /*pub fn unwrap_lock<'a, T: Sized>( result: LockResult>, lock_name: &str, @@ -27,6 +16,12 @@ pub fn unwrap_maybe_fatal(result: Result, message: & } }*/ +pub fn ron_pretty_config() -> ron::ser::PrettyConfig { + ron::ser::PrettyConfig::default() + .struct_names(true) + .compact_arrays(true) +} + pub fn settings_dir() -> std::path::PathBuf { usdpl_back::api::dirs::home() .unwrap_or_else(|| "/tmp/".into()) diff --git a/src/backend.ts b/src/backend.ts index 07fe9d8..1d8d1f0 100644 --- a/src/backend.ts +++ b/src/backend.ts @@ -247,8 +247,13 @@ export async function getGeneralPersistent(): Promise { return (await call_backend("GENERAL_get_persistent", []))[0]; } -export async function loadGeneralSettings(id: string, name: string): Promise { - return (await call_backend("GENERAL_load_settings", [id, name]))[0]; +export async function loadGeneralSettings(id: string, name: string, variant_id: number, variant_name: string | undefined): Promise { + if (variant_name) { + return (await call_backend("GENERAL_load_settings", [id, name, variant_id, variant_name]))[0]; + } else { + return (await call_backend("GENERAL_load_settings", [id, name, variant_id]))[0]; + } + } export async function loadGeneralDefaultSettings(): Promise { diff --git a/src/index.tsx b/src/index.tsx index df1407d..2412a10 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -191,7 +191,7 @@ const reload = function() { backend.log(backend.LogLevel.Info, "RegisterForGameActionStart callback(" + actionType + ", " + id + ")"); // don't use gameInfo.appid, haha backend.resolve( - backend.loadGeneralSettings(id.toString(), gameInfo.display_name), + backend.loadGeneralSettings(id.toString(), gameInfo.display_name, 0, undefined), (ok: boolean) => {backend.log(backend.LogLevel.Debug, "Loading settings ok? " + ok)} ); });