first commit

This commit is contained in:
Mateusz Gruszczyński
2026-08-23 21:34:07 +02:00
commit 1d3dcba1a9
62 changed files with 12456 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
mod api;
mod config;
mod db;
mod engine;
mod error;
mod home_assistant;
mod models;
mod protocol;
mod queries;
mod state;
use std::{sync::Arc, time::{Duration, Instant}};
use anyhow::{Context, Result};
use config::Config;
use db::Db;
use models::Device;
use protocol::GreeClient;
use state::AppState;
use tokio::{net::TcpListener, signal, sync::{broadcast, RwLock}};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
#[tokio::main]
async fn main() -> Result<()> {
let config = Config::load()?;
init_tracing();
let db = Db::open(&config.database)?;
let runtime_settings = db.load_runtime_settings()?.unwrap_or_else(|| config.runtime_defaults());
db.save_runtime_settings(&runtime_settings)?;
if config.simulate && config.auto_seed && db.count_devices()? == 0 {
db.save_device(&Device::simulated_default())?;
db.log_event(
"info",
"simulator.seeded",
"Created the default simulator device",
&serde_json::json!({"device_id":"sim-salon"}),
)?;
}
let (events, _) = broadcast::channel(256);
let http = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.user_agent(concat!("gree-controller/", env!("CARGO_PKG_VERSION")))
.build()?;
let state = AppState {
db,
settings: Arc::new(RwLock::new(runtime_settings.clone())),
config: Arc::new(config.clone()),
gree: GreeClient::new(runtime_settings.controller_id.clone()),
events,
http,
started: Instant::now(),
};
engine::start(state.clone());
let app = api::router(state.clone());
let listener = TcpListener::bind(config.bind).await
.with_context(|| format!("cannot bind HTTP server to {}", config.bind))?;
tracing::info!(
address = %config.bind,
database = %config.database.display(),
simulator = config.simulate,
auth = !config.app_token.trim().is_empty(),
"GREE Controller started"
);
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await?;
tracing::info!("GREE Controller stopped");
Ok(())
}
fn init_tracing() {
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info,tower_http=info".into());
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer().compact())
.init();
}
async fn shutdown_signal() {
let ctrl_c = async { signal::ctrl_c().await.expect("cannot install Ctrl+C handler"); };
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("cannot install SIGTERM handler")
.recv().await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! { _ = ctrl_c => {}, _ = terminate => {} }
}