mirror of
				https://github.com/Djeeberjr/fw-anwesenheit.git
				synced 2025-11-03 23:24:10 +00:00 
			
		
		
		
	changed TallyID to a struct instead of a type alias
This commit is contained in:
		
							parent
							
								
									0f5ca88ae4
								
							
						
					
					
						commit
						dfe5197ab8
					
				@ -25,7 +25,7 @@ extern crate alloc;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    init::sd_card::SDCardPersistence,
 | 
			
		||||
    store::{Date, IDStore, TallyID},
 | 
			
		||||
    store::{Date, IDStore, tally_id::TallyID},
 | 
			
		||||
    webserver::start_webserver,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ use alloc::collections::BTreeMap;
 | 
			
		||||
use alloc::string::String;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use super::TallyID;
 | 
			
		||||
use crate::store::tally_id::TallyID;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct Name {
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,8 @@ use serde::Serialize;
 | 
			
		||||
 | 
			
		||||
use super::Date;
 | 
			
		||||
use super::IDMapping;
 | 
			
		||||
use super::TallyID;
 | 
			
		||||
use crate::store::persistence::Persistence;
 | 
			
		||||
use crate::store::tally_id::TallyID;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize, Debug)]
 | 
			
		||||
pub struct AttendanceDay {
 | 
			
		||||
 | 
			
		||||
@ -1,48 +1,10 @@
 | 
			
		||||
use heapless::String;
 | 
			
		||||
 | 
			
		||||
pub use id_mapping::{IDMapping, Name};
 | 
			
		||||
pub use id_store::{IDStore,AttendanceDay};
 | 
			
		||||
 | 
			
		||||
mod id_mapping;
 | 
			
		||||
pub mod persistence;
 | 
			
		||||
mod id_store;
 | 
			
		||||
pub mod tally_id;
 | 
			
		||||
 | 
			
		||||
pub type TallyID = [u8; 6];
 | 
			
		||||
pub type Date = [u8; 10];
 | 
			
		||||
 | 
			
