first commit
This commit is contained in:
+96
@@ -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 => {} }
|
||||
}
|
||||
Reference in New Issue
Block a user