This commit is contained in:
Mateusz Gruszczyński
2026-08-27 22:00:13 +02:00
parent 4cc4378588
commit b93a1f2d92
16 changed files with 196 additions and 64 deletions
+36 -1
View File
@@ -1,4 +1,4 @@
use std::{collections::HashSet, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::{Arc, Mutex, atomic::{AtomicBool, Ordering}}, time::Duration};
use std::{collections::{HashMap, HashSet}, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::{Arc, Mutex, atomic::{AtomicBool, AtomicU64, Ordering}}, time::Duration};
use anyhow::{anyhow, bail, Context, Result};
use chrono::Utc;
use serde_json::{json, Value};
@@ -22,6 +22,8 @@ pub struct GreeClient {
interface: Option<String>,
debug_events: Option<broadcast::Sender<ApiEvent>>,
debug_gree_frames: Arc<AtomicBool>,
received_frames_total: Arc<AtomicU64>,
received_frames_by_device: Arc<Mutex<HashMap<String, u64>>>,
buzzer_unsupported: Arc<Mutex<HashSet<String>>>,
quiet_unsupported: Arc<Mutex<HashSet<String>>>,
sleep_unsupported: Arc<Mutex<HashSet<String>>>,
@@ -39,12 +41,43 @@ impl GreeClient {
interface,
debug_events,
debug_gree_frames,
received_frames_total: Arc::new(AtomicU64::new(0)),
received_frames_by_device: Arc::new(Mutex::new(HashMap::new())),
buzzer_unsupported: Arc::new(Mutex::new(HashSet::new())),
quiet_unsupported: Arc::new(Mutex::new(HashSet::new())),
sleep_unsupported: Arc::new(Mutex::new(HashSet::new())),
}
}
pub fn received_frame_stats(&self) -> (u64, HashMap<String, u64>) {
let total = self.received_frames_total.load(Ordering::Relaxed);
let by_device = self.received_frames_by_device.lock()
.map(|counts| counts.clone())
.unwrap_or_default();
(total, by_device)
}
fn record_received_frame(&self, device: &Device) {
let total = self.received_frames_total.fetch_add(1, Ordering::Relaxed).saturating_add(1);
let device_count = self.received_frames_by_device.lock().ok().map(|mut counts| {
let count = counts.entry(device.id.clone()).or_insert(0);
*count = (*count).saturating_add(1);
*count
}).unwrap_or(0);
if let Some(events) = &self.debug_events {
let _ = events.send(ApiEvent {
event: "gree.frame_received".into(),
timestamp: Utc::now(),
data: json!({
"device_id": device.id,
"device_name": device.name,
"total": total,
"device_count": device_count,
}),
});
}
}
fn debug_frame(&self, direction: &str, device: &Device, target: SocketAddr, protocol: u8, payload: &Value) {
if !self.debug_gree_frames.load(Ordering::Relaxed) { return; }
let Some(events) = &self.debug_events else { return; };
@@ -323,6 +356,7 @@ impl GreeClient {
let remaining = scan_deadline.saturating_duration_since(Instant::now());
match timeout(remaining, socket.recv_from(&mut scan_buf)).await {
Ok(Ok((_size, source))) if source.ip() == target.ip() => {
self.record_received_frame(device);
tracing::debug!(device=%device.id, source=%source, "Received scan response immediately before bind");
break;
}
@@ -667,6 +701,7 @@ impl GreeClient {
Err(_) => break,
};
if source.ip() != target.ip() { continue; }
self.record_received_frame(device);
let response: Value = match serde_json::from_slice(&buffer[..size]) {
Ok(value) => value,
Err(err) => { last_decode_error = Some(anyhow!("invalid GREE JSON response: {err}")); continue; }