		||||
pub fn hex_string_to_tally_id(s: &str) -> Option<TallyID> {
 | 
			
		||||
    let bytes = s.as_bytes();
 | 
			
		||||
    if bytes.len() != 12 {
 | 
			
		||||
        return None;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mut out: TallyID = [0;6];
 | 
			
		||||
    for i in 0..6 {
 | 
			
		||||
        let hi = hex_val(bytes[2 * i])?;
 | 
			
		||||
        let lo = hex_val(bytes[2 * i + 1])?;
 | 
			
		||||
        out[i] = (hi << 4) | lo;
 | 
			
		||||
    }
 | 
			
		||||
    Some(out)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn tally_id_to_hex_string(bytes: TallyID) -> Option<String<12>> {
 | 
			
		||||
    const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
 | 
			
		||||
    let mut s: String<12> = String::new();
 | 
			
		||||
 | 
			
		||||
    for &b in &bytes {
 | 
			
		||||
        s.push(HEX_CHARS[(b >> 4) as usize] as char).ok()?;
 | 
			
		||||
        s.push(HEX_CHARS[(b & 0x0F) as usize] as char).ok()?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Some(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn hex_val(b: u8) -> Option<u8> {
 | 
			
		||||
    match b {
 | 
			
		||||
        b'0'..=b'9' => Some(b - b'0'),
 | 
			
		||||
        b'a'..=b'f' => Some(b - b'a' + 10),
 | 
			
		||||
        b'A'..=b'F' => Some(b - b'A' + 10),
 | 
			
		||||
        _ => None,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								src/store/tally_id.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/store/tally_id.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
use core::str::FromStr;
 | 
			
		||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 | 
			
		||||
pub struct TallyID([u8; 6]);
 | 
			
		||||
 | 
			
		||||
impl FromStr for TallyID {
 | 
			
		||||
    type Err = ();
 | 
			
		||||
 | 
			
		||||
    fn from_str(s: &str) -> Result<Self, Self::Err> {
 | 
			
		||||
        s.as_bytes().try_into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TryFrom<heapless::String<12>> for TallyID {
 | 
			
		||||
    type Error = ();
 | 
			
		||||
 | 
			
		||||
    fn try_from(value: heapless::String<12>) -> Result<Self, Self::Error> {
 | 
			
		||||
        let bytes = value.as_bytes();
 | 
			
		||||
 | 
			
		||||
        let mut out: [u8; 6] = [0; 6];
 | 
			
		||||
        for i in 0..6 {
 | 
			
		||||
            let hi = hex_val(bytes[2 * i])?;
 | 
			
		||||
            let lo = hex_val(bytes[2 * i + 1])?;
 | 
			
		||||
            out[i] = (hi << 4) | lo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(TallyID(out))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn hex_val(b: u8) -> Result<u8, ()> {
 | 
			
		||||
    match b {
 | 
			
		||||
        b'0'..=b'9' => Ok(b - b'0'),
 | 
			
		||||
        b'a'..=b'f' => Ok(b - b'a' + 10),
 | 
			
		||||
        b'A'..=b'F' => Ok(b - b'A' + 10),
 | 
			
		||||
        _ => Err(()),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<TallyID> for heapless::String<12> {
 | 
			
		||||
    fn from(value: TallyID) -> Self {
 | 
			
		||||
        const HEX_CHARS: &[u8; 16] = b"0123456789ABCDEF";
 | 
			
		||||
        let mut s: Self = Self::new();
 | 
			
		||||
 | 
			
		||||
        for &b in &value.0 {
 | 
			
		||||
            // Should be safe to unwrap since the string is already long enough
 | 
			
		||||
            s.push(HEX_CHARS[(b >> 4) as usize] as char).unwrap();
 | 
			
		||||
            s.push(HEX_CHARS[(b & 0x0F) as usize] as char).unwrap();
 | 
			
		||||
        }
 | 
			
		||||
        s
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// From a array of hex chars
 | 
			
		||||
impl TryFrom<&[u8]> for TallyID {
 | 
			
		||||
    type Error = ();
 | 
			
		||||
 | 
			
		||||
    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
 | 
			
		||||
        if value.len() != 12 {
 | 
			
		||||
            return Err(());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut out: [u8; 6] = [0; 6];
 | 
			
		||||
        for i in 0..6 {
 | 
			
		||||
            let hi = hex_val(value[2 * i])?;
 | 
			
		||||
            let lo = hex_val(value[2 * i + 1])?;
 | 
			
		||||
            out[i] = (hi << 4) | lo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(TallyID(out))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Serialize for TallyID {
 | 
			
		||||
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
    where
 | 
			
		||||
        S: Serializer,
 | 
			
		||||
    {
 | 
			
		||||
        let s: heapless::String<12> = (*self).into();
 | 
			
		||||
        serializer.serialize_str(&s)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'de> Deserialize<'de> for TallyID {
 | 
			
		||||
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 | 
			
		||||
    where
 | 
			
		||||
        D: Deserializer<'de>,
 | 
			
		||||
    {
 | 
			
		||||
        let s = <&str>::deserialize(deserializer)?;
 | 
			
		||||
        TallyID::from_str(s).map_err(|_| de::Error::custom("Failed to parse Tally ID"))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
use alloc::string::String;
 | 
			
		||||
use picoserve::{
 | 
			
		||||
    extract::{Json, State},
 | 
			
		||||
    response::{self, IntoResponse},
 | 
			
		||||
@ -6,26 +5,31 @@ use picoserve::{
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    store::{Name, hex_string_to_tally_id},
 | 
			
		||||
    store::{Name, tally_id::TallyID},
 | 
			
		||||
    webserver::{app::AppState, sse::IDEvents},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Deserialize)]
 | 
			
		||||
pub struct NewMapping {
 | 
			
		||||
    id: String,
 | 
			
		||||
    id: TallyID,
 | 
			
		||||
    name: Name,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  #[get("/api/idevent")]
 | 
			
		||||
 *  #[get("/api/csv")]
 | 
			
		||||
 *  #[get("/api/mapping")]
 | 
			
		||||
 *  #[post("/api/mapping", format = "json", data = "<new_mapping>")]
 | 
			
		||||
 *  struct NewMapping {
 | 
			
		||||
 *      id: String,
 | 
			
		||||
 *      name: Name,
 | 
			
		||||
 *  }
 | 
			
		||||
*/
 | 
			
		||||
// struct MappingWrapper(IDMapping);
 | 
			
		||||
//
 | 
			
		||||
// impl Serialize for MappingWrapper {
 | 
			
		||||
//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
//     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()
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
pub async fn get_mapping(State(state): State<AppState>) -> impl IntoResponse {
 | 
			
		||||
    let store = state.store.lock().await;
 | 
			
		||||
@ -37,8 +41,7 @@ pub async fn add_mapping(
 | 
			
		||||
    Json(data): Json<NewMapping>,
 | 
			
		||||
) -> impl IntoResponse {
 | 
			
		||||
    let mut store = state.store.lock().await;
 | 
			
		||||
    let tally_id = hex_string_to_tally_id(&data.id).unwrap();
 | 
			
		||||
    store.mapping.add_mapping(tally_id, data.name);
 | 
			
		||||
    store.mapping.add_mapping(data.id, data.name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn get_idevent(State(state): State<AppState>) -> impl IntoResponse {
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ use embassy_time::{Duration, Timer};
 | 
			
		||||
use log::warn;
 | 
			
		||||
use picoserve::response;
 | 
			
		||||
 | 
			
		||||
use crate::{TallySubscriber, store::tally_id_to_hex_string};
 | 
			
		||||
use crate::TallySubscriber;
 | 
			
		||||
 | 
			
		||||
pub struct IDEvents(pub TallySubscriber);
 | 
			
		||||
 | 
			
		||||
@ -18,9 +18,8 @@ impl response::sse::EventSource for IDEvents {
 | 
			
		||||
            match sel.await {
 | 
			
		||||
                embassy_futures::select::Either::First(msg) => match msg {
 | 
			
		||||
                    embassy_sync::pubsub::WaitResult::Message(id) => {
 | 
			
		||||
                        writer
 | 
			
		||||
                            .write_event("msg", tally_id_to_hex_string(id).unwrap().as_str())
 | 
			
		||||
                            .await?
 | 
			
		||||
                        let id_str: heapless::String<12> = id.into();
 | 
			
		||||
                        writer.write_event("msg", id_str.as_str()).await?
 | 
			
		||||
                    }
 | 
			
		||||
                    embassy_sync::pubsub::WaitResult::Lagged(_) => {
 | 
			
		||||
                        warn!("SSE subscriber got lagged");
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user