From b90c978a38f99ea6b0967441c650b25f2f13f978 Mon Sep 17 00:00:00 2001
From: Arkitu <85173315+Arkitu@users.noreply.github.com>
Date: Thu, 1 May 2025 21:30:55 +0200
Subject: [PATCH] save
---
Cargo.lock | 7 ++
Cargo.toml | 3 +-
src/apps/chat.html | 53 +++++++++++++++
src/apps/chat.rs | 163 +++++++++++++++++++++++++++++++++++++++++++++
src/apps/mod.rs | 1 +
src/main.rs | 15 +----
src/socket.rs | 21 ++++--
7 files changed, 243 insertions(+), 20 deletions(-)
create mode 100644 src/apps/chat.html
create mode 100644 src/apps/chat.rs
diff --git a/Cargo.lock b/Cargo.lock
index 8471634..6c0442c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1111,6 +1111,7 @@ dependencies = [
"panic-probe",
"portable-atomic",
"rand_core",
+ "ringbuffer",
"serde",
"serde-json-core",
"static_cell",
@@ -1304,6 +1305,12 @@ dependencies = [
"bytemuck",
]
+[[package]]
+name = "ringbuffer"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53"
+
[[package]]
name = "rp-pac"
version = "7.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index e190936..f430dbf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -56,4 +56,5 @@ serde = { version = "*", optional = true, default-features = false, features = [
"derive",
] }
dhcparse = { version = "*", default-features = false, optional = true }
-dnsparse = { version = "*", optional = true }
\ No newline at end of file
+dnsparse = { version = "*", optional = true }
+ringbuffer = { version = "*", default-features = false }
\ No newline at end of file
diff --git a/src/apps/chat.html b/src/apps/chat.html
new file mode 100644
index 0000000..706ec69
--- /dev/null
+++ b/src/apps/chat.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+ Chat
+
+
+
+
+
diff --git a/src/apps/chat.rs b/src/apps/chat.rs
new file mode 100644
index 0000000..38665a8
--- /dev/null
+++ b/src/apps/chat.rs
@@ -0,0 +1,163 @@
+use core::fmt::Write;
+use heapless::{String, Vec};
+use log::info;
+use pico_website::unwrap;
+use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
+
+use crate::socket::HttpResCode;
+
+use super::App;
+
+const MEMORY_SIZE: usize = 16;
+
+pub struct ChatApp {
+ res_buf: Vec,
+ msgs: ConstGenericRingBuffer,
+ next_msg: u16,
+}
+impl ChatApp {
+ pub fn new() -> Self {
+ let mut msgs = ConstGenericRingBuffer::new();
+
+ let mut aut0 = String::new();
+ write!(&mut aut0, "rael").unwrap();
+ let mut msg0 = String::new();
+ write!(&mut msg0, "Prout...").unwrap();
+ msgs.push(Message {
+ author: aut0,
+ content: msg0,
+ });
+ let mut aut1 = String::new();
+ write!(&mut aut1, "josh").unwrap();
+ let mut msg1 = String::new();
+ write!(&mut msg1, "Salut !\nJe m'appelle...").unwrap();
+ msgs.push(Message {
+ author: aut1,
+ content: msg1,
+ });
+
+ Self {
+ res_buf: Vec::new(),
+ msgs,
+ next_msg: 2,
+ }
+ }
+}
+impl App for ChatApp {
+ fn socket_name(&self) -> &'static str {
+ "chat"
+ }
+ async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]) {
+ match path {
+ "/" | "/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('&') {
+ 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() {
+ return (
+ HttpResCode::Ok,
+ "html",
+ "",
+ );
+ } 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, "", &[]),
+ };
+ info!("msg_id = {:?}", msg_id);
+ if msg_id >= self.next_msg {
+ return (HttpResCode::BadRequest, "", &[]);
+ }
+ if msg_id < self.next_msg.saturating_sub(MEMORY_SIZE as u16 + 1) {
+ return (HttpResCode::NoContent, "", &[]);
+ }
+ let msg = match self
+ .msgs
+ .get_signed((msg_id as isize) + 1 - (self.next_msg as isize))
+ {
+ Some(msg) => msg,
+ None => return (HttpResCode::NoContent, "", &[]),
+ };
+ self.res_buf.clear();
+ unwrap(write!(&mut self.res_buf, "{}: {}
",
+ msg.author, msg.content
+ ))
+ .await;
+ // unwrap(write!(
+ // &mut self.res_buf,
+ // "\
+ // {}: {}\
+ //
",
+ // match load {
+ // Some(target) => "hx-get=\"/chat/message{}\" \
+ // hx-target=\"next .message\" \
+ // hx-swap=\"outerHTML\" \
+ // hx-trigger=\"load\"\"
+ // }
+ // (msg_num + 1),
+ // msg.author,
+ // msg.content
+ // ))
+ // .await;
+ return (HttpResCode::Ok, "html", &self.res_buf);
+ } else {
+ (HttpResCode::NotFound, "", &[])
+ }
+ }
+ }
+ }
+}
+
+struct Message {
+ author: String<16>,
+ content: String<256>,
+}
diff --git a/src/apps/mod.rs b/src/apps/mod.rs
index 9699932..4074c14 100644
--- a/src/apps/mod.rs
+++ b/src/apps/mod.rs
@@ -1,5 +1,6 @@
use crate::socket::HttpResCode;
+pub mod chat;
pub mod index;
pub mod ttt;
diff --git a/src/main.rs b/src/main.rs
index 8774e8c..0c9e260 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -170,18 +170,9 @@ async fn main(spawner: Spawner) {
unwrap(spawner.spawn(dns::dns_server(stack))).await;
unwrap(spawner.spawn(socket::index_listen_task(stack, 80))).await;
- unwrap(spawner.spawn(socket::ttt_listen_task(
- stack,
- apps::ttt::TttApp::new(apps::ttt::Team::Zero),
- 8080,
- )))
- .await;
- unwrap(spawner.spawn(socket::ttt_listen_task(
- stack,
- apps::ttt::TttApp::new(apps::ttt::Team::One),
- 8081,
- )))
- .await;
+ unwrap(spawner.spawn(socket::ttt_listen_task(stack, apps::ttt::Team::Zero, 8080))).await;
+ unwrap(spawner.spawn(socket::ttt_listen_task(stack, apps::ttt::Team::One, 8081))).await;
+ unwrap(spawner.spawn(socket::chat_listen_task(stack, 8082))).await;
}
#[cfg(feature = "wifi-connect")]
diff --git a/src/socket.rs b/src/socket.rs
index 9355839..6b2842b 100644
--- a/src/socket.rs
+++ b/src/socket.rs
@@ -6,11 +6,11 @@ use embedded_io_async::Write as _;
use heapless::Vec;
use log::{info, warn};
-use crate::apps::{App, index::IndexApp, ttt};
+use crate::apps::{App, chat, index::IndexApp, ttt};
#[embassy_executor::task(pool_size = 2)]
-pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, app: ttt::TttApp, port: u16) {
- listen_task(stack, app, port).await
+pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, team: ttt::Team, port: u16) {
+ listen_task(stack, ttt::TttApp::new(team), port).await
}
#[embassy_executor::task(pool_size = 2)]
@@ -18,15 +18,20 @@ pub async fn index_listen_task(stack: embassy_net::Stack<'static>, port: u16) {
listen_task(stack, IndexApp, port).await
}
+#[embassy_executor::task(pool_size = 1)]
+pub async fn chat_listen_task(stack: embassy_net::Stack<'static>, port: u16) {
+ listen_task(stack, chat::ChatApp::new(), port).await
+}
+
pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App, port: u16) {
// loop {
// info!("team:{:?}", team);
// Timer::after_millis(0).await;
// }
- let mut rx_buffer = [0; 4096];
- let mut tx_buffer = [0; 4096];
- let mut buf = [0; 4096];
- let mut res_head_buf = Vec::::new();
+ let mut rx_buffer = [0; 8192];
+ let mut tx_buffer = [0; 8192];
+ let mut buf = [0; 1024];
+ let mut res_head_buf = Vec::::new();
loop {
Timer::after_secs(0).await;
@@ -191,6 +196,7 @@ impl Into<&str> for HttpRequestType {
pub enum HttpResCode {
Ok,
NoContent,
+ BadRequest,
NotFound,
Forbidden,
}
@@ -199,6 +205,7 @@ impl Into<&str> for HttpResCode {
match self {
HttpResCode::Ok => "HTTP/1.1 200 OK",
HttpResCode::NoContent => "HTTP/1.1 204 NO CONTENT",
+ HttpResCode::BadRequest => "HTTP/1.1 400 BAD REQUEST",
HttpResCode::NotFound => "HTTP/1.1 404 NOT FOUND",
HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN",
}