use futures::{future::join_all, stream::FuturesUnordered, StreamExt}; use once_cell::sync::OnceCell; use paris::info; use serde::{Deserialize, Serialize}; use serde_json::value::Index; use std::{collections::HashMap, iter::Map, sync::Arc, thread, time::Duration}; use tauri::async_runtime::RwLock; use tokio::{ join, sync::mpsc, task, time::{sleep, Instant}, }; use tracing::warn; use crate::{ picker::{ config::DisplayConfig, display_picker::DisplayPicker, led_color::LedColor, manager::Picker, screenshot::Screenshot, }, rpc, }; #[derive(Debug, Serialize, Deserialize)] pub enum AmbientLightMode { None, Follow, Flowing, } pub struct CoreManager { ambient_light_mode: Arc>, } impl CoreManager { pub fn global() -> &'static CoreManager { static CORE_MANAGER: OnceCell = OnceCell::new(); let core = CORE_MANAGER.get_or_init(|| CoreManager { ambient_light_mode: Arc::new(RwLock::new(AmbientLightMode::None)), }); tokio::spawn(async { loop { core.play_flowing_light().await; match core.play_follow().await { Ok(_) => {} Err(error) => { warn!("Can not following displays. {}", error); sleep(Duration::from_millis(1000)).await; } }; sleep(Duration::from_millis(10)).await; } }); core } pub async fn set_ambient_light(&self, target_mode: AmbientLightMode) { let mut mode = self.ambient_light_mode.write().await; *mode = target_mode; } pub async fn play_flowing_light(&self) { let mut hue = 0f64; let step_length = 2.0; loop { let lock = self.ambient_light_mode.read().await; if let AmbientLightMode::Flowing = *lock { let mut colors = Vec::::new(); for i in 0..60 { let color = LedColor::from_hsv((hue + i as f64 * step_length) % 360.0, 1.0, 0.5); colors.push(color); } hue = (hue + 1.0) % 360.0; match rpc::manager::Manager::global() .publish_led_colors(&colors) .await { Ok(_) => {} Err(error) => { warn!("publish led colors failed. {}", error); } } } else { break; } sleep(Duration::from_millis(50)).await; } } pub async fn play_follow(&self) -> anyhow::Result<()> { let lock = self.ambient_light_mode.read().await; let mut futs = vec![]; if let AmbientLightMode::Follow = *lock { drop(lock); let configs = Picker::global().display_configs.lock().await; let (tx, mut rx) = mpsc::channel(10); for config in configs.to_owned() { let tx = tx.clone(); let fut = tokio::spawn(async move { match Self::follow_display_by_config(config, tx).await { Ok(_) => {} Err(error) => { warn!("following failed. {}", error); } } }); futs.push(fut); } let configs = configs.clone(); tokio::spawn(async move { let mut global_colors = HashMap::new(); while let Some(screenshot) = rx.recv().await { let start_at = Instant::now(); match screenshot.get_top_colors().await { Ok(colors) => { let start = screenshot.get_top_of_led_start_at().min(screenshot.get_top_of_led_end_at()); let colors_len = colors.len(); for (index, color) in colors.into_iter().enumerate() { global_colors.insert(index + start, color); } info!("led count: {}, spend: {:?}", global_colors.len(), start_at.elapsed()); if global_colors.len() == 60 { let mut colors = vec![]; for index in 0..global_colors.len() { colors.push(*global_colors.get(&index).unwrap()); } global_colors = HashMap::new(); match rpc::manager::Manager::global() .publish_led_colors(&colors) .await { Ok(_) => { info!("publish successful",); } Err(error) => { warn!("publish led colors failed. {}", error); } } } } Err(_) => {} }; } }); join_all(futs).await; } else { drop(lock); return Ok(()); } Ok(()) } async fn follow_display_by_config( config: DisplayConfig, tx: mpsc::Sender, ) -> anyhow::Result<()> { let mut picker = DisplayPicker::from_config(config)?; info!("width: {}", picker.config.display_width); loop { let start = Instant::now(); let next_tick = start + Duration::from_millis(16); let lock = Self::global().ambient_light_mode.read().await; if let AmbientLightMode::Follow = *lock { drop(lock); let screenshot = picker.take_screenshot()?; info!("Take Screenshot Spend: {:?}", start.elapsed()); tx.send(screenshot).await; } else { break; } tokio::time::sleep_until(next_tick).await; } // // Picker::global().take_screenshots_for_all().await?; // // let colors = Picker::global().get_led_strip_colors().await?; // // let colors = colors.into_iter().rev().collect(); Ok(()) } }