same functionality now works with axum the same way it did with actix

This commit is contained in:
2026-03-02 20:39:08 +01:00
parent 05ba925d54
commit a86a28fd85
7 changed files with 96 additions and 57 deletions

Binary file not shown.

View File

@@ -10,7 +10,7 @@ use utoipa::OpenApi;
use utoipa_axum::router::OpenApiRouter;
use utoipa_swagger_ui::SwaggerUi;
use crate::{ringer::BeepRinger, scheduler::Scheduler};
use crate::{ringer::{BeepRinger, SilentRinger}, scheduler::Scheduler};
mod scheduler;
mod ringer;
@@ -22,16 +22,17 @@ mod model;
#[derive(Clone)]
struct AppState {
scheduler: Arc<Scheduler<BeepRinger>>
scheduler: Arc<Scheduler<SilentRinger>>
}
async fn app_state() -> AppState {
let chip: Arc<Mutex<Chip>> = Arc::new(Mutex::new(Chip::new("/dev/gpiochip0").unwrap()));
// let chip: Arc<Mutex<Chip>> = 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<dyn std::error::Error>> {
// 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<dyn std::error::Error>> {
#[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::<AppState>::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));

View File

@@ -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<AppState> {
OpenApiRouter::new().routes(routes!(post::post_handler))
}

View File

@@ -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<Local>,
}
#[derive(ToSchema, Serialize)]
pub struct OkResponseBody {
time: DateTime<Local>,
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<Alarm> 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<RequestBody>) -> Responses {
todo!()
pub async fn post_handler(State(AppState { scheduler, ..}): State<AppState>, Json(body): Json<RequestBody>) -> Responses {
let alarm = scheduler.add_alarm(body.time).await.unwrap();
Responses::Ok(alarm.into())
}

View File

@@ -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<AppState> {
OpenApiRouter::new().nest("/alarm", alarm::router())
}

View File

@@ -1,4 +1,7 @@
use std::{sync::{Arc, Mutex}, thread};
use std::{
sync::{Arc, Mutex},
thread,
};
use gpio_cdev::{Chip, LineRequestFlags};
@@ -12,7 +15,6 @@ pub struct BeepRinger {
}
impl BeepRinger {
fn beep(times: u32, chip: &mut Chip) -> Result<(), String> {
let beeper = chip.get_line(17);
@@ -24,9 +26,7 @@ impl BeepRinger {
}
};
let beeper = beeper
.request(LineRequestFlags::OUTPUT, 0, "my-gpio");
let beeper = beeper.request(LineRequestFlags::OUTPUT, 0, "my-gpio");
let beeper = match beeper {
Ok(beeper) => beeper,
@@ -68,3 +68,20 @@ impl Ringer for BeepRinger {
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(())
}
}

View File

@@ -45,7 +45,7 @@ impl<T: Ringer> Scheduler<T> {
});
job_result.expect("Faild to add job");
todo!()
Ok(())
}
pub async fn add_alarm(&self, time: DateTime<Local>) -> Result<Alarm, String> {