pref: 缓存显示器参数读数。#5.
This commit is contained in:
parent
070100cdbc
commit
550328ba1e
27
src-tauri/Cargo.lock
generated
27
src-tauri/Cargo.lock
generated
@ -856,6 +856,7 @@ dependencies = [
|
|||||||
"mdns",
|
"mdns",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paris",
|
"paris",
|
||||||
|
"redb",
|
||||||
"rumqttc",
|
"rumqttc",
|
||||||
"scrap",
|
"scrap",
|
||||||
"serde",
|
"serde",
|
||||||
@ -2732,6 +2733,16 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyo3-build-config"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
@ -2868,6 +2879,16 @@ dependencies = [
|
|||||||
"num_cpus",
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redb"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78f210bb101d3a0ddba42f67b12a1d7186e584733ad028f119c8d217d867f03d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pyo3-build-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -3614,6 +3635,12 @@ dependencies = [
|
|||||||
"xattr",
|
"xattr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "target-lexicon"
|
||||||
|
version = "0.12.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri"
|
name = "tauri"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
@ -37,6 +37,7 @@ image = "0.24.5"
|
|||||||
mdns = "3.0.0"
|
mdns = "3.0.0"
|
||||||
macos-app-nap = "0.0.1"
|
macos-app-nap = "0.0.1"
|
||||||
ddc-hi = "0.4.1"
|
ddc-hi = "0.4.1"
|
||||||
|
redb = "0.13.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
|
25
src-tauri/src/db/db.rs
Normal file
25
src-tauri/src/db/db.rs
Normal 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
3
src-tauri/src/db/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod db;
|
||||||
|
|
||||||
|
pub use db::*;
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
pub enum Brightness {
|
pub enum Brightness {
|
||||||
Relative(u16),
|
Relative(i16),
|
||||||
Absolute(u16),
|
Absolute(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src-tauri/src/display/display_config.rs
Normal file
36
src-tauri/src/display/display_config.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,58 +1,158 @@
|
|||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
collections::HashMap,
|
||||||
|
ops::Sub,
|
||||||
|
sync::Arc,
|
||||||
|
time::{Duration, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
use ddc_hi::Display;
|
use ddc_hi::Display;
|
||||||
use paris::{error, info};
|
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 crate::{display::Brightness, rpc};
|
||||||
|
|
||||||
use super::DisplayBrightness;
|
use super::{display_config::DisplayConfig, DisplayBrightness};
|
||||||
use ddc_hi::Ddc;
|
use ddc_hi::Ddc;
|
||||||
|
|
||||||
pub struct Manager {}
|
pub struct Manager {
|
||||||
|
displays: Arc<Mutex<HashMap<usize, Arc<Mutex<DisplayConfig>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
pub async fn global() -> &'static Self {
|
pub fn global() -> &'static Self {
|
||||||
static DISPLAY_MANAGER: OnceCell<Manager> = OnceCell::const_new();
|
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 rpc = rpc::Manager::global().await;
|
||||||
|
|
||||||
let rx = rpc.client().subscribe_change_display_brightness_rx();
|
let mut rx = rpc.client().subscribe_change_display_brightness_rx();
|
||||||
tokio::spawn(Self::subscribe_display_brightness(rx));
|
|
||||||
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn subscribe_display_brightness(mut rx: broadcast::Receiver<DisplayBrightness>) {
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(display_brightness) = rx.recv().await {
|
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);
|
error!("set_display_brightness failed. {:?}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_display_brightness(display_brightness: DisplayBrightness) -> anyhow::Result<()> {
|
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) {
|
match Display::enumerate().get_mut(display_brightness.display_index) {
|
||||||
Some(display) => match display.handle.get_vcp_feature(0x10) {
|
Some(display) => {
|
||||||
Ok(curr_brightness) => {
|
match self.get_display(display_brightness.display_index).await {
|
||||||
let curr = curr_brightness.value();
|
Ok(mut config) => {
|
||||||
|
let curr = config.brightness;
|
||||||
info!("curr_brightness: {:?}", curr);
|
info!("curr_brightness: {:?}", curr);
|
||||||
let mut target = match display_brightness.brightness {
|
let mut target = match display_brightness.brightness {
|
||||||
Brightness::Relative(v) => v + curr,
|
Brightness::Relative(v) => curr.wrapping_add_signed(v),
|
||||||
Brightness::Absolute(v) => v,
|
Brightness::Absolute(v) => v,
|
||||||
};
|
};
|
||||||
if target.gt(&curr_brightness.maximum()) {
|
if target.gt(&config.max_brightness) {
|
||||||
target = curr_brightness.maximum();
|
target = config.max_brightness;
|
||||||
} else if target.lt(&0) {
|
} else if target.lt(&config.min_brightness) {
|
||||||
target = 0;
|
target = config.min_brightness;
|
||||||
}
|
}
|
||||||
|
config.brightness = target;
|
||||||
display
|
display
|
||||||
.handle
|
.handle
|
||||||
.set_vcp_feature(0x10, target)
|
.set_vcp_feature(0x10, target as u16)
|
||||||
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
|
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -61,18 +161,15 @@ impl Manager {
|
|||||||
display_brightness.display_index, err
|
display_brightness.display_index, err
|
||||||
);
|
);
|
||||||
if let Brightness::Absolute(v) = display_brightness.brightness {
|
if let Brightness::Absolute(v) = display_brightness.brightness {
|
||||||
display
|
display.handle.set_vcp_feature(0x10, v).map_err(|err| {
|
||||||
.handle
|
anyhow::anyhow!("can not set brightness. {:?}", err)
|
||||||
.set_vcp_feature(0x10, v)
|
})?;
|
||||||
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
anyhow::bail!(
|
warn!("display#{} is not found.", display_brightness.display_index);
|
||||||
"display#{} was not found.",
|
|
||||||
display_brightness.display_index
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
mod brightness;
|
mod brightness;
|
||||||
mod manager;
|
mod manager;
|
||||||
|
mod display_config;
|
||||||
|
|
||||||
pub use brightness::*;
|
pub use brightness::*;
|
||||||
pub use manager::*;
|
pub use manager::*;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
|
|
||||||
mod core;
|
mod core;
|
||||||
|
mod db;
|
||||||
mod display;
|
mod display;
|
||||||
mod picker;
|
mod picker;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
@ -92,7 +93,10 @@ async fn play_mode(target_mode: AmbientLightMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[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()
|
tauri::Builder::default()
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
take_snapshot,
|
take_snapshot,
|
||||||
|
@ -31,7 +31,7 @@ impl MqttRpc {
|
|||||||
match eventloop.poll().await {
|
match eventloop.poll().await {
|
||||||
Ok(notification) => {
|
Ok(notification) => {
|
||||||
let handled = || -> anyhow::Result<()> {
|
let handled = || -> anyhow::Result<()> {
|
||||||
println!("MQTT notification = {:?}", notification);
|
// println!("MQTT notification = {:?}", notification);
|
||||||
if let Event::Incoming(notification) = notification {
|
if let Event::Incoming(notification) = notification {
|
||||||
if let Incoming::Publish(notification) = notification {
|
if let Incoming::Publish(notification) = notification {
|
||||||
match notification.topic.as_str() {
|
match notification.topic.as_str() {
|
||||||
|
Loading…
Reference in New Issue
Block a user