use core::fmt::Write; use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, mutex::Mutex}; use heapless::{String, Vec}; use pico_website::unwrap; use ringbuffer::{ConstGenericRingBuffer, RingBuffer}; use crate::socket::{HttpRequestType, HttpResCode}; use super::App; const MEMORY_SIZE: usize = 16; static MESSAGES: Mutex = Mutex::new(Messages::new()); pub struct ChatApp { res_buf: Vec, } impl ChatApp { pub fn new() -> Self { Self { res_buf: Vec::new(), } } } impl App for ChatApp { fn socket_name(&self) -> &'static str { "chat" } async fn handle_request<'a>( &'a mut self, path: &str, req_type: HttpRequestType, content: &str, ) -> (HttpResCode, &'static str, &'a [u8]) { match (req_type, path) { (HttpRequestType::Get, "/" | "/index" | "/index.html" | "/chat" | "/chat.html") => { (HttpResCode::Ok, "html", include_bytes!("./chat.html")) } (_, path) => { let (path, args) = path.split_once('?').unwrap_or((path, "")); let mut load = None; let mut username = None; for arg in args.split('&').chain(content.split('&')) { match arg.split_once('=') { Some(("load", n)) => { let n: u16 = match n.parse() { Ok(v) => v, Err(_) => return (HttpResCode::BadRequest, "", &[]), }; if n > 0 { load = Some(n); } } Some(("username", u)) => { if u.len() < 3 || u.len() > 16 { return (HttpResCode::BadRequest, "", &[]); } username = Some(u); } _ => {} } } if path == "/chat" && username.is_some() { self.res_buf.clear(); unwrap(write!( &mut self.res_buf, "
", MEMORY_SIZE )) .await; return (HttpResCode::Ok, "html", &self.res_buf); } else if path.starts_with("/chat/message/abs/") && path.len() > 18 { let msg_id: u16 = match path[18..].parse() { Ok(n) => n, Err(_) => return (HttpResCode::BadRequest, "", &[]), }; let msgs = MESSAGES.lock().await; if msg_id >= msgs.next { return (HttpResCode::BadRequest, "", &[]); } if msg_id < msgs.next.saturating_sub(MEMORY_SIZE as u16 + 1) { return (HttpResCode::NoContent, "", &[]); } self.res_buf.clear(); unwrap(write!(&mut self.res_buf, "
msg, None => return (HttpResCode::NoContent, "", &[]), }; unwrap(write!( &mut self.res_buf, ">{}: {}
", msg.author, msg.content )) .await; return (HttpResCode::Ok, "html", &self.res_buf); } else { (HttpResCode::NotFound, "", &[]) } } } } } struct Message { author: String<16>, content: String<256>, } struct Messages { inner: ConstGenericRingBuffer, next: u16, } impl Messages { const fn new() -> Self { Self { inner: ConstGenericRingBuffer::new(), next: 2, } } fn get_abs(&self, id: u16) -> Option<&Message> { self.inner .get_signed((id as isize) + 1 - (self.next as isize)) } }