mod command; mod http; mod panels; mod serialization; mod telemetry; use crate::command::service::CommandManagementService; use crate::panels::PanelService; use crate::telemetry::history::TelemetryHistoryService; use crate::telemetry::management_service::TelemetryManagementService; use log::{error, info}; use sqlx::sqlite::SqliteConnectOptions; use sqlx::SqlitePool; use std::path; use std::sync::Arc; use std::time::Duration; use tokio::time::sleep; use tokio_util::sync::CancellationToken; pub async fn setup() -> anyhow::Result<()> { let cancellation_token = CancellationToken::new(); { let cancellation_token = cancellation_token.clone(); tokio::spawn(async move { let _ = tokio::signal::ctrl_c().await; cancellation_token.cancel(); }); } let data_folder = path::absolute("data")?; let telemetry_folder = data_folder.join("telemetry"); let database_url = data_folder.join("database.db"); info!("Opening Database: {database_url:?}"); let sqlite = SqlitePool::connect_with( SqliteConnectOptions::new() .filename(database_url) .create_if_missing(true), ) .await?; sqlx::migrate!().run(&sqlite).await?; let tlm = Arc::new(TelemetryManagementService::new( TelemetryHistoryService::new(telemetry_folder)?, )?); let cmd = Arc::new(CommandManagementService::new()); let panel_service = PanelService::new(sqlite.clone()); let result = http::setup(cancellation_token.clone(), tlm.clone(), panel_service, cmd).await; cancellation_token.cancel(); result?; // result is dropped drop(cancellation_token); // All cancellation tokens are now dropped sqlite.close().await; // Perform cleanup functions - at this point all servers have stopped and we can be sure that cleaning things up is safe for _ in 0..15 { if Arc::strong_count(&tlm) != 1 { sleep(Duration::from_secs(1)).await; } } if let Some(tlm) = Arc::into_inner(tlm) { tlm.cleanup().await?; } else { error!("Could not clean up Telemetry Management Service. Arc not released.") } Ok(()) }