From a86a28fd854293b1551afd68a7e48943a96489f4 Mon Sep 17 00:00:00 2001 From: quirinecker Date: Mon, 2 Mar 2026 20:39:08 +0100 Subject: [PATCH] same functionality now works with axum the same way it did with actix --- snooze-pal.db | Bin 20480 -> 20480 bytes src/main.rs | 22 +++++----- src/resources/alarm/mod.rs | 7 +-- src/resources/alarm/post.rs | 32 +++++++++++--- src/resources/mod.rs | 7 +-- src/ringer.rs | 83 ++++++++++++++++++++++-------------- src/scheduler.rs | 2 +- 7 files changed, 96 insertions(+), 57 deletions(-) diff --git a/snooze-pal.db b/snooze-pal.db index 174d33433194912a6ccaf2c4d467f1878062e38e..f101f503ae980fabed164df9dc60a4d3aabb4dcc 100644 GIT binary patch delta 635 zcmZozz}T>Wae_3X;6xc`M!}5lzp-7+P8x8(W!J>X{lC73b%smSkk+rK|Fy zD>E{%GB&a@wbU~(G)E}oL01Me&B)Bk#8}VB5Xm%dn6i2#Td}C)f~mu=jFUKJ9GJ@L zvAK>NQ=OHOsg@To&6VQEH%fP_E$p4jr X|LbN!gV+4roQ%xkjEOmkMY((c7&4V{ delta 45 scmZozz}T>Wae_1>^F$eEM&^wPOZ1r-1U3sgJmH@>L5z);0SMq+03> + scheduler: Arc> } async fn app_state() -> AppState { - let chip: Arc> = Arc::new(Mutex::new(Chip::new("/dev/gpiochip0").unwrap())); + // let chip: Arc> = Arc::new(Mutex::new(Chip::new("/dev/gpiochip0").unwrap())); let cron = Arc::new(Mutex::new(Cron::new(chrono::Local))); let db = Database::connect("sqlite://snooze-pal.db").await.unwrap(); + let silent = Arc::new(Mutex::new(SilentRinger::new())); AppState { scheduler: Arc::new(Scheduler::new( - Arc::new(Mutex::new(BeepRinger::new(chip.clone()))), + silent, cron.clone(), Arc::new(db) )) @@ -40,11 +41,9 @@ async fn app_state() -> AppState { #[tokio::main] async fn main() -> Result<(), Box> { - // let app_state = app_state().await; - - // app_state.scheduler.start(); - - start_axum_server().await; + let app_state = app_state().await; + app_state.scheduler.start(); + start_axum_server(app_state).await; Ok(()) } @@ -52,11 +51,12 @@ async fn main() -> Result<(), Box> { #[derive(OpenApi)] struct ApiDocs; -async fn start_axum_server() { +async fn start_axum_server(app_state: AppState) { let docs = ApiDocs::openapi(); - let (router, spec) = OpenApiRouter::with_openapi(docs) + let (router, spec) = OpenApiRouter::::with_openapi(docs) .nest("/v1", resources::router()) + .with_state(app_state) .split_for_parts(); let router = router.merge(SwaggerUi::new("/swagger-ui").url("/openapi.json", spec)); diff --git a/src/resources/alarm/mod.rs b/src/resources/alarm/mod.rs index baaecc7..1c2ae13 100644 --- a/src/resources/alarm/mod.rs +++ b/src/resources/alarm/mod.rs @@ -1,7 +1,8 @@ mod post; use utoipa_axum::{router::OpenApiRouter, routes}; -pub fn router() -> OpenApiRouter { - OpenApiRouter::new() - .routes(routes!(post::post_handler)) +use crate::AppState; + +pub fn router() -> OpenApiRouter { + OpenApiRouter::new().routes(routes!(post::post_handler)) } diff --git a/src/resources/alarm/post.rs b/src/resources/alarm/post.rs index 092eede..33f7e77 100644 --- a/src/resources/alarm/post.rs +++ b/src/resources/alarm/post.rs @@ -1,32 +1,51 @@ -use axum::Json; +use axum::extract::State; +use axum::{Json}; use axum::http::StatusCode; use axum::debug_handler; use axum::response::IntoResponse; use chrono::{DateTime, Local}; use schemars::JsonSchema; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use utoipa::{IntoResponses, ToSchema}; +use crate::AppState; +use crate::types::Alarm; + #[derive(Debug, Deserialize, JsonSchema, ToSchema)] pub struct RequestBody { time: DateTime, } +#[derive(ToSchema, Serialize)] +pub struct OkResponseBody { + time: DateTime, + enabled: bool, +} + #[derive(IntoResponses)] pub enum Responses { #[response(status = 200)] - Ok + Ok(#[to_schema] OkResponseBody), + #[response(status = 500)] + Error(String) } impl IntoResponse for Responses { fn into_response(self) -> axum::response::Response { match self { - Responses::Ok => (StatusCode::OK).into_response(), + Responses::Ok(body) => (StatusCode::OK, Json(body)).into_response(), + Responses::Error(message) => (StatusCode::INTERNAL_SERVER_ERROR, Json(message)).into_response(), } } } +impl From for OkResponseBody { + fn from(value: Alarm) -> Self { + OkResponseBody { time: value.time, enabled: value.enabled } + } +} + #[utoipa::path( post, path = "", @@ -35,6 +54,7 @@ impl IntoResponse for Responses { ) )] #[debug_handler] -pub async fn post_handler(Json(body): Json) -> Responses { - todo!() +pub async fn post_handler(State(AppState { scheduler, ..}): State, Json(body): Json) -> Responses { + let alarm = scheduler.add_alarm(body.time).await.unwrap(); + Responses::Ok(alarm.into()) } diff --git a/src/resources/mod.rs b/src/resources/mod.rs index 5730bd4..bb29ed3 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -1,8 +1,9 @@ use utoipa_axum::router::OpenApiRouter; +use crate::AppState; + mod alarm; -pub fn router() -> OpenApiRouter { - OpenApiRouter::new() - .nest("/alarm", alarm::router()) +pub fn router() -> OpenApiRouter { + OpenApiRouter::new().nest("/alarm", alarm::router()) } diff --git a/src/ringer.rs b/src/ringer.rs index 6add61c..34b128c 100644 --- a/src/ringer.rs +++ b/src/ringer.rs @@ -1,4 +1,7 @@ -use std::{sync::{Arc, Mutex}, thread}; +use std::{ + sync::{Arc, Mutex}, + thread, +}; use gpio_cdev::{Chip, LineRequestFlags}; @@ -12,43 +15,40 @@ pub struct BeepRinger { } impl BeepRinger { + fn beep(times: u32, chip: &mut Chip) -> Result<(), String> { + let beeper = chip.get_line(17); - fn beep(times: u32, chip: &mut Chip) -> Result<(), String> { - let beeper = chip.get_line(17); + let beeper = match beeper { + Ok(beeper) => beeper, + Err(e) => { + println!("Error opening line: {}", e); + return Err("Could not open Line to Beeper".to_string()); + } + }; - let beeper = match beeper { - Ok(beeper) => beeper, - Err(e) => { - println!("Error opening line: {}", e); - return Err("Could not open Line to Beeper".to_string()); - } - }; + let beeper = beeper.request(LineRequestFlags::OUTPUT, 0, "my-gpio"); + let beeper = match beeper { + Ok(beeper) => beeper, + Err(e) => { + println!("Error requesting line: {}", e); + return Err("Could not request Line to Beeper".to_string()); + } + }; - let beeper = beeper - .request(LineRequestFlags::OUTPUT, 0, "my-gpio"); - - let beeper = match beeper { - Ok(beeper) => beeper, - Err(e) => { - println!("Error requesting line: {}", e); - return Err("Could not request Line to Beeper".to_string()); - } - }; - - for _ in 0..times { - beeper.set_value(1).map_err(|e| e.to_string())?; - thread::sleep(std::time::Duration::from_secs(1)); - beeper.set_value(0).map_err(|e| e.to_string())?; - thread::sleep(std::time::Duration::from_secs(1)); - } + for _ in 0..times { + beeper.set_value(1).map_err(|e| e.to_string())?; + thread::sleep(std::time::Duration::from_secs(1)); + beeper.set_value(0).map_err(|e| e.to_string())?; + thread::sleep(std::time::Duration::from_secs(1)); + } return Ok(()); - } + } - pub fn new(chip: Arc>) -> Self { - Self { chip } - } + pub fn new(chip: Arc>) -> Self { + Self { chip } + } } impl Ringer for BeepRinger { @@ -63,8 +63,25 @@ impl Ringer for BeepRinger { } }; - BeepRinger::beep(5, &mut *chip)?; + BeepRinger::beep(5, &mut *chip)?; - Ok(()) + Ok(()) + } +} + +/// Used for local testing without an actual beeper or similar. The only thing it does is print +/// that it's ringing. +pub struct SilentRinger; + +impl SilentRinger { + pub fn new() -> Self { + Self {} + } +} + +impl Ringer for SilentRinger { + fn ring(&self) -> Result<(), String> { + println!("Ringing"); + Ok(()) } } diff --git a/src/scheduler.rs b/src/scheduler.rs index 9e88e30..ce809c8 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -45,7 +45,7 @@ impl Scheduler { }); job_result.expect("Faild to add job"); - todo!() + Ok(()) } pub async fn add_alarm(&self, time: DateTime) -> Result {