pref: 缓存显示器参数读数。#5.

This commit is contained in:
2023-02-18 14:47:41 +08:00
parent 070100cdbc
commit 550328ba1e
10 changed files with 245 additions and 51 deletions

25
src-tauri/src/db/db.rs Normal file
View File

@@ -0,0 +1,25 @@
use std::env::current_dir;
use once_cell::sync::OnceCell;
use redb::Database;
use tauri::api::path::config_dir;
use crate::picker;
trait GlobalDatabase<T> {
fn global() -> &'static T;
}
impl GlobalDatabase<Database> for Database {
fn global() -> &'static Database {
static GLOBAL_DATABASE: OnceCell<Database> = OnceCell::new();
GLOBAL_DATABASE.get_or_init(|| {
let path = config_dir()
.unwrap_or(current_dir().unwrap())
.join("main.redb");
let db = Database::create(path).unwrap();
return db;
})
}
}

3
src-tauri/src/db/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
mod db;
pub use db::*;

View File

@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub enum Brightness {
Relative(u16),
Relative(i16),
Absolute(u16),
}

View File

@@ -0,0 +1,36 @@
use std::time::SystemTime;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct DisplayConfig {
pub id: usize,
pub brightness: u16,
pub max_brightness: u16,
pub min_brightness: u16,
pub contrast: u16,
pub max_contrast: u16,
pub min_contrast: u16,
pub mode: u16,
pub max_mode: u16,
pub min_mode: u16,
pub last_modified_at: SystemTime,
}
impl DisplayConfig {
pub fn default(index: usize) -> Self {
Self {
id: index,
brightness: 30,
contrast: 50,
mode: 0,
last_modified_at: SystemTime::now(),
max_brightness: 100,
min_brightness: 0,
max_contrast: 100,
min_contrast: 0,
max_mode: 15,
min_mode: 0,
}
}
}

View File

@@ -1,78 +1,175 @@
use std::{
borrow::Borrow,
collections::HashMap,
ops::Sub,
sync::Arc,
time::{Duration, SystemTime},
};
use ddc_hi::Display;
use paris::{error, info};
use tokio::sync::{broadcast, OnceCell};
use tauri::async_runtime::Mutex;
use tokio::sync::{broadcast, OwnedMutexGuard};
use tracing::warn;
use crate::{display::Brightness, rpc};
use super::DisplayBrightness;
use super::{display_config::DisplayConfig, DisplayBrightness};
use ddc_hi::Ddc;
pub struct Manager {}
pub struct Manager {
displays: Arc<Mutex<HashMap<usize, Arc<Mutex<DisplayConfig>>>>>,
}
impl Manager {
pub async fn global() -> &'static Self {
static DISPLAY_MANAGER: OnceCell<Manager> = OnceCell::const_new();
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()).await
DISPLAY_MANAGER.get_or_init(|| Self::create())
}
pub async fn create() -> Self {
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 rx = rpc.client().subscribe_change_display_brightness_rx();
tokio::spawn(Self::subscribe_display_brightness(rx));
let mut rx = rpc.client().subscribe_change_display_brightness_rx();
Self {}
}
pub async fn subscribe_display_brightness(mut rx: broadcast::Receiver<DisplayBrightness>) {
loop {
if let Ok(display_brightness) = rx.recv().await {
if let Err(err) = Self::set_display_brightness(display_brightness) {
if let Err(err) = self.set_display_brightness(display_brightness).await {
error!("set_display_brightness failed. {:?}", err);
}
}
}
}
pub fn set_display_brightness(display_brightness: DisplayBrightness) -> anyhow::Result<()> {
match Display::enumerate().get_mut(display_brightness.display_index) {
Some(display) => match display.handle.get_vcp_feature(0x10) {
Ok(curr_brightness) => {
let curr = curr_brightness.value();
info!("curr_brightness: {:?}", curr);
let mut target = match display_brightness.brightness {
Brightness::Relative(v) => v + curr,
Brightness::Absolute(v) => v,
};
if target.gt(&curr_brightness.maximum()) {
target = curr_brightness.maximum();
} else if target.lt(&0) {
target = 0;
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();
}
display
.handle
.set_vcp_feature(0x10, target)
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
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);
}
Err(err) => {
info!(
"can not get display#{} brightness. {:?}",
display_brightness.display_index, err
);
if let Brightness::Absolute(v) = display_brightness.brightness {
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, v)
.set_vcp_feature(0x10, target as u16)
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
};
}
},
}
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 => {
anyhow::bail!(
"display#{} was not found.",
display_brightness.display_index
);
warn!("display#{} is not found.", display_brightness.display_index);
}
}
Ok(())

View File

@@ -1,5 +1,6 @@
mod brightness;
mod manager;
mod display_config;
pub use brightness::*;
pub use manager::*;

View File

@@ -5,6 +5,7 @@
#![feature(bool_to_option)]
mod core;
mod db;
mod display;
mod picker;
mod rpc;
@@ -92,7 +93,10 @@ async fn play_mode(target_mode: AmbientLightMode) {
}
#[tokio::main]
async fn main() {display::Manager::global().await;
async fn main() {
let displayManager = display::Manager::global();
tokio::spawn(displayManager.subscribe_display_brightness());
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
take_snapshot,

View File

@@ -31,7 +31,7 @@ impl MqttRpc {
match eventloop.poll().await {
Ok(notification) => {
let handled = || -> anyhow::Result<()> {
println!("MQTT notification = {:?}", notification);
// println!("MQTT notification = {:?}", notification);
if let Event::Incoming(notification) = notification {
if let Incoming::Publish(notification) = notification {
match notification.topic.as_str() {