mirror of
https://github.com/Djeeberjr/fw-anwesenheit.git
synced 2025-11-04 23:54:11 +00:00
improved error handeling for sdcard functions
This commit is contained in:
parent
07d51264f9
commit
02798d90c4
@ -1,10 +1,12 @@
|
|||||||
use core::str::from_utf8;
|
|
||||||
|
|
||||||
use alloc::{string::ToString, vec::Vec};
|
use alloc::{string::ToString, vec::Vec};
|
||||||
|
use core::str::from_utf8;
|
||||||
use embassy_time::Delay;
|
use embassy_time::Delay;
|
||||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||||
use embedded_sdmmc::{SdCard, ShortFileName, TimeSource, Timestamp, VolumeIdx, VolumeManager};
|
use embedded_sdmmc::{
|
||||||
|
SdCard, SdCardError, ShortFileName, TimeSource, Timestamp, VolumeIdx, VolumeManager,
|
||||||
|
};
|
||||||
use esp_hal::{Blocking, gpio::Output, spi::master::Spi};
|
use esp_hal::{Blocking, gpio::Output, spi::master::Spi};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::store::{
|
use crate::store::{
|
||||||
AttendanceDay, day::Day, mapping_loader::Name, persistence::Persistence, tally_id::TallyID,
|
AttendanceDay, day::Day, mapping_loader::Name, persistence::Persistence, tally_id::TallyID,
|
||||||
@ -45,190 +47,229 @@ pub struct SDCardPersistence {
|
|||||||
impl SDCardPersistence {
|
impl SDCardPersistence {
|
||||||
const MAPPING_DIRNAME: &'static str = "MAPPINGS";
|
const MAPPING_DIRNAME: &'static str = "MAPPINGS";
|
||||||
|
|
||||||
fn generate_filename_for_day(day: Day) -> ShortFileName {
|
fn generate_filename_for_day(day: Day) -> Result<ShortFileName, PersistenceError> {
|
||||||
let basename = day.to_string();
|
let basename = day.to_string();
|
||||||
let mut filename: heapless::String<11> = heapless::String::new();
|
let mut filename: heapless::String<11> = heapless::String::new();
|
||||||
filename.push_str(&basename).unwrap();
|
filename
|
||||||
filename.push_str(".JS").unwrap();
|
.push_str(&basename)
|
||||||
|
.map_err(|_| PersistenceError::DayFilename)?;
|
||||||
|
filename
|
||||||
|
.push_str(".JS")
|
||||||
|
.map_err(|_| PersistenceError::DayFilename)?;
|
||||||
|
|
||||||
ShortFileName::create_from_str(&filename).unwrap()
|
ShortFileName::create_from_str(&filename).map_err(|_| PersistenceError::DayFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_path_for_id(id: TallyID) -> (ShortFileName, ShortFileName) {
|
fn generate_path_for_id(
|
||||||
|
id: TallyID,
|
||||||
|
) -> Result<(ShortFileName, ShortFileName), PersistenceError> {
|
||||||
let basename: heapless::String<12> = id.into();
|
let basename: heapless::String<12> = id.into();
|
||||||
let (dir, file) = basename.split_at(6);
|
let (dir, file) = basename.split_at(6);
|
||||||
|
|
||||||
let mut filename: heapless::String<11> = heapless::String::new();
|
let mut filename: heapless::String<11> = heapless::String::new();
|
||||||
filename.push_str(file).unwrap();
|
filename
|
||||||
filename.push_str(".JS").unwrap();
|
.push_str(file)
|
||||||
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
filename
|
||||||
|
.push_str(".JS")
|
||||||
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
|
||||||
let mut dirname: heapless::String<11> = heapless::String::new();
|
let mut dirname: heapless::String<11> = heapless::String::new();
|
||||||
dirname.push_str(dir).unwrap();
|
dirname
|
||||||
|
.push_str(dir)
|
||||||
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
|
||||||
(
|
Ok((
|
||||||
ShortFileName::create_from_str(&dirname).unwrap(),
|
ShortFileName::create_from_str(&dirname).map_err(|_| PersistenceError::IDFilename)?,
|
||||||
ShortFileName::create_from_str(&filename).unwrap(),
|
ShortFileName::create_from_str(&filename).map_err(|_| PersistenceError::IDFilename)?,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tallyid_from_path(dirname: &ShortFileName, filename: &ShortFileName) -> Option<TallyID> {
|
fn get_tallyid_from_path(
|
||||||
|
dirname: &ShortFileName,
|
||||||
|
filename: &ShortFileName,
|
||||||
|
) -> Result<TallyID, PersistenceError> {
|
||||||
let mut id_str: heapless::String<12> = heapless::String::new();
|
let mut id_str: heapless::String<12> = heapless::String::new();
|
||||||
|
|
||||||
id_str.push_str(&dirname.to_string()).unwrap();
|
|
||||||
id_str
|
id_str
|
||||||
.push_str(from_utf8(filename.base_name()).unwrap())
|
.push_str(&dirname.to_string())
|
||||||
.unwrap();
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
id_str
|
||||||
|
.push_str(from_utf8(filename.base_name()).map_err(|_| PersistenceError::IDFilename)?)
|
||||||
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
|
||||||
let id: TallyID = id_str.try_into().unwrap();
|
let id: TallyID = id_str
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| PersistenceError::IDFilename)?;
|
||||||
|
|
||||||
Some(id)
|
Ok(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum PersistenceError {
|
||||||
|
#[error("Failed to interact with SD card")]
|
||||||
|
SdCard(embedded_sdmmc::Error<SdCardError>),
|
||||||
|
|
||||||
|
#[error("Failed to parse data")]
|
||||||
|
Parseing(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error("Failed to parse Day and Filename")]
|
||||||
|
DayFilename,
|
||||||
|
|
||||||
|
#[error("Failed to parse TallyID for file path")]
|
||||||
|
IDFilename,
|
||||||
|
|
||||||
|
#[error("Item not found")]
|
||||||
|
NotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<embedded_sdmmc::Error<SdCardError>> for PersistenceError {
|
||||||
|
fn from(err: embedded_sdmmc::Error<SdCardError>) -> Self {
|
||||||
|
PersistenceError::SdCard(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Persistence for SDCardPersistence {
|
impl Persistence for SDCardPersistence {
|
||||||
async fn load_day(&mut self, day: Day) -> Option<AttendanceDay> {
|
type Error = PersistenceError;
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
|
||||||
|
|
||||||
let filename = Self::generate_filename_for_day(day);
|
async fn load_day(&mut self, day: Day) -> Result<AttendanceDay, Self::Error> {
|
||||||
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
|
|
||||||
|
let filename = Self::generate_filename_for_day(day)?;
|
||||||
let file = root_dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly);
|
let file = root_dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly);
|
||||||
|
|
||||||
if file.is_err() {
|
if file.is_err() {
|
||||||
return None;
|
return Err(PersistenceError::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut open_file = file.unwrap();
|
let mut open_file = file?;
|
||||||
|
|
||||||
let mut read_buffer: [u8; 1024] = [0; 1024];
|
let mut read_buffer: [u8; 1024] = [0; 1024];
|
||||||
let read = open_file.read(&mut read_buffer).unwrap();
|
let read = open_file.read(&mut read_buffer)?;
|
||||||
open_file.close().unwrap();
|
open_file.close()?;
|
||||||
|
|
||||||
let day: AttendanceDay = serde_json::from_slice(&read_buffer[..read]).unwrap();
|
let day: AttendanceDay = serde_json::from_slice(&read_buffer[..read])?;
|
||||||
|
|
||||||
Some(day)
|
Ok(day)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_day(&mut self, day: Day, data: &AttendanceDay) {
|
async fn save_day(&mut self, day: Day, data: &AttendanceDay) -> Result<(), Self::Error> {
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
|
|
||||||
let filename = Self::generate_filename_for_day(day);
|
let filename = Self::generate_filename_for_day(day)?;
|
||||||
|
|
||||||
let mut file = root_dir
|
let mut file =
|
||||||
.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadWriteCreateOrTruncate)
|
root_dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadWriteCreateOrTruncate)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
file.write(&serde_json::to_vec(data).unwrap()).unwrap();
|
file.write(&serde_json::to_vec(data)?)?;
|
||||||
|
|
||||||
file.flush().unwrap();
|
file.flush()?;
|
||||||
file.close().unwrap();
|
file.close()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_days(&mut self) -> Vec<Day> {
|
async fn list_days(&mut self) -> Result<Vec<Day>, Self::Error> {
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
|
|
||||||
let mut days_dir = root_dir.open_dir(".").unwrap();
|
let mut days_dir = root_dir.open_dir(".")?;
|
||||||
|
|
||||||
let mut days: Vec<Day> = Vec::new();
|
let mut days: Vec<Day> = Vec::new();
|
||||||
days_dir
|
days_dir.iterate_dir(|e| {
|
||||||
.iterate_dir(|e| {
|
|
||||||
let filename = e.name.clone();
|
let filename = e.name.clone();
|
||||||
|
|
||||||
if let Ok(day) = filename.try_into() {
|
if let Ok(day) = filename.try_into() {
|
||||||
days.push(day);
|
days.push(day);
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
days
|
Ok(days)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_mapping_for_id(
|
async fn load_mapping_for_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: crate::store::tally_id::TallyID,
|
id: crate::store::tally_id::TallyID,
|
||||||
) -> Option<crate::store::mapping_loader::Name> {
|
) -> Result<crate::store::mapping_loader::Name, Self::Error> {
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME).unwrap();
|
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME)?;
|
||||||
|
|
||||||
let (dirname, filename) = Self::generate_path_for_id(id);
|
let (dirname, filename) = Self::generate_path_for_id(id)?;
|
||||||
|
|
||||||
let mut dir = mapping_dir.open_dir(dirname).unwrap();
|
let mut dir = mapping_dir.open_dir(dirname)?;
|
||||||
let mut file = dir
|
let mut file = dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly)?;
|
||||||
.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadOnly)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut read_buffer: [u8; 1024] = [0; 1024];
|
let mut read_buffer: [u8; 1024] = [0; 1024];
|
||||||
let read_bytes = file.read(&mut read_buffer).unwrap();
|
let read_bytes = file.read(&mut read_buffer)?;
|
||||||
file.close().unwrap();
|
file.close()?;
|
||||||
|
|
||||||
let mapping: Name = serde_json::from_slice(&read_buffer[..read_bytes]).unwrap();
|
let mapping: Name = serde_json::from_slice(&read_buffer[..read_bytes])?;
|
||||||
|
|
||||||
Some(mapping)
|
Ok(mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_mapping_for_id(
|
async fn save_mapping_for_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: crate::store::tally_id::TallyID,
|
id: crate::store::tally_id::TallyID,
|
||||||
name: crate::store::mapping_loader::Name,
|
name: crate::store::mapping_loader::Name,
|
||||||
) {
|
) -> Result<(), Self::Error> {
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME).unwrap();
|
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME)?;
|
||||||
|
|
||||||
let (dirname, filename) = Self::generate_path_for_id(id);
|
let (dirname, filename) = Self::generate_path_for_id(id)?;
|
||||||
|
|
||||||
let mut dir = if let Ok(dir) = mapping_dir.open_dir(&dirname) {
|
let mut dir = if let Ok(dir) = mapping_dir.open_dir(&dirname) {
|
||||||
dir
|
dir
|
||||||
} else {
|
} else {
|
||||||
mapping_dir.make_dir_in_dir(&dirname).unwrap();
|
mapping_dir.make_dir_in_dir(&dirname)?;
|
||||||
mapping_dir.open_dir(&dirname).unwrap()
|
mapping_dir.open_dir(&dirname)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file = dir
|
let mut file =
|
||||||
.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadWriteCreateOrTruncate)
|
dir.open_file_in_dir(filename, embedded_sdmmc::Mode::ReadWriteCreateOrTruncate)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
file.write(&serde_json::to_vec(&name).unwrap()).unwrap();
|
file.write(&serde_json::to_vec(&name)?)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_mappings(&mut self) -> Vec<TallyID> {
|
async fn list_mappings(&mut self) -> Result<Vec<TallyID>, Self::Error> {
|
||||||
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0)).unwrap();
|
let mut vol_0 = self.vol_mgr.open_volume(VolumeIdx(0))?;
|
||||||
let mut root_dir = vol_0.open_root_dir().unwrap();
|
let mut root_dir = vol_0.open_root_dir()?;
|
||||||
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME).unwrap();
|
let mut mapping_dir = root_dir.open_dir(Self::MAPPING_DIRNAME)?;
|
||||||
let mut ids: Vec<TallyID> = Vec::new();
|
let mut ids: Vec<TallyID> = Vec::new();
|
||||||
|
|
||||||
let mut dir_names = Vec::new();
|
let mut dir_names = Vec::new();
|
||||||
mapping_dir
|
mapping_dir.iterate_dir(|entry| {
|
||||||
.iterate_dir(|entry| {
|
|
||||||
if entry.attributes.is_directory()
|
if entry.attributes.is_directory()
|
||||||
&& entry.name.to_string() != "."
|
&& entry.name.to_string() != "."
|
||||||
&& entry.name.to_string() != ".."
|
&& entry.name.to_string() != ".."
|
||||||
{
|
{
|
||||||
dir_names.push(entry.name.clone());
|
dir_names.push(entry.name.clone());
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for dirname in dir_names {
|
for dirname in dir_names {
|
||||||
if let Ok(mut subdir) = mapping_dir.open_dir(&dirname) {
|
if let Ok(mut subdir) = mapping_dir.open_dir(&dirname) {
|
||||||
let mut file_names = Vec::new();
|
let mut file_names = Vec::new();
|
||||||
subdir
|
subdir.iterate_dir(|file_entry| {
|
||||||
.iterate_dir(|file_entry| {
|
|
||||||
if !file_entry.attributes.is_directory() {
|
if !file_entry.attributes.is_directory() {
|
||||||
file_names.push(file_entry.name.clone());
|
file_names.push(file_entry.name.clone());
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for filename in file_names {
|
for filename in file_names {
|
||||||
let id = Self::get_tallyid_from_path(&dirname, &filename);
|
let id = Self::get_tallyid_from_path(&dirname, &filename)?;
|
||||||
ids.push(id.unwrap());
|
ids.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ids
|
Ok(ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
#![warn(clippy::unwrap_used)]
|
||||||
|
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
|||||||
@ -58,7 +58,7 @@ impl<T: Persistence> IDStore<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn persist_day(&mut self) {
|
async fn persist_day(&mut self) -> Result<(), T::Error> {
|
||||||
self.persistence_layer
|
self.persistence_layer
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
@ -88,21 +88,25 @@ impl<T: Persistence> IDStore<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Load and return a AttendanceDay. Nothing more. Nothing less.
|
/// Load and return a AttendanceDay. Nothing more. Nothing less.
|
||||||
pub async fn load_day(&mut self, day: Day) -> Option<AttendanceDay> {
|
pub async fn load_day(&mut self, day: Day) -> Result<AttendanceDay, T::Error> {
|
||||||
if day == self.current_day.date {
|
if day == self.current_day.date {
|
||||||
return Some(self.current_day.clone());
|
return Ok(self.current_day.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.persistence_layer.lock().await.load_day(day).await
|
self.persistence_layer.lock().await.load_day(day).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_days_in_timespan(&mut self, from: Day, to: Day) -> Vec<Day> {
|
pub async fn list_days_in_timespan(
|
||||||
let all_days = self.persistence_layer.lock().await.list_days().await;
|
&mut self,
|
||||||
|
from: Day,
|
||||||
|
to: Day,
|
||||||
|
) -> Result<Vec<Day>, T::Error> {
|
||||||
|
let all_days = self.persistence_layer.lock().await.list_days().await?;
|
||||||
|
|
||||||
all_days
|
Ok(all_days
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|e| *e >= from)
|
.filter(|e| *e >= from)
|
||||||
.filter(|e| *e <= to)
|
.filter(|e| *e <= to)
|
||||||
.collect()
|
.collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,15 +17,15 @@ impl<T: Persistence> MappingLoader<T> {
|
|||||||
Self(persistence_layer)
|
Self(persistence_layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_mapping(&self, id: TallyID) -> Option<Name> {
|
pub async fn get_mapping(&self, id: TallyID) -> Result<Name, T::Error> {
|
||||||
self.0.lock().await.load_mapping_for_id(id).await
|
self.0.lock().await.load_mapping_for_id(id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_mapping(&self, id: TallyID, name: Name) {
|
pub async fn set_mapping(&self, id: TallyID, name: Name) -> Result<(), T::Error> {
|
||||||
self.0.lock().await.save_mapping_for_id(id, name).await;
|
self.0.lock().await.save_mapping_for_id(id, name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_mappings(&self) -> Vec<TallyID> {
|
pub async fn list_mappings(&self) -> Result<Vec<TallyID>,T::Error> {
|
||||||
self.0.lock().await.list_mappings().await
|
self.0.lock().await.list_mappings().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,11 +3,13 @@ use alloc::vec::Vec;
|
|||||||
use crate::store::{day::Day, id_store::AttendanceDay, mapping_loader::Name, tally_id::TallyID};
|
use crate::store::{day::Day, id_store::AttendanceDay, mapping_loader::Name, tally_id::TallyID};
|
||||||
|
|
||||||
pub trait Persistence {
|
pub trait Persistence {
|
||||||
async fn load_day(&mut self, day: Day) -> Option<AttendanceDay>;
|
type Error: core::error::Error;
|
||||||
async fn save_day(&mut self, day: Day, data: &AttendanceDay);
|
|
||||||
async fn list_days(&mut self) -> Vec<Day>;
|
|
||||||
|
|
||||||
async fn load_mapping_for_id(&mut self, id:TallyID ) -> Option<Name>;
|
async fn load_day(&mut self, day: Day) -> Result<AttendanceDay, Self::Error>;
|
||||||
async fn save_mapping_for_id(&mut self, id:TallyID, name: Name);
|
async fn save_day(&mut self, day: Day, data: &AttendanceDay) -> Result<(), Self::Error>;
|
||||||
async fn list_mappings(&mut self) -> Vec<TallyID>;
|
async fn list_days(&mut self) -> Result<Vec<Day>, Self::Error>;
|
||||||
|
|
||||||
|
async fn load_mapping_for_id(&mut self, id: TallyID) -> Result<Name, Self::Error>;
|
||||||
|
async fn save_mapping_for_id(&mut self, id: TallyID, name: Name) -> Result<(), Self::Error>;
|
||||||
|
async fn list_mappings(&mut self) -> Result<Vec<TallyID>, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,19 +34,34 @@ pub struct QueryMapping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/mappings
|
// GET /api/mappings
|
||||||
pub async fn get_mappings(State(state): State<AppState>) -> impl IntoResponse {
|
pub async fn get_mappings(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
let loader = state.mapping_loader.lock().await;
|
let loader = state.mapping_loader.lock().await;
|
||||||
response::Json(loader.list_mappings().await)
|
|
||||||
|
match loader.list_mappings().await {
|
||||||
|
Ok(ids) => Ok(response::Json(ids)),
|
||||||
|
Err(_) => Err((
|
||||||
|
response::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"INTERNAL_SERVER_ERROR",
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/mapping
|
// GET /api/mapping
|
||||||
pub async fn get_mapping(
|
pub async fn get_mapping(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(QueryMapping { id }): Query<QueryMapping>,
|
Query(QueryMapping { id }): Query<QueryMapping>,
|
||||||
) -> impl IntoResponse {
|
) -> Result<impl IntoResponse, impl IntoResponse> {
|
||||||
let loader = state.mapping_loader.lock().await;
|
let loader = state.mapping_loader.lock().await;
|
||||||
let mapping = loader.get_mapping(id).await;
|
|
||||||
response::Json(mapping)
|
match loader.get_mapping(id).await {
|
||||||
|
Ok(name) => Ok(response::Json(name)),
|
||||||
|
Err(_) => Err((
|
||||||
|
response::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"INTERNAL_SERVER_ERROR",
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/mapping
|
// POST /api/mapping
|
||||||
@ -55,7 +70,13 @@ pub async fn add_mapping(
|
|||||||
Json(data): Json<NewMapping>,
|
Json(data): Json<NewMapping>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let loader = state.mapping_loader.lock().await;
|
let loader = state.mapping_loader.lock().await;
|
||||||
loader.set_mapping(data.id, data.name).await;
|
match loader.set_mapping(data.id, data.name).await {
|
||||||
|
Ok(_) => (response::StatusCode::CREATED, ""),
|
||||||
|
Err(_) => (
|
||||||
|
response::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"INTERNAL_SERVER_ERROR",
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSE /api/idevent
|
// SSE /api/idevent
|
||||||
@ -84,9 +105,13 @@ pub async fn get_days(
|
|||||||
|
|
||||||
let mut store = state.store.lock().await;
|
let mut store = state.store.lock().await;
|
||||||
|
|
||||||
let days = store.list_days_in_timespan(from_day, to_day).await;
|
match store.list_days_in_timespan(from_day, to_day).await {
|
||||||
|
Ok(days) => Ok(response::Json(days)),
|
||||||
response::Json(days)
|
Err(_) => Err((
|
||||||
|
response::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Internal server error",
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /api/day
|
// GET /api/day
|
||||||
@ -102,7 +127,10 @@ pub async fn get_day(
|
|||||||
let mut store = state.store.lock().await;
|
let mut store = state.store.lock().await;
|
||||||
|
|
||||||
match store.load_day(parsed_day).await {
|
match store.load_day(parsed_day).await {
|
||||||
Some(att_day) => Ok(response::Json(att_day)),
|
Ok(att_day) => Ok(response::Json(att_day)),
|
||||||
None => Err((response::StatusCode::NOT_FOUND, "Not found")),
|
Err(_) => Err((
|
||||||
|
response::StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
"Internal server error",
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user