diff --git a/src/errors.rs b/src/errors.rs index f2eb99a..c650f9b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,6 @@ +use std::sync::PoisonError; + +use rocket::response::Responder; use thiserror::Error; pub trait PrintErrors { @@ -22,6 +25,34 @@ where } } +#[derive(Error, Debug)] +pub enum ServerError { + #[error("rwlock error")] + // 500 + Lock, + #[error("no data")] + // 503 + NoData, + #[error("prometheus")] + Prometheus(#[from] prometheus::Error), +} + +impl From> for ServerError { + fn from(_: PoisonError) -> Self { + Self::Lock + } +} + +impl<'a> Responder<'a, 'a> for ServerError { + fn respond_to(self, _: &'a rocket::Request<'_>) -> rocket::response::Result<'a> { + Err(match self { + ServerError::Lock => rocket::http::Status::InternalServerError, + ServerError::NoData => rocket::http::Status::ServiceUnavailable, + ServerError::Prometheus(_) => rocket::http::Status::InternalServerError, + }) + } +} + #[derive(Error, Debug)] pub enum SaveError { #[error("stdio error")] diff --git a/src/server/mod.rs b/src/server/mod.rs index 935a098..839747a 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -11,6 +11,7 @@ use rocket::{ use crate::{ api_interface::InterfaceRequest, config::Config, + errors::ServerError, pl_interface::{PlState, PliRequest}, types::{CarState, ChargeState, ClimateState}, }; @@ -63,19 +64,35 @@ fn rocket(state: ServerState) -> rocket::Rocket { } #[get("/home")] -async fn home(state: &State) -> Option> { - let location_data = &state.car_state.read().ok()?.location_data?; - Some(Json(location_data.coords.overlaps(&state.config.coords))) +async fn home(state: &State) -> Result, ServerError> { + let location_data = &state + .car_state + .read()? + .location_data + .ok_or(ServerError::NoData)?; + Ok(Json(location_data.coords.overlaps(&state.config.coords))) } #[get("/charge-state")] -async fn charge_state(state: &State) -> Option> { - Some(Json(state.car_state.read().ok()?.charge_state?)) +async fn charge_state(state: &State) -> Result, ServerError> { + Ok(Json( + state + .car_state + .read()? + .charge_state + .ok_or(ServerError::NoData)?, + )) } #[get("/climate-state")] -async fn climate_state(state: &State) -> Option> { - Some(Json(state.car_state.read().ok()?.climate_state?)) +async fn climate_state(state: &State) -> Result, ServerError> { + Ok(Json( + state + .car_state + .read()? + .climate_state + .ok_or(ServerError::NoData)?, + )) } #[post("/flash")] @@ -84,10 +101,11 @@ async fn flash(state: &State) { } #[get("/metrics")] -fn metrics() -> Option { - prometheus::TextEncoder::new() - .encode_to_string(&prometheus::default_registry().gather()) - .ok() +fn metrics() -> Result { + Ok( + prometheus::TextEncoder::new() + .encode_to_string(&prometheus::default_registry().gather())?, + ) } #[get("/read-ram/
")] @@ -97,11 +115,12 @@ async fn read_ram(address: u8, state: &State) -> String { } #[get("/regulator-state")] -async fn regulator_state(state: &State) -> Option> { +async fn regulator_state(state: &State) -> Result, ServerError> { state .pl_state .as_ref() - .and_then(|v| Some(Json(*(v.read().ok()?)))) + .ok_or(ServerError::NoData) + .and_then(|v| Ok(Json(*(v.read()?)))) } pub struct Cors;