feat: 支持 MQTT 上报灯条颜色数据
This commit is contained in:
parent
d4709b9404
commit
c56304a6ba
206
src-tauri/Cargo.lock
generated
206
src-tauri/Cargo.lock
generated
@ -636,6 +636,19 @@ dependencies = [
|
|||||||
"miniz_oxide 0.5.4",
|
"miniz_oxide 0.5.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.10.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"nanorand",
|
||||||
|
"pin-project",
|
||||||
|
"spin 0.9.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -676,6 +689,21 @@ dependencies = [
|
|||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
@ -683,6 +711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -719,6 +748,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
@ -731,9 +766,13 @@ version = "0.3.25"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"slab",
|
"slab",
|
||||||
@ -861,8 +900,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1457,6 +1498,15 @@ dependencies = [
|
|||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nanorand"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@ -1915,6 +1965,26 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-internal"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@ -1971,6 +2041,12 @@ dependencies = [
|
|||||||
"miniz_oxide 0.6.2",
|
"miniz_oxide 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pollster"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@ -2220,6 +2296,40 @@ dependencies = [
|
|||||||
"windows 0.37.0",
|
"windows 0.37.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.16.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"spin 0.5.2",
|
||||||
|
"untrusted",
|
||||||
|
"web-sys",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rumqttc"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "499b7ab08ffa5a722958b6ce1b7c0270bea30909f589d12c5ec3a051afe423fc"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"flume",
|
||||||
|
"futures",
|
||||||
|
"http",
|
||||||
|
"log",
|
||||||
|
"pollster",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"rustls-pemfile 0.3.0",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -2238,6 +2348,48 @@ dependencies = [
|
|||||||
"semver 1.0.14",
|
"semver 1.0.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.20.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"ring",
|
||||||
|
"sct",
|
||||||
|
"webpki",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pemfile 1.0.1",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
@ -2309,17 +2461,29 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paris",
|
"paris",
|
||||||
|
"rumqttc",
|
||||||
"scrap",
|
"scrap",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"webp",
|
"webp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sct"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
@ -2596,6 +2760,21 @@ dependencies = [
|
|||||||
"system-deps 5.0.0",
|
"system-deps 5.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -3079,6 +3258,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
"webpki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
@ -3198,6 +3388,12 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@ -3417,6 +3613,16 @@ dependencies = [
|
|||||||
"libwebp-sys",
|
"libwebp-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki"
|
||||||
|
version = "0.22.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.19.1"
|
version = "0.19.1"
|
||||||
|
@ -28,6 +28,8 @@ tokio = { version = "1.22.0", features = ["full"] }
|
|||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = "0.3.16"
|
tracing-subscriber = "0.3.16"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
rumqttc = "0.17.0"
|
||||||
|
time = { version = "0.3.17", features = ["formatting"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# by default Tauri runs in production mode
|
# by default Tauri runs in production mode
|
||||||
|
@ -3,21 +3,19 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
mod led_color;
|
mod picker;
|
||||||
mod screen;
|
mod rpc;
|
||||||
mod screen_color_picker;
|
|
||||||
|
|
||||||
use led_color::LedColor;
|
|
||||||
use paris::*;
|
use paris::*;
|
||||||
use screen_color_picker::ScreenColorPicker;
|
use picker::led_color::LedColor;
|
||||||
|
use picker::manager::Picker;
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Mutex},
|
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn refresh_displays() {
|
async fn refresh_displays() {
|
||||||
match ScreenColorPicker::global().refresh_displays() {
|
match Picker::global().refresh_displays().await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("{}", error)
|
error!("{}", error)
|
||||||
@ -26,67 +24,39 @@ fn refresh_displays() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn take_snapshot() -> Arc<Mutex<Vec<String>>> {
|
async fn take_snapshot() -> Vec<String> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
let manager = Picker::global();
|
||||||
|
|
||||||
let screenshot_futures = match ScreenColorPicker::global().take_screenshots_for_all() {
|
match manager.take_screenshots_for_all().await {
|
||||||
Ok(bitmaps) => {
|
Ok(screenshots) => {
|
||||||
info!("bitmaps len: {}", bitmaps.len());
|
info!("screenshots len: {}", screenshots.len());
|
||||||
match ScreenColorPicker::global().screens.lock() {
|
let mut futures = Vec::new();
|
||||||
Ok(screens) => Some(Vec::from_iter(screens.iter().enumerate().map(
|
for screenshot in screenshots {
|
||||||
|(index, screen)| {
|
let future = screenshot.to_webp_base64().await;
|
||||||
bitmap_to_webp_base64(screen.width, screen.height, bitmaps[index].to_vec())
|
futures.push(future);
|
||||||
},
|
|
||||||
))),
|
|
||||||
Err(error) => {
|
|
||||||
error!("can not lock screens. {}", error);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
futures
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("can not take screenshots for all. {}", error);
|
error!("can not take screenshots for all. {}", error);
|
||||||
None
|
vec![]
|
||||||
}
|
}
|
||||||
};
|
|
||||||
match screenshot_futures {
|
|
||||||
Some(futures) => {
|
|
||||||
let mut handles = Vec::with_capacity(futures.len());
|
|
||||||
|
|
||||||
for fut in futures {
|
|
||||||
handles.push(tokio::spawn(fut));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut results = Vec::with_capacity(handles.len());
|
|
||||||
for handle in handles {
|
|
||||||
results.push(handle.await.unwrap());
|
|
||||||
}
|
|
||||||
println!("运行耗时: {:?}", start.elapsed());
|
|
||||||
Arc::new(Mutex::new(results))
|
|
||||||
}
|
|
||||||
None => Arc::new(Mutex::new(Vec::new())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn get_led_strip_colors() -> Result<Vec<LedColor>, String> {
|
async fn get_led_strip_colors() -> Result<Vec<LedColor>, String> {
|
||||||
let screens = ScreenColorPicker::global()
|
let colors = Picker::global().get_led_strip_colors().await;
|
||||||
.screens
|
match colors {
|
||||||
.lock()
|
Ok(colors) => {
|
||||||
.map_err(|error| {
|
rpc::manager::Manager::global()
|
||||||
error!("can not lock ScreenColorPick.screens. {}", error);
|
.publish_led_colors(&colors)
|
||||||
"failed to lock."
|
.await;
|
||||||
})?;
|
Ok(colors)
|
||||||
let mut colors = Vec::new();
|
|
||||||
for screen in screens.iter() {
|
|
||||||
let result = screen.get_top_colors();
|
|
||||||
if let Ok(result) = result {
|
|
||||||
colors.extend_from_slice(&result);
|
|
||||||
} else if let Err(result) = result {
|
|
||||||
return Err(format!("can not get led strip colors. {}", result));
|
|
||||||
}
|
}
|
||||||
|
Err(error) => Err(format!("{}", error)),
|
||||||
}
|
}
|
||||||
Ok(colors)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn bitmap_to_webp_base64(width: usize, height: usize, bitmap: Vec<u8>) -> String {
|
async fn bitmap_to_webp_base64(width: usize, height: usize, bitmap: Vec<u8>) -> String {
|
||||||
@ -111,7 +81,9 @@ async fn bitmap_to_webp_base64(width: usize, height: usize, bitmap: Vec<u8>) ->
|
|||||||
return base64::encode(&*webp_memory);
|
return base64::encode(&*webp_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
rpc::manager::Manager::global();
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
take_snapshot,
|
take_snapshot,
|
||||||
|
82
src-tauri/src/picker/manager.rs
Normal file
82
src-tauri/src/picker/manager.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use paris::*;
|
||||||
|
use scrap::{Capturer, Display};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use crate::picker::screen::Screen;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
led_color::LedColor,
|
||||||
|
screenshot::{Screenshot},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Picker {
|
||||||
|
pub screens: Arc<Mutex<Vec<Screen>>>,
|
||||||
|
pub screenshots: Arc<Mutex<Vec<Screenshot>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Picker {
|
||||||
|
pub fn global() -> &'static Picker {
|
||||||
|
static SCREEN_COLOR_PICKER: OnceCell<Picker> = OnceCell::new();
|
||||||
|
|
||||||
|
SCREEN_COLOR_PICKER.get_or_init(|| Picker {
|
||||||
|
screens: Arc::new(Mutex::new(vec![])),
|
||||||
|
screenshots: Arc::new(Mutex::new(vec![])),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn refresh_displays(&self) -> anyhow::Result<()> {
|
||||||
|
let displays = Display::all()
|
||||||
|
.map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
|
||||||
|
let mut screens = self.screens.lock().await;
|
||||||
|
let mut screenshots = self.screenshots.lock().await;
|
||||||
|
screens.clear();
|
||||||
|
info!("number of displays: {}", displays.len());
|
||||||
|
for display in displays {
|
||||||
|
let height = display.height();
|
||||||
|
let width = display.width();
|
||||||
|
match Capturer::new(display) {
|
||||||
|
Ok(capturer) => screens.push(Screen::new(capturer, width, height)),
|
||||||
|
Err(error) => screens.push(Screen::new_failed(
|
||||||
|
anyhow::anyhow!("{}", error),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
screenshots.push(Screenshot::new(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
screens.reverse();
|
||||||
|
screenshots.reverse();
|
||||||
|
screenshots[0].set_number_of_leds(22, 0);
|
||||||
|
screenshots[1].set_number_of_leds(38, 0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn take_screenshots_for_all(&self) -> anyhow::Result<Vec<Screenshot>> {
|
||||||
|
let mut screens = self.screens.lock().await;
|
||||||
|
let mut screenshots = self.screenshots.lock().await;
|
||||||
|
for (index, screen) in screens.iter_mut().enumerate() {
|
||||||
|
let bitmap = screen.take().map_err(|error| {
|
||||||
|
anyhow::anyhow!("take screenshot for display failed. {}", error)
|
||||||
|
})?;
|
||||||
|
screenshots[index].set_bitmap(bitmap).await
|
||||||
|
}
|
||||||
|
Ok(screenshots.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_led_strip_colors(&self) -> anyhow::Result<Vec<LedColor>> {
|
||||||
|
let screenshots = self.screenshots.lock().await;
|
||||||
|
let mut colors = Vec::new();
|
||||||
|
for screenshot in screenshots.iter() {
|
||||||
|
let result = screenshot
|
||||||
|
.get_top_colors()
|
||||||
|
.await
|
||||||
|
.map_err(|error| anyhow::anyhow!("get top colors failed. {}", error))?;
|
||||||
|
colors.extend_from_slice(&result);
|
||||||
|
}
|
||||||
|
Ok(colors)
|
||||||
|
}
|
||||||
|
}
|
4
src-tauri/src/picker/mod.rs
Normal file
4
src-tauri/src/picker/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod led_color;
|
||||||
|
pub mod screen;
|
||||||
|
pub mod manager;
|
||||||
|
pub mod screenshot;
|
43
src-tauri/src/picker/screen.rs
Normal file
43
src-tauri/src/picker/screen.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
use scrap::Capturer;
|
||||||
|
|
||||||
|
pub struct Screen {
|
||||||
|
capturer: Option<Capturer>,
|
||||||
|
init_error: Option<anyhow::Error>,
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Screen {
|
||||||
|
pub fn new(capturer: Capturer, width: usize, height: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
capturer: Some(capturer),
|
||||||
|
init_error: None,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_failed(init_error: anyhow::Error, width: usize, height: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
capturer: None,
|
||||||
|
init_error: Some(init_error),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(&mut self) -> anyhow::Result<Vec<u8>> {
|
||||||
|
match self.capturer.as_mut() {
|
||||||
|
Some(capturer) => {
|
||||||
|
let buffer = capturer
|
||||||
|
.frame()
|
||||||
|
.map_err(|error| anyhow::anyhow!("failed to frame of display. {}", error))?;
|
||||||
|
anyhow::Ok(buffer.to_vec())
|
||||||
|
}
|
||||||
|
None => anyhow::bail!("Do not initialized"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Screen {}
|
@ -1,81 +1,53 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use anyhow::Ok;
|
use super::led_color::LedColor;
|
||||||
use scrap::Capturer;
|
|
||||||
|
|
||||||
use crate::led_color::LedColor;
|
#[derive(Clone)]
|
||||||
|
pub struct Screenshot {
|
||||||
pub struct Screen {
|
|
||||||
bitmap: Arc<Mutex<Option<Vec<u8>>>>,
|
bitmap: Arc<Mutex<Option<Vec<u8>>>>,
|
||||||
capturer: Option<Capturer>,
|
width: usize,
|
||||||
init_error: Option<anyhow::Error>,
|
height: usize,
|
||||||
pub width: usize,
|
led_number_of_x: usize,
|
||||||
pub height: usize,
|
led_number_of_y: usize,
|
||||||
pub led_number_of_x: usize,
|
|
||||||
pub led_number_of_y: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screen {
|
impl Screenshot {
|
||||||
pub fn new(capturer: Capturer, width: usize, height: usize) -> Self {
|
pub fn new(width: usize, height: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bitmap: Arc::new(Mutex::new(None)),
|
bitmap: Arc::new(Mutex::new(None)),
|
||||||
capturer: Some(capturer),
|
|
||||||
init_error: None,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
led_number_of_x: 0,
|
led_number_of_x: 0,
|
||||||
led_number_of_y: 0,
|
led_number_of_y: 0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_failed(init_error: anyhow::Error, width: usize, height: usize) -> Self {
|
pub fn get_size(&self) -> (usize, usize) {
|
||||||
Self {
|
(self.width, self.height)
|
||||||
bitmap: Arc::new(Mutex::new(None)),
|
|
||||||
capturer: None,
|
|
||||||
init_error: Some(init_error),
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
led_number_of_x: 0,
|
|
||||||
led_number_of_y: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_number_of_leds(&mut self, led_number_of_x: usize, led_number_of_y: usize) -> &Self {
|
pub fn get_number_of_leds(&self) -> (usize, usize) {
|
||||||
|
(self.led_number_of_x, self.led_number_of_y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_number_of_leds(&mut self, led_number_of_x: usize, led_number_of_y: usize) {
|
||||||
self.led_number_of_x = led_number_of_x;
|
self.led_number_of_x = led_number_of_x;
|
||||||
self.led_number_of_y = led_number_of_y;
|
self.led_number_of_y = led_number_of_y;
|
||||||
self
|
}
|
||||||
|
pub async fn get_top_colors(&self) -> anyhow::Result<Vec<LedColor>> {
|
||||||
|
self.get_x_colors(XPosition::Top).await
|
||||||
|
}
|
||||||
|
pub async fn get_bottom_colors(&self) -> anyhow::Result<Vec<LedColor>> {
|
||||||
|
self.get_x_colors(XPosition::Bottom).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take(&mut self) -> anyhow::Result<Vec<u8>> {
|
async fn get_x_colors(&self, position: XPosition) -> anyhow::Result<Vec<LedColor>> {
|
||||||
match self.capturer.as_mut() {
|
|
||||||
Some(capturer) => {
|
|
||||||
let buffer = capturer
|
|
||||||
.frame()
|
|
||||||
.map_err(|error| anyhow::anyhow!("failed to frame of display. {}", error))?;
|
|
||||||
|
|
||||||
self.bitmap = Arc::new(Mutex::new(Some(buffer.to_vec())));
|
|
||||||
anyhow::Ok(buffer.to_vec())
|
|
||||||
}
|
|
||||||
None => anyhow::bail!("Do not initialized"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_top_colors(&self) -> anyhow::Result<Vec<LedColor>> {
|
|
||||||
self.get_x_colors(XPosition::Top)
|
|
||||||
}
|
|
||||||
pub fn get_bottom_colors(&self) -> anyhow::Result<Vec<LedColor>> {
|
|
||||||
self.get_x_colors(XPosition::Bottom)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_x_colors(&self, position: XPosition) -> anyhow::Result<Vec<LedColor>> {
|
|
||||||
if self.led_number_of_x == 0 {
|
if self.led_number_of_x == 0 {
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bitmap = self
|
let bitmap = self.bitmap.lock().await;
|
||||||
.bitmap
|
|
||||||
.lock()
|
|
||||||
.map_err(|error| anyhow::anyhow!("can not lock Screen#bitmap. {}", error))?;
|
|
||||||
match bitmap.as_ref() {
|
match bitmap.as_ref() {
|
||||||
Some(bitmap) => {
|
Some(bitmap) => {
|
||||||
let cell_size_x = self.width / self.led_number_of_x;
|
let cell_size_x = self.width / self.led_number_of_x;
|
||||||
@ -90,8 +62,6 @@ impl Screen {
|
|||||||
let stride = bitmap.len() / self.height;
|
let stride = bitmap.len() / self.height;
|
||||||
|
|
||||||
for pos in 0..self.led_number_of_x {
|
for pos in 0..self.led_number_of_x {
|
||||||
let mut y_range = y_range.to_owned();
|
|
||||||
|
|
||||||
let mut r = 0u32;
|
let mut r = 0u32;
|
||||||
let mut g = 0u32;
|
let mut g = 0u32;
|
||||||
let mut b = 0u32;
|
let mut b = 0u32;
|
||||||
@ -114,9 +84,40 @@ impl Screen {
|
|||||||
None => Ok(vec![]),
|
None => Ok(vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Screen {}
|
pub async fn set_bitmap(&mut self, bitmap: Vec<u8>) {
|
||||||
|
let mut self_bitmap = self.bitmap.lock().await;
|
||||||
|
*self_bitmap = Some(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn to_webp_base64(&self) -> String {
|
||||||
|
let bitmap = self.bitmap.lock().await;
|
||||||
|
match bitmap.to_owned() {
|
||||||
|
Some(bitmap) => {
|
||||||
|
let mut bitflipped = Vec::with_capacity(self.width * self.height * 3);
|
||||||
|
let stride = bitmap.len() / self.height;
|
||||||
|
|
||||||
|
for y in 0..self.height {
|
||||||
|
for x in 0..self.width {
|
||||||
|
let i = stride * y + 4 * x;
|
||||||
|
bitflipped.extend_from_slice(&[bitmap[i + 2], bitmap[i + 1], bitmap[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let webp_memory = webp::Encoder::from_rgb(
|
||||||
|
bitflipped.as_slice(),
|
||||||
|
self.width as u32,
|
||||||
|
self.height as u32,
|
||||||
|
)
|
||||||
|
.encode(100.0);
|
||||||
|
return base64::encode(&*webp_memory);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
"".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum XPosition {
|
enum XPosition {
|
||||||
Top,
|
Top,
|
41
src-tauri/src/rpc/manager.rs
Normal file
41
src-tauri/src/rpc/manager.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::picker::led_color::LedColor;
|
||||||
|
|
||||||
|
use super::mqtt::MqttConnection;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
pub struct Manager {
|
||||||
|
mqtt: MqttConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Manager {
|
||||||
|
pub fn global() -> &'static Self {
|
||||||
|
static RPC_MANAGER: OnceCell<Manager> = OnceCell::new();
|
||||||
|
|
||||||
|
RPC_MANAGER.get_or_init(|| Manager::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut mqtt = MqttConnection::new();
|
||||||
|
mqtt.initialize();
|
||||||
|
Self { mqtt }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn publish_led_colors(&self, colors: &Vec<LedColor>) -> anyhow::Result<()> {
|
||||||
|
let payload = colors
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.get_rgb().clone())
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<u8>>();
|
||||||
|
|
||||||
|
self.mqtt
|
||||||
|
.client
|
||||||
|
.publish(
|
||||||
|
"screen-bg-light/desktop/colors",
|
||||||
|
rumqttc::QoS::AtMostOnce,
|
||||||
|
false,
|
||||||
|
payload,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error))
|
||||||
|
}
|
||||||
|
}
|
2
src-tauri/src/rpc/mod.rs
Normal file
2
src-tauri/src/rpc/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod manager;
|
||||||
|
pub mod mqtt;
|
66
src-tauri/src/rpc/mqtt.rs
Normal file
66
src-tauri/src/rpc/mqtt.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use rumqttc::{AsyncClient, MqttOptions, QoS};
|
||||||
|
use std::{time::Duration};
|
||||||
|
use time::{format_description, OffsetDateTime};
|
||||||
|
use tokio::task;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
pub struct MqttConnection {
|
||||||
|
pub client: AsyncClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MqttConnection {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut options = MqttOptions::new("rumqtt-async", "192.168.31.11", 1883);
|
||||||
|
options.set_keep_alive(Duration::from_secs(5));
|
||||||
|
|
||||||
|
let (mut client, mut eventloop) = AsyncClient::new(options, 10);
|
||||||
|
task::spawn(async move {
|
||||||
|
while let Ok(notification) = eventloop.poll().await {
|
||||||
|
println!("Received = {:?}", notification);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Self { client }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize(&mut self) {
|
||||||
|
self.subscribe_board();
|
||||||
|
self.broadcast_desktop_online();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscribe_board(&self) {
|
||||||
|
self.client
|
||||||
|
.subscribe("screen-bg-light/board/#", QoS::AtMostOnce);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn broadcast_desktop_online(&mut self) {
|
||||||
|
let client = self.client.to_owned();
|
||||||
|
task::spawn(async move {
|
||||||
|
loop {
|
||||||
|
match OffsetDateTime::now_utc()
|
||||||
|
.format(&format_description::well_known::Iso8601::DEFAULT)
|
||||||
|
{
|
||||||
|
Ok(now_str) => {
|
||||||
|
match client
|
||||||
|
.publish(
|
||||||
|
"screen-bg-light/desktop/last-online-at",
|
||||||
|
QoS::AtLeastOnce,
|
||||||
|
false,
|
||||||
|
now_str.as_bytes(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(error) => {
|
||||||
|
warn!("can not publish last online time. {}", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
warn!("can not get time for now. {}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokio::time::sleep(Duration::from_millis(1000)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
use once_cell::sync::OnceCell;
|
|
||||||
use paris::*;
|
|
||||||
use scrap::{Capturer, Display};
|
|
||||||
use tracing::field::display;
|
|
||||||
use std::{
|
|
||||||
borrow::BorrowMut,
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::screen::Screen;
|
|
||||||
|
|
||||||
pub struct ScreenColorPicker {
|
|
||||||
pub screens: Arc<Mutex<Vec<Screen>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ScreenColorPicker {
|
|
||||||
pub fn global() -> &'static ScreenColorPicker {
|
|
||||||
static SCREEN_COLOR_PICKER: OnceCell<ScreenColorPicker> = OnceCell::new();
|
|
||||||
|
|
||||||
SCREEN_COLOR_PICKER.get_or_init(|| ScreenColorPicker {
|
|
||||||
screens: Arc::new(Mutex::new(Vec::<Screen>::new())),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn refresh_displays(&self) -> anyhow::Result<()> {
|
|
||||||
let displays = Display::all()
|
|
||||||
.map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
|
|
||||||
let mut screens = self
|
|
||||||
.screens
|
|
||||||
.lock()
|
|
||||||
.map_err(|error| anyhow::anyhow!("lock screens failed. {}", error))?;
|
|
||||||
screens.clear();
|
|
||||||
info!("number of displays: {}", displays.len());
|
|
||||||
for display in displays {
|
|
||||||
let height = display.height();
|
|
||||||
let width = display.width();
|
|
||||||
match Capturer::new(display) {
|
|
||||||
Ok(capturer) => screens.push(Screen::new(capturer, width, height)),
|
|
||||||
Err(error) => screens.push(Screen::new_failed(
|
|
||||||
anyhow::anyhow!("{}", error),
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
screens.reverse();
|
|
||||||
screens[0].set_number_of_leds(22, 0);
|
|
||||||
screens[1].set_number_of_leds(38, 0);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_screenshots_for_all(&self) -> anyhow::Result<Vec<Vec<u8>>> {
|
|
||||||
let mut screens = self
|
|
||||||
.screens
|
|
||||||
.lock()
|
|
||||||
.map_err(|error| anyhow::anyhow!("lock screens failed. {}", error))?;
|
|
||||||
let mut screenshots = Vec::<Vec<u8>>::new();
|
|
||||||
for screen in screens.iter_mut() {
|
|
||||||
let screenshot = screen.take().map_err(|error| {
|
|
||||||
anyhow::anyhow!("take screenshot for display failed. {}", error)
|
|
||||||
})?;
|
|
||||||
screenshots.push(screenshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
anyhow::Ok(screenshots)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user