diff --git a/src-tauri/src/display/manager.rs b/src-tauri/src/display/manager.rs index 73424b7..c4bf61c 100644 --- a/src-tauri/src/display/manager.rs +++ b/src-tauri/src/display/manager.rs @@ -5,14 +5,16 @@ use std::{ use ddc_hi::Display; use paris::{error, info, warn}; -use tokio::sync::{OnceCell, RwLock}; - -use super::{display_state::DisplayState, display_handler::DisplayHandler}; +use tokio::{sync::{watch, OnceCell, RwLock}, task::yield_now}; +use crate::rpc::{BoardMessageChannels, DisplaySetting}; +use super::{display_handler::DisplayHandler, display_state::DisplayState}; pub struct DisplayManager { displays: Arc>>>>, + setting_request_handler: Option>, + displays_changed_sender: Arc>>, } impl DisplayManager { @@ -23,10 +25,16 @@ impl DisplayManager { } pub async fn create() -> Self { - let instance = Self { + let (displays_changed_sender, _) = watch::channel(Vec::new()); + let displays_changed_sender = Arc::new(displays_changed_sender); + + let mut instance = Self { displays: Arc::new(RwLock::new(Vec::new())), + setting_request_handler: None, + displays_changed_sender, }; instance.fetch_displays().await; + instance.subscribe_setting_request(); instance } @@ -60,19 +68,57 @@ impl DisplayManager { states } - // pub async fn subscribe_display_brightness(&self) { - // let rpc = rpc::Manager::global().await; + fn subscribe_setting_request(&mut self) { + let displays = self.displays.clone(); + let displays_changed_sender = self.displays_changed_sender.clone(); + log::info!("start display setting request handler"); + let handler = tokio::spawn(async move { + let channels = BoardMessageChannels::global().await; - // let mut rx = rpc.client().subscribe_change_display_brightness_rx(); + let mut request_rx = channels.display_setting_request_sender.subscribe(); - // 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); - // } - // } - // } - // } + log::info!("display setting request handler started"); + + while let Ok(message) = request_rx.recv().await { + let displays = displays.write().await; + + let display = displays.get(message.display_index); + if display.is_none() { + warn!("display#{} not found", message.display_index); + continue; + } + + log::info!("display setting request received. {:?}", message); + + let display = display.unwrap().write().await; + match message.setting { + DisplaySetting::Brightness(value) => display.set_brightness(value as u16).await, + DisplaySetting::Contrast(value) => display.set_contrast(value as u16).await, + DisplaySetting::Mode(value) => display.set_mode(value as u16).await, + } + drop(display); + + log::info!("display setting request handled. {:?}", message); + + let mut states = Vec::new(); + for display in displays.iter() { + let state = display.read().await.state.read().await.clone(); + states.push(state); + } + + if let Err(err) = displays_changed_sender.send(states) { + error!("failed to send displays changed event: {}", err); + } + yield_now().await; + } + }); + + self.setting_request_handler = Some(handler); + } + + pub fn subscribe_displays_changed(&self) -> watch::Receiver> { + self.displays_changed_sender.subscribe() + } // fn read_display_config_by_ddc(index: usize) -> anyhow::Result { // let mut displays = Display::enumerate(); @@ -208,3 +254,11 @@ impl DisplayManager { // Ok(()) // } } + +impl Drop for DisplayManager { + fn drop(&mut self) { + if let Some(handler) = self.setting_request_handler.take() { + handler.abort(); + } + } +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e30b2f2..c8da01c 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -450,6 +450,20 @@ async fn main() { } }); + let app_handle = app.handle().clone(); + tokio::spawn(async move { + let display_manager = DisplayManager::global().await; + let mut rx =display_manager.subscribe_displays_changed(); + + while rx.changed().await.is_ok() { + let displays = rx.borrow().clone(); + + log::info!("displays changed. emit displays_changed event."); + + app_handle.emit_all("displays_changed", displays).unwrap(); + } + }); + Ok(()) }) .run(tauri::generate_context!()) diff --git a/src-tauri/src/rpc/board.rs b/src-tauri/src/rpc/board.rs index c8cbbce..4f64f3a 100644 --- a/src-tauri/src/rpc/board.rs +++ b/src-tauri/src/rpc/board.rs @@ -1,9 +1,11 @@ use std::{sync::Arc, time::Duration}; -use paris::{info, warn, error}; -use tokio::{net::UdpSocket, sync::RwLock, time::timeout, io}; +use paris::{error, info, warn}; +use tokio::{io, net::UdpSocket, sync::RwLock, time::timeout, task::yield_now}; -use super::{BoardConnectStatus, BoardInfo}; +use crate::rpc::DisplaySettingRequest; + +use super::{BoardConnectStatus, BoardInfo, UdpRpc}; #[derive(Debug)] pub struct Board { @@ -31,16 +33,34 @@ impl Board { let info = self.info.clone(); - let handler=tokio::spawn(async move { + let handler = tokio::spawn(async move { let mut buf = [0u8; 128]; if let Err(err) = socket.readable().await { error!("socket read error: {:?}", err); return; } + + let board_message_channels = crate::rpc::channels::BoardMessageChannels::global().await; + + let display_setting_request_sender = board_message_channels.display_setting_request_sender.clone(); + loop { match socket.try_recv(&mut buf) { Ok(len) => { log::info!("recv: {:?}", &buf[..len]); + if buf[0] == 3 { + let result = display_setting_request_sender.send(DisplaySettingRequest { + display_index: buf[1] as usize, + setting: crate::rpc::DisplaySetting::Brightness(buf[2]), + }); + + if let Err(err) = result { + error!("send display setting request to channel failed: {:?}", err); + } else { + info!("send display setting request to channel success"); + yield_now().await; + } + } } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { continue; @@ -125,7 +145,6 @@ impl Board { } } - impl Drop for Board { fn drop(&mut self) { if let Some(handler) = self.listen_handler.take() { @@ -136,4 +155,4 @@ impl Drop for Board { info!("listen handler aborted"); } } -} \ No newline at end of file +} diff --git a/src-tauri/src/rpc/channels.rs b/src-tauri/src/rpc/channels.rs new file mode 100644 index 0000000..8e7a20d --- /dev/null +++ b/src-tauri/src/rpc/channels.rs @@ -0,0 +1,26 @@ +use std::sync::Arc; + +use tokio::sync::{broadcast, OnceCell}; + +use super::DisplaySettingRequest; + +pub struct BoardMessageChannels { + pub display_setting_request_sender: Arc>, +} + +impl BoardMessageChannels { + pub async fn global() -> &'static Self { + static BOARD_MESSAGE_CHANNELS: OnceCell = OnceCell::const_new(); + + BOARD_MESSAGE_CHANNELS.get_or_init(|| async {Self::new()}).await + } + + pub fn new() -> Self { + let (display_setting_request_sender, _) = broadcast::channel(16); + let display_setting_request_sender = Arc::new(display_setting_request_sender); + + Self { + display_setting_request_sender, + } + } +} \ No newline at end of file diff --git a/src-tauri/src/rpc/display_setting_request.rs b/src-tauri/src/rpc/display_setting_request.rs new file mode 100644 index 0000000..682d4b2 --- /dev/null +++ b/src-tauri/src/rpc/display_setting_request.rs @@ -0,0 +1,13 @@ + +#[derive(Clone, Debug)] +pub enum DisplaySetting { + Brightness(u8), + Contrast(u8), + Mode(u8), +} + +#[derive(Clone, Debug)] +pub struct DisplaySettingRequest { + pub display_index: usize, + pub setting: DisplaySetting, +} \ No newline at end of file diff --git a/src-tauri/src/rpc/mod.rs b/src-tauri/src/rpc/mod.rs index b2f3cd5..1a32233 100644 --- a/src-tauri/src/rpc/mod.rs +++ b/src-tauri/src/rpc/mod.rs @@ -2,8 +2,12 @@ mod board_info; mod mqtt; mod udp; mod board; +mod display_setting_request; +mod channels; pub use board_info::*; pub use mqtt::*; pub use udp::*; pub use board::*; +pub use display_setting_request::*; +pub use channels::*; diff --git a/src-tauri/src/rpc/udp.rs b/src-tauri/src/rpc/udp.rs index 3d6f5b7..1ef01ae 100644 --- a/src-tauri/src/rpc/udp.rs +++ b/src-tauri/src/rpc/udp.rs @@ -1,14 +1,11 @@ -use std::{collections::HashMap, net::Ipv4Addr, sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use futures::future::join_all; use mdns_sd::{ServiceDaemon, ServiceEvent}; use paris::{error, info, warn}; -use tokio::{ - net::UdpSocket, - sync::{watch, OnceCell, RwLock}, -}; +use tokio::sync::{watch, OnceCell, RwLock, broadcast}; -use super::{Board, BoardInfo}; +use super::{Board, BoardInfo, DisplaySettingRequest}; #[derive(Debug, Clone)] pub struct UdpRpc { @@ -212,7 +209,7 @@ impl UdpRpc { if let Err(err) = board_change_sender.send(tx_boards) { error!("failed to send board change: {:?}", err); } - + drop(board_change_sender); } }