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",
|
||||
"once_cell",
|
||||
"paris",
|
||||
"redb",
|
||||
"rumqttc",
|
||||
"scrap",
|
||||
"serde",
|
||||
@ -2732,6 +2733,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
@ -2868,6 +2879,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@ -3614,6 +3635,12 @@ dependencies = [
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "1.2.3"
|
||||
|
@ -37,14 +37,15 @@ image = "0.24.5"
|
||||
mdns = "3.0.0"
|
||||
macos-app-nap = "0.0.1"
|
||||
ddc-hi = "0.4.1"
|
||||
redb = "0.13.0"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = [ "custom-protocol" ]
|
||||
default = ["custom-protocol"]
|
||||
# this feature is used used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[dev-dependencies]
|
||||
test_dir = "0.2.0"
|
||||
|
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)]
|
||||
pub enum Brightness {
|
||||
Relative(u16),
|
||||
Relative(i16),
|
||||
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 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<()> {
|
||||
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 display.handle.get_vcp_feature(0x10) {
|
||||
Ok(curr_brightness) => {
|
||||
let curr = curr_brightness.value();
|
||||
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) => v + curr,
|
||||
Brightness::Relative(v) => curr.wrapping_add_signed(v),
|
||||
Brightness::Absolute(v) => v,
|
||||
};
|
||||
if target.gt(&curr_brightness.maximum()) {
|
||||
target = curr_brightness.maximum();
|
||||
} else if target.lt(&0) {
|
||||
target = 0;
|
||||
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)
|
||||
.set_vcp_feature(0x10, target as u16)
|
||||
.map_err(|err| anyhow::anyhow!("can not set brightness. {:?}", err))?;
|
||||
}
|
||||
Err(err) => {
|
||||
@ -61,18 +161,15 @@ impl Manager {
|
||||
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))?;
|
||||
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(())
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod brightness;
|
||||
mod manager;
|
||||
mod display_config;
|
||||
|
||||
pub use brightness::*;
|
||||
pub use manager::*;
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user