use std::{sync::{Arc, atomic::AtomicBool}, time::Instant}; use chrono::Utc; use serde_json::Value; use tokio::sync::{broadcast, RwLock}; use crate::{config::Config, db::Db, models::{ApiEvent, RuntimeSettings}, protocol::GreeClient}; #[derive(Clone)] pub struct AppState { pub db: Db, pub settings: Arc>, pub config: Arc, pub gree: GreeClient, pub events: broadcast::Sender, pub http: reqwest::Client, pub outdoor_temperature: Arc>>, pub debug_gree_frames: Arc, pub started: Instant, } impl AppState { pub fn broadcast(&self, event: impl Into, data: Value) { let _ = self.events.send(ApiEvent { event: event.into(), timestamp: Utc::now(), data, }); } pub fn log(&self, level: &str, kind: &str, message: &str, metadata: Value) { if let Err(err) = self.db.log_event(level, kind, message, &metadata) { tracing::warn!(error=?err, "cannot persist event log"); } self.broadcast("log.created", serde_json::json!({ "level": level, "kind": kind, "message": message, "metadata": metadata, })); if let Ok(handle) = tokio::runtime::Handle::try_current() { let state = self.clone(); let level = level.to_string(); let kind = kind.to_string(); let message = message.to_string(); handle.spawn(async move { crate::notifications::dispatch(state, level, kind, message, metadata).await; }); } } }