diff --git a/com.steampowered.SteamOSManager1.Manager.xml b/com.steampowered.SteamOSManager1.Manager.xml index 3fa1856..4f5fe46 100644 --- a/com.steampowered.SteamOSManager1.Manager.xml +++ b/com.steampowered.SteamOSManager1.Manager.xml @@ -31,44 +31,6 @@ --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/bin/steamosctl.rs b/src/bin/steamosctl.rs index 94fa56d..0506c8f 100644 --- a/src/bin/steamosctl.rs +++ b/src/bin/steamosctl.rs @@ -12,7 +12,11 @@ use std::ops::Deref; use steamos_manager::cec::HdmiCecState; use steamos_manager::hardware::FanControlState; use steamos_manager::power::{CPUScalingGovernor, GPUPerformanceLevel, GPUPowerProfile}; -use steamos_manager::proxy::ManagerProxy; +use steamos_manager::proxy::{ + AmbientLightSensor1Proxy, CpuScaling1Proxy, FactoryReset1Proxy, FanControl1Proxy, + HdmiCec1Proxy, ManagerProxy, Storage1Proxy, UpdateBios1Proxy, UpdateDock1Proxy, + WifiPowerManagement1Proxy, +}; use steamos_manager::wifi::{WifiBackend, WifiDebugMode, WifiPowerManagement}; use zbus::fdo::PropertiesProxy; use zbus::names::InterfaceName; @@ -194,6 +198,7 @@ async fn main() -> Result<()> { } } Commands::GetAlsCalibrationGain => { + let proxy = AmbientLightSensor1Proxy::new(&conn).await?; let gain = proxy.als_calibration_gain().await?; println!("ALS calibration gain: {gain}"); } @@ -206,9 +211,11 @@ async fn main() -> Result<()> { println!("Version: {version}"); } Commands::SetFanControlState { state } => { + let proxy = FanControl1Proxy::new(&conn).await?; proxy.set_fan_control_state(*state as u32).await?; } Commands::GetFanControlState => { + let proxy = FanControl1Proxy::new(&conn).await?; let state = proxy.fan_control_state().await?; match FanControlState::try_from(state) { Ok(s) => println!("Fan control state: {}", s), @@ -216,6 +223,7 @@ async fn main() -> Result<()> { } } Commands::GetAvailableCpuScalingGovernors => { + let proxy = CpuScaling1Proxy::new(&conn).await?; let governors = proxy.available_cpu_scaling_governors().await?; println!("Governors:\n"); for name in governors { @@ -223,6 +231,7 @@ async fn main() -> Result<()> { } } Commands::GetCpuScalingGovernor => { + let proxy = CpuScaling1Proxy::new(&conn).await?; let governor = proxy.cpu_scaling_governor().await?; let governor_type = CPUScalingGovernor::try_from(governor.as_str()); match governor_type { @@ -235,6 +244,7 @@ async fn main() -> Result<()> { } } Commands::SetCpuScalingGovernor { governor } => { + let proxy = CpuScaling1Proxy::new(&conn).await?; proxy .set_cpu_scaling_governor(governor.to_string().as_str()) .await?; @@ -324,9 +334,11 @@ async fn main() -> Result<()> { } } Commands::SetWifiPowerManagementState { state } => { + let proxy = WifiPowerManagement1Proxy::new(&conn).await?; proxy.set_wifi_power_management_state(*state as u32).await?; } Commands::GetWifiPowerManagementState => { + let proxy = WifiPowerManagement1Proxy::new(&conn).await?; let state = proxy.wifi_power_management_state().await?; match WifiPowerManagement::try_from(state) { Ok(s) => println!("Wifi power management state: {}", s), @@ -334,9 +346,11 @@ async fn main() -> Result<()> { } } Commands::SetHdmiCecState { state } => { + let proxy = HdmiCec1Proxy::new(&conn).await?; proxy.set_hdmi_cec_state(*state as u32).await?; } Commands::GetHdmiCecState => { + let proxy = HdmiCec1Proxy::new(&conn).await?; let state = proxy.hdmi_cec_state().await?; match HdmiCecState::try_from(state) { Ok(s) => println!("HDMI-CEC state: {}", s.to_human_readable()), @@ -344,15 +358,19 @@ async fn main() -> Result<()> { } } Commands::UpdateBios => { + let proxy = UpdateBios1Proxy::new(&conn).await?; let _ = proxy.update_bios().await?; } Commands::UpdateDock => { + let proxy = UpdateDock1Proxy::new(&conn).await?; let _ = proxy.update_dock().await?; } Commands::FactoryReset => { + let proxy = FactoryReset1Proxy::new(&conn).await?; let _ = proxy.prepare_factory_reset().await?; } Commands::TrimDevices => { + let proxy = Storage1Proxy::new(&conn).await?; let _ = proxy.trim_devices().await?; } } diff --git a/src/manager/user.rs b/src/manager/user.rs index 4686d42..2a14929 100644 --- a/src/manager/user.rs +++ b/src/manager/user.rs @@ -29,6 +29,8 @@ use crate::power::{ use crate::wifi::{get_wifi_backend, get_wifi_power_management_state}; use crate::API_VERSION; +const MANAGER_PATH: &str = "/com/steampowered/SteamOSManager1"; + macro_rules! method { ($self:expr, $method:expr, $($args:expr),+) => { $self.proxy @@ -91,33 +93,57 @@ macro_rules! setter { struct SteamOSManager { proxy: Proxy<'static>, - hdmi_cec: HdmiCecControl<'static>, channel: Sender, +} + +struct AmbientLightSensor1 { + proxy: Proxy<'static>, +} + +struct CpuScaling1 { + proxy: Proxy<'static>, +} + +struct FactoryReset1 { + proxy: Proxy<'static>, +} + +struct FanControl1 { + proxy: Proxy<'static>, +} + +struct HdmiCec1 { + hdmi_cec: HdmiCecControl<'static>, +} + +struct Storage1 { + proxy: Proxy<'static>, job_manager: UnboundedSender, } +struct UpdateBios1 { + proxy: Proxy<'static>, + job_manager: UnboundedSender, +} + +struct UpdateDock1 { + proxy: Proxy<'static>, + job_manager: UnboundedSender, +} + +struct WifiPowerManagement1 { + proxy: Proxy<'static>, +} + impl SteamOSManager { pub async fn new( - connection: Connection, system_conn: Connection, + proxy: Proxy<'static>, channel: Sender, job_manager: UnboundedSender, ) -> Result { - let hdmi_cec = HdmiCecControl::new(&connection).await?; - let proxy = Builder::new(&system_conn) - .destination("com.steampowered.SteamOSManager1")? - .path("/com/steampowered/SteamOSManager1")? - .interface("com.steampowered.SteamOSManager1.RootManager")? - .cache_properties(CacheProperties::No) - .build() - .await?; job_manager.send(JobManagerCommand::MirrorConnection(system_conn))?; - Ok(SteamOSManager { - hdmi_cec, - proxy, - job_manager, - channel, - }) + Ok(SteamOSManager { proxy, channel }) } } @@ -128,57 +154,6 @@ impl SteamOSManager { API_VERSION } - #[zbus(property(emits_changed_signal = "false"))] - async fn hdmi_cec_state(&self) -> fdo::Result { - match self.hdmi_cec.get_enabled_state().await { - Ok(state) => Ok(state as u32), - Err(e) => Err(to_zbus_fdo_error(e)), - } - } - - #[zbus(property)] - async fn set_hdmi_cec_state(&self, state: u32) -> zbus::Result<()> { - let state = match HdmiCecState::try_from(state) { - Ok(state) => state, - Err(err) => return Err(fdo::Error::InvalidArgs(err.to_string()).into()), - }; - self.hdmi_cec - .set_enabled_state(state) - .await - .inspect_err(|message| error!("Error setting CEC state: {message}")) - .map_err(to_zbus_error) - } - - async fn prepare_factory_reset(&self) -> fdo::Result { - method!(self, "PrepareFactoryReset") - } - - #[zbus(property(emits_changed_signal = "false"))] - async fn wifi_power_management_state(&self) -> fdo::Result { - match get_wifi_power_management_state().await { - Ok(state) => Ok(state as u32), - Err(e) => Err(to_zbus_fdo_error(e)), - } - } - - #[zbus(property)] - async fn set_wifi_power_management_state(&self, state: u32) -> zbus::Result<()> { - self.proxy - .call("SetWifiPowerManagementState", &(state)) - .await - .map_err(to_zbus_error) - } - - #[zbus(property(emits_changed_signal = "false"))] - async fn fan_control_state(&self) -> fdo::Result { - getter!(self, "FanControlState") - } - - #[zbus(property)] - async fn set_fan_control_state(&self, state: u32) -> zbus::Result<()> { - setter!(self, "FanControlState", state) - } - #[zbus(property(emits_changed_signal = "const"))] async fn hardware_currently_supported(&self) -> fdo::Result { match check_support().await { @@ -187,72 +162,6 @@ impl SteamOSManager { } } - #[zbus(property(emits_changed_signal = "false"))] - async fn als_calibration_gain(&self) -> fdo::Result { - getter!(self, "AlsCalibrationGain") - } - - async fn get_als_integration_time_file_descriptor(&self) -> fdo::Result { - let m = self - .proxy - .call_method::<&str, ()>("GetAlsIntegrationTimeFileDescriptor", &()) - .await - .map_err(zbus_to_zbus_fdo)?; - match m.body().deserialize::() { - Ok(fd) => fd.try_to_owned().map_err(to_zbus_fdo_error), - Err(e) => Err(zbus_to_zbus_fdo(e)), - } - } - - async fn update_bios(&mut self) -> fdo::Result { - job_method!(self, "UpdateBios") - } - - async fn update_dock(&mut self) -> fdo::Result { - job_method!(self, "UpdateDock") - } - - async fn trim_devices(&mut self) -> fdo::Result { - job_method!(self, "TrimDevices") - } - - async fn format_device( - &mut self, - device: &str, - label: &str, - validate: bool, - ) -> fdo::Result { - job_method!(self, "FormatDevice", device, label, validate) - } - - #[zbus(property(emits_changed_signal = "false"))] - async fn available_cpu_scaling_governors(&self) -> fdo::Result> { - let governors = get_available_cpu_scaling_governors() - .await - .map_err(to_zbus_fdo_error)?; - let mut result = Vec::new(); - for g in governors { - result.push(g.to_string()); - } - Ok(result) - } - - #[zbus(property(emits_changed_signal = "false"))] - async fn cpu_scaling_governor(&self) -> fdo::Result { - let governor = get_cpu_scaling_governor() - .await - .map_err(to_zbus_fdo_error)?; - Ok(governor.to_string()) - } - - #[zbus(property)] - async fn set_cpu_scaling_governor(&self, governor: String) -> zbus::Result<()> { - self.proxy - .call("SetCpuScalingGovernor", &(governor)) - .await - .map_err(to_zbus_error) - } - #[zbus(property(emits_changed_signal = "false"))] async fn gpu_power_profiles(&self) -> fdo::Result> { get_gpu_power_profiles().await.map_err(to_zbus_fdo_error) @@ -388,16 +297,215 @@ impl SteamOSManager { } } +#[interface(name = "com.steampowered.SteamOSManager1.AmbientLightSensor1")] +impl AmbientLightSensor1 { + #[zbus(property(emits_changed_signal = "false"))] + async fn als_calibration_gain(&self) -> fdo::Result { + getter!(self, "AlsCalibrationGain") + } + + async fn get_als_integration_time_file_descriptor(&self) -> fdo::Result { + let m = self + .proxy + .call_method::<&str, ()>("GetAlsIntegrationTimeFileDescriptor", &()) + .await + .map_err(zbus_to_zbus_fdo)?; + match m.body().deserialize::() { + Ok(fd) => fd.try_to_owned().map_err(to_zbus_fdo_error), + Err(e) => Err(zbus_to_zbus_fdo(e)), + } + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.CpuScaling1")] +impl CpuScaling1 { + #[zbus(property(emits_changed_signal = "false"))] + async fn available_cpu_scaling_governors(&self) -> fdo::Result> { + let governors = get_available_cpu_scaling_governors() + .await + .map_err(to_zbus_fdo_error)?; + let mut result = Vec::new(); + for g in governors { + result.push(g.to_string()); + } + Ok(result) + } + + #[zbus(property(emits_changed_signal = "false"))] + async fn cpu_scaling_governor(&self) -> fdo::Result { + let governor = get_cpu_scaling_governor() + .await + .map_err(to_zbus_fdo_error)?; + Ok(governor.to_string()) + } + + #[zbus(property)] + async fn set_cpu_scaling_governor(&self, governor: String) -> zbus::Result<()> { + self.proxy + .call("SetCpuScalingGovernor", &(governor)) + .await + .map_err(to_zbus_error) + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.FactoryReset1")] +impl FactoryReset1 { + async fn prepare_factory_reset(&self) -> fdo::Result { + method!(self, "PrepareFactoryReset") + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.FanControl1")] +impl FanControl1 { + #[zbus(property(emits_changed_signal = "false"))] + async fn fan_control_state(&self) -> fdo::Result { + getter!(self, "FanControlState") + } + + #[zbus(property)] + async fn set_fan_control_state(&self, state: u32) -> zbus::Result<()> { + setter!(self, "FanControlState", state) + } +} + +impl HdmiCec1 { + async fn new(connection: &Connection) -> Result { + let hdmi_cec = HdmiCecControl::new(connection).await?; + Ok(HdmiCec1 { hdmi_cec }) + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.HdmiCec1")] +impl HdmiCec1 { + #[zbus(property(emits_changed_signal = "false"))] + async fn hdmi_cec_state(&self) -> fdo::Result { + match self.hdmi_cec.get_enabled_state().await { + Ok(state) => Ok(state as u32), + Err(e) => Err(to_zbus_fdo_error(e)), + } + } + + #[zbus(property)] + async fn set_hdmi_cec_state(&self, state: u32) -> zbus::Result<()> { + let state = match HdmiCecState::try_from(state) { + Ok(state) => state, + Err(err) => return Err(fdo::Error::InvalidArgs(err.to_string()).into()), + }; + self.hdmi_cec + .set_enabled_state(state) + .await + .inspect_err(|message| error!("Error setting CEC state: {message}")) + .map_err(to_zbus_error) + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.Storage1")] +impl Storage1 { + async fn format_device( + &mut self, + device: &str, + label: &str, + validate: bool, + ) -> fdo::Result { + job_method!(self, "FormatDevice", device, label, validate) + } + + async fn trim_devices(&mut self) -> fdo::Result { + job_method!(self, "TrimDevices") + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.UpdateBios1")] +impl UpdateBios1 { + async fn update_bios(&mut self) -> fdo::Result { + job_method!(self, "UpdateBios") + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.UpdateDock1")] +impl UpdateDock1 { + async fn update_dock(&mut self) -> fdo::Result { + job_method!(self, "UpdateDock") + } +} + +#[interface(name = "com.steampowered.SteamOSManager1.WifiPowerManagement1")] +impl WifiPowerManagement1 { + #[zbus(property(emits_changed_signal = "false"))] + async fn wifi_power_management_state(&self) -> fdo::Result { + match get_wifi_power_management_state().await { + Ok(state) => Ok(state as u32), + Err(e) => Err(to_zbus_fdo_error(e)), + } + } + + #[zbus(property)] + async fn set_wifi_power_management_state(&self, state: u32) -> zbus::Result<()> { + self.proxy + .call("SetWifiPowerManagementState", &(state)) + .await + .map_err(to_zbus_error) + } +} + pub(crate) async fn create_interfaces( session: Connection, system: Connection, daemon: Sender, job_manager: UnboundedSender, ) -> Result<()> { - let manager = SteamOSManager::new(session.clone(), system.clone(), daemon, job_manager).await?; - session - .object_server() - .at("/com/steampowered/SteamOSManager1", manager) + let proxy = Builder::::new(&system) + .destination("com.steampowered.SteamOSManager1")? + .path("/com/steampowered/SteamOSManager1")? + .interface("com.steampowered.SteamOSManager1.RootManager")? + .cache_properties(CacheProperties::No) + .build() + .await?; + + let manager = + SteamOSManager::new(system.clone(), proxy.clone(), daemon, job_manager.clone()).await?; + + let als = AmbientLightSensor1 { + proxy: proxy.clone(), + }; + let cpu_scaling = CpuScaling1 { + proxy: proxy.clone(), + }; + let factory_reset = FactoryReset1 { + proxy: proxy.clone(), + }; + let fan_control = FanControl1 { + proxy: proxy.clone(), + }; + let hdmi_cec = HdmiCec1::new(&session).await?; + let storage = Storage1 { + proxy: proxy.clone(), + job_manager: job_manager.clone(), + }; + let update_bios = UpdateBios1 { + proxy: proxy.clone(), + job_manager: job_manager.clone(), + }; + let update_dock = UpdateDock1 { + proxy: proxy.clone(), + job_manager: job_manager.clone(), + }; + let wifi_power_management = WifiPowerManagement1 { + proxy: proxy.clone(), + }; + + let object_server = session.object_server(); + object_server.at(MANAGER_PATH, manager).await?; + object_server.at(MANAGER_PATH, als).await?; + object_server.at(MANAGER_PATH, cpu_scaling).await?; + object_server.at(MANAGER_PATH, factory_reset).await?; + object_server.at(MANAGER_PATH, fan_control).await?; + object_server.at(MANAGER_PATH, hdmi_cec).await?; + object_server.at(MANAGER_PATH, storage).await?; + object_server.at(MANAGER_PATH, update_bios).await?; + object_server.at(MANAGER_PATH, update_dock).await?; + object_server + .at(MANAGER_PATH, wifi_power_management) .await?; Ok(()) @@ -413,7 +521,7 @@ mod test { use std::time::Duration; use tokio::sync::mpsc::unbounded_channel; use tokio::time::sleep; - use zbus::Connection; + use zbus::{Connection, Interface}; struct TestHandle { _handle: testing::TestHandle, @@ -425,12 +533,7 @@ mod test { let (tx_ctx, _rx_ctx) = channel::(); let (tx_job, _rx_job) = unbounded_channel::(); let connection = handle.new_dbus().await?; - let manager = - SteamOSManager::new(connection.clone(), connection.clone(), tx_ctx, tx_job).await?; - connection - .object_server() - .at("/com/steampowered/SteamOSManager1", manager) - .await?; + create_interfaces(connection.clone(), connection.clone(), tx_ctx, tx_job).await?; sleep(Duration::from_millis(1)).await; @@ -446,7 +549,7 @@ mod test { let remote = testing::InterfaceIntrospection::from_remote::( &test.connection, - "/com/steampowered/SteamOSManager1", + MANAGER_PATH, ) .await .expect("remote"); @@ -458,4 +561,100 @@ mod test { .expect("local"); assert!(remote.compare(&local)); } + + async fn test_interface_matches(connection: &Connection) -> Result { + let remote = + testing::InterfaceIntrospection::from_remote::(connection, MANAGER_PATH).await?; + let local = testing::InterfaceIntrospection::from_local( + "com.steampowered.SteamOSManager1.xml", + I::name().to_string(), + ) + .await?; + Ok(remote.compare(&local)) + } + + #[tokio::test] + async fn interface_matches_ambient_light_sensor1() { + let test = start().await.expect("start"); + + assert!( + test_interface_matches::(&test.connection) + .await + .unwrap() + ); + } + + #[tokio::test] + async fn interface_matches_cpu_scaling1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_factory_reset1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_fan_control1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_hdmi_cec1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_storage1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_update_bios1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_update_dock1() { + let test = start().await.expect("start"); + + assert!(test_interface_matches::(&test.connection) + .await + .unwrap()); + } + + #[tokio::test] + async fn interface_matches_wifi_power_management1() { + let test = start().await.expect("start"); + + assert!( + test_interface_matches::(&test.connection) + .await + .unwrap() + ); + } } diff --git a/src/proxy/manager.rs b/src/proxy/manager.rs index 307e95c..22235ef 100644 --- a/src/proxy/manager.rs +++ b/src/proxy/manager.rs @@ -19,55 +19,12 @@ use zbus::proxy; assume_defaults = true )] trait Manager { - /// FormatDevice method - fn format_device( - &self, - device: &str, - label: &str, - validate: bool, - ) -> zbus::Result; - - /// GetAlsIntegrationTimeFileDescriptor method - fn get_als_integration_time_file_descriptor(&self) -> zbus::Result; - - /// PrepareFactoryReset method - fn prepare_factory_reset(&self) -> zbus::Result; - /// ReloadConfig method fn reload_config(&self) -> zbus::Result<()>; /// SetWifiDebugMode method fn set_wifi_debug_mode(&self, mode: u32, buffer_size: u32) -> zbus::Result<()>; - /// TrimDevices method - fn trim_devices(&self) -> zbus::Result; - - /// UpdateBios method - fn update_bios(&self) -> zbus::Result; - - /// UpdateDock method - fn update_dock(&self) -> zbus::Result; - - /// AlsCalibrationGain property - #[zbus(property)] - fn als_calibration_gain(&self) -> zbus::Result; - - /// AvailableCpuScalingGovernors property - #[zbus(property)] - fn available_cpu_scaling_governors(&self) -> zbus::Result>; - - /// CpuScalingGovernor property - #[zbus(property)] - fn cpu_scaling_governor(&self) -> zbus::Result; - #[zbus(property)] - fn set_cpu_scaling_governor(&self, value: &str) -> zbus::Result<()>; - - /// FanControlState property - #[zbus(property)] - fn fan_control_state(&self) -> zbus::Result; - #[zbus(property)] - fn set_fan_control_state(&self, value: u32) -> zbus::Result<()>; - /// GpuPerformanceLevel property #[zbus(property)] fn gpu_performance_level(&self) -> zbus::Result; @@ -88,12 +45,6 @@ trait Manager { #[zbus(property)] fn hardware_currently_supported(&self) -> zbus::Result; - /// HdmiCecState property - #[zbus(property)] - fn hdmi_cec_state(&self) -> zbus::Result; - #[zbus(property)] - fn set_hdmi_cec_state(&self, value: u32) -> zbus::Result<()>; - /// ManualGpuClock property #[zbus(property)] fn manual_gpu_clock(&self) -> zbus::Result; @@ -135,10 +86,4 @@ trait Manager { /// WifiDebugModeState property #[zbus(property)] fn wifi_debug_mode_state(&self) -> zbus::Result; - - /// WifiPowerManagementState property - #[zbus(property)] - fn wifi_power_management_state(&self) -> zbus::Result; - #[zbus(property)] - fn set_wifi_power_management_state(&self, value: u32) -> zbus::Result<()>; }