added routes for listing days & getting days

/api/days?from=...&to=...
/api/day?day=...
This commit is contained in:
Djeeberjr 2025-10-13 16:32:28 +02:00
parent a34dc18381
commit 6421074931
2 changed files with 54 additions and 18 deletions

View File

@ -1,11 +1,12 @@
use esp_println::dbg;
use picoserve::{ use picoserve::{
extract::{Json, State}, extract::{Json, Query, State},
response::{self, IntoResponse}, response::{self, IntoResponse},
}; };
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
store::{Name, tally_id::TallyID}, store::{self, Name, day::Day, tally_id::TallyID},
webserver::{app::AppState, sse::IDEvents}, webserver::{app::AppState, sse::IDEvents},
}; };
@ -15,27 +16,25 @@ pub struct NewMapping {
name: Name, name: Name,
} }
// struct MappingWrapper(IDMapping); #[derive(Deserialize)]
// pub struct QueryTimespan {
// impl Serialize for MappingWrapper { from: u64,
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> to: u64,
// where }
// S: serde::Serializer,
// {
// use serde::ser::SerializeMap;
// let mut map = serializer.serialize_map(Some(self.0.id_map.len()))?;
// for (k, v) in &self.0.id_map {
// map.serialize_entry(tally_id_to_hex_string(*k).unwrap().as_str(), &v)?;
// }
// map.end()
// }
// }
#[derive(Deserialize)]
pub struct QueryDay {
timestamp: Option<u64>,
day: Option<u32>,
}
// GET /api/mapping
pub async fn get_mapping(State(state): State<AppState>) -> impl IntoResponse { pub async fn get_mapping(State(state): State<AppState>) -> impl IntoResponse {
let store = state.store.lock().await; let store = state.store.lock().await;
response::Json(store.mapping.clone()) response::Json(store.mapping.clone())
} }
// POST /api/mapping
pub async fn add_mapping( pub async fn add_mapping(
State(state): State<AppState>, State(state): State<AppState>,
Json(data): Json<NewMapping>, Json(data): Json<NewMapping>,
@ -44,6 +43,41 @@ pub async fn add_mapping(
store.mapping.add_mapping(data.id, data.name); store.mapping.add_mapping(data.id, data.name);
} }
// SSE /api/idevent
pub async fn get_idevent(State(state): State<AppState>) -> impl IntoResponse { pub async fn get_idevent(State(state): State<AppState>) -> impl IntoResponse {
response::EventStream(IDEvents(state.chan.subscriber().unwrap())) response::EventStream(IDEvents(state.chan.subscriber().unwrap()))
} }
// GET /api/days
pub async fn get_days(
State(state): State<AppState>,
Query(QueryTimespan { from, to }): Query<QueryTimespan>,
) -> impl IntoResponse {
let from_day = Day::new_from_timestamp(from);
let to_day = Day::new_from_timestamp(to);
let mut store = state.store.lock().await;
let days = store.list_days_in_timespan(from_day, to_day).await;
response::Json(days)
}
// GET /api/day
pub async fn get_day(
State(state): State<AppState>,
Query(QueryDay { timestamp, day }): Query<QueryDay>,
) -> Result<impl IntoResponse, impl IntoResponse> {
let parsed_day = timestamp
.map(Day::new_from_timestamp)
.or_else(|| day.map(Day::new))
.ok_or((response::StatusCode::NOT_FOUND, "Not found"))?;
let mut store = state.store.lock().await;
match store.load_day(parsed_day).await {
Some(att_day) => Ok(response::Json(att_day)),
None => Err((response::StatusCode::NOT_FOUND, "Not found")),
}
}

View File

@ -5,7 +5,7 @@ use picoserve::{AppWithStateBuilder, routing::get};
use crate::{ use crate::{
TallyChannel, UsedStore, TallyChannel, UsedStore,
webserver::{ webserver::{
api::{add_mapping, get_idevent, get_mapping}, api::{add_mapping, get_day, get_days, get_idevent, get_mapping},
assets::Assets, assets::Assets,
}, },
}; };
@ -26,5 +26,7 @@ impl AppWithStateBuilder for AppProps {
picoserve::Router::from_service(Assets) picoserve::Router::from_service(Assets)
.route("/api/mapping", get(get_mapping).post(add_mapping)) .route("/api/mapping", get(get_mapping).post(add_mapping))
.route("/api/idevent", get(get_idevent)) .route("/api/idevent", get(get_idevent))
.route("/api/days", get(get_days))
.route("/api/day", get(get_day))
} }
} }