Files
snooze-pal/src/main.rs

82 lines
1.9 KiB
Rust

use std::sync::{Arc, Mutex};
use cron_tab::Cron;
use gpio_cdev::Chip;
use sea_orm::Database;
use tokio::net::TcpListener;
use utoipa::OpenApi;
use utoipa_axum::router::OpenApiRouter;
use utoipa_scalar::{Scalar, Servable};
use crate::{ringer::{BeepRinger, Ringer, SilentRinger}, scheduler::Scheduler};
mod scheduler;
mod ringer;
mod types;
mod resources;
mod dao;
mod model;
#[derive(Clone)]
struct AppState {
scheduler: Arc<Scheduler>
}
fn construct_ringer() -> Arc<Mutex<dyn Ringer>> {
let result = Chip::new("/dev/gpiochip0");
match result {
Ok(chip) => {
let chip = Arc::new(Mutex::new(chip));
Arc::new(Mutex::new(BeepRinger::new(chip))) as Arc<Mutex<dyn Ringer>>
},
Err(e) => {
println!("Error opening chip (falling back to silent ringer): {}", e);
Arc::new(Mutex::new(SilentRinger::new())) as Arc<Mutex<dyn Ringer>>
}
}
}
async fn app_state() -> AppState {
let cron = Arc::new(Mutex::new(Cron::new(chrono::Local)));
let db = Database::connect("sqlite://snooze-pal.db").await.unwrap();
let ringer = construct_ringer();
AppState {
scheduler: Arc::new(Scheduler::new(
ringer,
cron.clone(),
Arc::new(db)
))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app_state = app_state().await;
app_state.scheduler.start().await;
start_axum_server(app_state).await;
Ok(())
}
#[derive(OpenApi)]
struct ApiDocs;
async fn start_axum_server(app_state: AppState) {
let docs = ApiDocs::openapi();
let (router, spec) = OpenApiRouter::<AppState>::with_openapi(docs)
.nest("/v1", resources::router())
.with_state(app_state)
.split_for_parts();
let router = router.merge(Scalar::with_url("/docs", spec));
let listener = TcpListener::bind("0.0.0.0:8080")
.await.expect("Failed to bind to port 8080. It may be taken by another process.");
axum::serve(listener, router)
.await.expect("Failed to serve");
}