save
This commit is contained in:
parent
f085ceba1e
commit
b90c978a38
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -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"
|
||||
|
@ -57,3 +57,4 @@ serde = { version = "*", optional = true, default-features = false, features = [
|
||||
] }
|
||||
dhcparse = { version = "*", default-features = false, optional = true }
|
||||
dnsparse = { version = "*", optional = true }
|
||||
ringbuffer = { version = "*", default-features = false }
|
53
src/apps/chat.html
Normal file
53
src/apps/chat.html
Normal file
@ -0,0 +1,53 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<script src="./htmx.js"></script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
/* #grid {
|
||||
.cell {
|
||||
border: 1px dotted black;
|
||||
padding: 33%;
|
||||
}
|
||||
display: grid;
|
||||
border: 1px solid black;
|
||||
grid-template-rows: 1fr 1fr 1fr;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
} */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Chat</h1>
|
||||
|
||||
<!-- <div
|
||||
class="message"
|
||||
hx-get="/chat/message/abs/0?load=3"
|
||||
hx-target="this"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
<div class="message"></div>
|
||||
<div class="message"></div>
|
||||
<div class="message"></div> -->
|
||||
<form id="login-page">
|
||||
Enter your name :
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
minlength="3"
|
||||
maxlength="16"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
hx-get="/chat/connect"
|
||||
hx-include="#username"
|
||||
hx-target="#login-page"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
Connect
|
||||
</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
163
src/apps/chat.rs
Normal file
163
src/apps/chat.rs
Normal file
@ -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<u8, 2048>,
|
||||
msgs: ConstGenericRingBuffer<Message, MEMORY_SIZE>,
|
||||
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",
|
||||
"<div \
|
||||
class=\"message\" \
|
||||
hx-get=\"/chat/message/abs/0?load=\" \
|
||||
hx-target=\"this\" \
|
||||
hx-swap=\"outerHTML\" \
|
||||
hx-trigger=\"load\" \
|
||||
></div>",
|
||||
);
|
||||
} 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, "<div class=\"message\"")).await;
|
||||
if let Some(n) = load {
|
||||
unwrap(write!(
|
||||
&mut self.res_buf,
|
||||
" hx-get=\"/chat/message/abs/{}?load={}\" \
|
||||
hx-target=\"this\" \
|
||||
hx-swap=\"afterend\" \
|
||||
hx-trigger=\"load\"",
|
||||
msg_id + 1,
|
||||
n - 1
|
||||
))
|
||||
.await;
|
||||
}
|
||||
unwrap(write!(
|
||||
&mut self.res_buf,
|
||||
"><b>{}</b>: {}</div>",
|
||||
msg.author, msg.content
|
||||
))
|
||||
.await;
|
||||
// unwrap(write!(
|
||||
// &mut self.res_buf,
|
||||
// "<div class=\"message\" \
|
||||
// hx-get=\"/chat/message{}\" \
|
||||
// hx-target=\"next .message\" \
|
||||
// hx-swap=\"outerHTML\" \
|
||||
// hx-trigger=\"load\"\
|
||||
// >\
|
||||
// <b>{}</b>: {}\
|
||||
// </div>",
|
||||
// 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>,
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use crate::socket::HttpResCode;
|
||||
|
||||
pub mod chat;
|
||||
pub mod index;
|
||||
pub mod ttt;
|
||||
|
||||
|
15
src/main.rs
15
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")]
|
||||
|
@ -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::<u8, 4096>::new();
|
||||
let mut rx_buffer = [0; 8192];
|
||||
let mut tx_buffer = [0; 8192];
|
||||
let mut buf = [0; 1024];
|
||||
let mut res_head_buf = Vec::<u8, 1024>::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",
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user