diff --git a/backend/src/api/handler.rs b/backend/src/api/handler.rs index 2ff576a..de717aa 100644 --- a/backend/src/api/handler.rs +++ b/backend/src/api/handler.rs @@ -290,6 +290,16 @@ impl ApiMessageHandler { 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", + ); + } + } 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); diff --git a/backend/src/persist/general.rs b/backend/src/persist/general.rs index 9148675..58497ec 100644 --- a/backend/src/persist/general.rs +++ b/backend/src/persist/general.rs @@ -5,6 +5,25 @@ 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, @@ -14,6 +33,7 @@ pub struct SettingsJson { pub gpu: GpuJson, pub battery: BatteryJson, pub provider: Option, + pub events: Option, } impl Default for SettingsJson { @@ -26,6 +46,7 @@ impl Default for SettingsJson { gpu: GpuJson::default(), battery: BatteryJson::default(), provider: None, + events: None, } } } diff --git a/backend/src/persist/mod.rs b/backend/src/persist/mod.rs index 75c3caf..17dfa35 100644 --- a/backend/src/persist/mod.rs +++ b/backend/src/persist/mod.rs @@ -8,7 +8,7 @@ mod gpu; pub use battery::{BatteryEventJson, BatteryJson}; pub use cpu::CpuJson; pub use driver::DriverJson; -pub use general::{MinMaxJson, SettingsJson}; +pub use general::{MinMaxJson, OnEventJson, SettingsJson}; pub use gpu::GpuJson; pub use error::JsonError; diff --git a/backend/src/settings/detect/auto_detect.rs b/backend/src/settings/detect/auto_detect.rs index 567837b..e66394a 100644 --- a/backend/src/settings/detect/auto_detect.rs +++ b/backend/src/settings/detect/auto_detect.rs @@ -303,6 +303,7 @@ impl DriverBuilder { path: json_path, name: profile_name, driver: DriverJson::AutoDetect, + events: Default::default(), }), cpus: None, gpu: None, diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index 5f39258..4192f6f 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -21,6 +21,7 @@ impl Driver { path: json_path, name: settings.name, driver: DriverJson::SteamDeck, + events: settings.events.unwrap_or_default(), }), cpus: Box::new(super::steam_deck::Cpus::from_json( settings.cpus, @@ -51,6 +52,7 @@ impl Driver { path: json_path, name: settings.name, driver: DriverJson::SteamDeck, + events: settings.events.unwrap_or_default(), }), cpus: Box::new(super::steam_deck::Cpus::from_json( settings.cpus, @@ -72,6 +74,7 @@ impl Driver { path: json_path, name: settings.name, driver: DriverJson::SteamDeckAdvance, + events: settings.events.unwrap_or_default(), }), cpus: Box::new(super::steam_deck::Cpus::from_json( settings.cpus, diff --git a/backend/src/settings/general.rs b/backend/src/settings/general.rs index 5e39694..1f47bc2 100644 --- a/backend/src/settings/general.rs +++ b/backend/src/settings/general.rs @@ -34,16 +34,43 @@ pub struct General { pub path: PathBuf, pub 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(()) } } @@ -82,6 +109,10 @@ impl TGeneral for General { fn provider(&self) -> crate::persist::DriverJson { self.driver.clone() } + + fn on_event(&self) -> &crate::persist::OnEventJson { + &self.events + } } #[derive(Debug)] @@ -214,6 +245,17 @@ impl Settings { *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, + })?; + } + } Ok(*self.general.persistent()) } @@ -257,6 +299,7 @@ impl Settings { 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 1e77c4d..f98c44d 100644 --- a/backend/src/settings/traits.rs +++ b/backend/src/settings/traits.rs @@ -104,6 +104,8 @@ pub trait TGeneral: OnSet + OnResume + OnPowerEvent + Debug + Send { fn name(&mut self, name: String); fn provider(&self) -> crate::persist::DriverJson; + + fn on_event(&self) -> &'_ crate::persist::OnEventJson; } pub trait TBattery: OnSet + OnResume + OnPowerEvent + Debug + Send {