use std::{ borrow::Borrow, collections::HashMap, ops::Sub, sync::Arc, time::{Duration, SystemTime}, }; use base64::Config; use ddc_hi::Display; use paris::{error, info, warn}; use tauri::async_runtime::Mutex; use tokio::sync::{broadcast, OwnedMutexGuard}; use tracing::warn; use crate::{display::Brightness, models, rpc}; use super::{display_config::DisplayConfig, DisplayBrightness}; use ddc_hi::Ddc; pub struct Manager { displays: Arc<Mutex<HashMap<usize, Arc<Mutex<DisplayConfig>>>>>, } impl Manager { pub fn global() -> &'static Self { static DISPLAY_MANAGER: once_cell::sync::OnceCell<Manager> = once_cell::sync::OnceCell::new(); DISPLAY_MANAGER.get_or_init(|| Self::create()) } pub fn create() -> Self { let instance = Self { displays: Arc::new(Mutex::new(HashMap::new())), }; instance } pub async fn subscribe_display_brightness(&self) { let rpc = rpc::Manager::global().await; let mut rx = rpc.client().subscribe_change_display_brightness_rx(); loop { if let Ok(display_brightness) = rx.recv().await { if let Err(err) = self.set_display_brightness(display_brightness).await { error!("set_display_brightness failed. {:?}", err); } } } } fn read_display_config_by_ddc(index: usize) -> anyhow::Result<DisplayConfig> { let mut displays = Display::enumerate(); match displays.get_mut(index) { Some(display) => { let mut config = DisplayConfig::default(index); match display.handle.get_vcp_feature(0x10) { Ok(value) => { config.max_brightness = value.maximum(); config.min_brightness = 0; config.brightness = value.value(); } Err(_) => {} }; match display.handle.get_vcp_feature(0x12) { Ok(value) => { config.max_contrast = value.maximum(); config.min_contrast = 0; config.contrast = value.value(); } Err(_) => {} }; match display.handle.get_vcp_feature(0xdc) { Ok(value) => { config.max_mode = value.maximum(); config.min_mode = 0; config.mode = value.value(); } Err(_) => {} }; Ok(config) } None => anyhow::bail!("display#{} is missed.", index), } } async fn get_display(&self, index: usize) -> anyhow::Result<OwnedMutexGuard<DisplayConfig>> { let mut displays = self.displays.lock().await; match displays.get_mut(&index) { Some(config) => { let mut config = config.to_owned().lock_owned().await; if config.last_modified_at > SystemTime::now().sub(Duration::from_secs(10)) { info!("cached"); return Ok(config); } return match Self::read_display_config_by_ddc(index) { Ok(config) => { let id = config.id; let value = Arc::new(Mutex::new(config)); let valueGuard = value.clone().lock_owned().await; displays.insert(id, value); info!("read form ddc"); Ok(valueGuard) } Err(err) => { warn!( "can not read config from display by ddc, use CACHED value. {:?}", err ); config.last_modified_at = SystemTime::now(); Ok(config) } }; } None => { let config = Self::read_display_config_by_ddc(index).map_err(|err| { anyhow::anyhow!( "can not read config from display by ddc,use DEFAULT value. {:?}", err ) })?; let id = config.id; let value = Arc::new(Mutex::new(config)); let valueGuard = value.clone().lock_owned().await; displays.insert(id, value); Ok(valueGuard) } } } pub async fn set_display_brightness( &self, display_brightness: DisplayBrightness, ) -> anyhow::Result<()> { match Display::enumerate().get_mut(display_brightness.display_index) { Some(display) => { match self.get_display(display_brightness.display_index).await { Ok(mut config) => { let curr = config.brightness; info!("curr_brightness: {:?}", curr); let mut target = match display_brightness.brightness { Brightness::Relative(v) => curr.wrapping_add_signed(v), Brightness::Absolute(v) => v, }; if target.gt(&config.max_brightness) { target = config.max_brightness; } else if target.lt(&config.min_brightness) { target = config.min_brightness; } config.brightness = target; display .handle .set_vcp_feature(0x10, target as u16) .map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?; let rpc = rpc::Manager::global().await; rpc.publish_desktop_cmd( format!("display{}/brightness", display_brightness.display_index) .as_str(), target.to_be_bytes().to_vec(), ) .await; } Err(err) => { info!( "can not get display#{} brightness. {:?}", display_brightness.display_index, err ); if let Brightness::Absolute(v) = display_brightness.brightness { display.handle.set_vcp_feature(0x10, v).map_err(|err| { anyhow::anyhow!("can not set brightness. {:?}", err) })?; }; } }; } None => { warn!("display#{} is not found.", display_brightness.display_index); } } Ok(()) } }