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",
|
"panic-probe",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
"ringbuffer",
|
||||||
"serde",
|
"serde",
|
||||||
"serde-json-core",
|
"serde-json-core",
|
||||||
"static_cell",
|
"static_cell",
|
||||||
@ -1304,6 +1305,12 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ringbuffer"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3df6368f71f205ff9c33c076d170dd56ebf68e8161c733c0caa07a7a5509ed53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rp-pac"
|
name = "rp-pac"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
|
@ -56,4 +56,5 @@ serde = { version = "*", optional = true, default-features = false, features = [
|
|||||||
"derive",
|
"derive",
|
||||||
] }
|
] }
|
||||||
dhcparse = { version = "*", default-features = false, optional = true }
|
dhcparse = { version = "*", default-features = false, optional = true }
|
||||||
dnsparse = { version = "*", 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;
|
use crate::socket::HttpResCode;
|
||||||
|
|
||||||
|
pub mod chat;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod ttt;
|
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(dns::dns_server(stack))).await;
|
||||||
|
|
||||||
unwrap(spawner.spawn(socket::index_listen_task(stack, 80))).await;
|
unwrap(spawner.spawn(socket::index_listen_task(stack, 80))).await;
|
||||||
unwrap(spawner.spawn(socket::ttt_listen_task(
|
unwrap(spawner.spawn(socket::ttt_listen_task(stack, apps::ttt::Team::Zero, 8080))).await;
|
||||||
stack,
|
unwrap(spawner.spawn(socket::ttt_listen_task(stack, apps::ttt::Team::One, 8081))).await;
|
||||||
apps::ttt::TttApp::new(apps::ttt::Team::Zero),
|
unwrap(spawner.spawn(socket::chat_listen_task(stack, 8082))).await;
|
||||||
8080,
|
|
||||||
)))
|
|
||||||
.await;
|
|
||||||
unwrap(spawner.spawn(socket::ttt_listen_task(
|
|
||||||
stack,
|
|
||||||
apps::ttt::TttApp::new(apps::ttt::Team::One),
|
|
||||||
8081,
|
|
||||||
)))
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wifi-connect")]
|
#[cfg(feature = "wifi-connect")]
|
||||||
|
@ -6,11 +6,11 @@ use embedded_io_async::Write as _;
|
|||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use log::{info, warn};
|
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)]
|
#[embassy_executor::task(pool_size = 2)]
|
||||||
pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, app: ttt::TttApp, port: u16) {
|
pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, team: ttt::Team, port: u16) {
|
||||||
listen_task(stack, app, port).await
|
listen_task(stack, ttt::TttApp::new(team), port).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task(pool_size = 2)]
|
#[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
|
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) {
|
pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App, port: u16) {
|
||||||
// loop {
|
// loop {
|
||||||
// info!("team:{:?}", team);
|
// info!("team:{:?}", team);
|
||||||
// Timer::after_millis(0).await;
|
// Timer::after_millis(0).await;
|
||||||
// }
|
// }
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 8192];
|
||||||
let mut tx_buffer = [0; 4096];
|
let mut tx_buffer = [0; 8192];
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 1024];
|
||||||
let mut res_head_buf = Vec::<u8, 4096>::new();
|
let mut res_head_buf = Vec::<u8, 1024>::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
Timer::after_secs(0).await;
|
Timer::after_secs(0).await;
|
||||||
@ -191,6 +196,7 @@ impl Into<&str> for HttpRequestType {
|
|||||||
pub enum HttpResCode {
|
pub enum HttpResCode {
|
||||||
Ok,
|
Ok,
|
||||||
NoContent,
|
NoContent,
|
||||||
|
BadRequest,
|
||||||
NotFound,
|
NotFound,
|
||||||
Forbidden,
|
Forbidden,
|
||||||
}
|
}
|
||||||
@ -199,6 +205,7 @@ impl Into<&str> for HttpResCode {
|
|||||||
match self {
|
match self {
|
||||||
HttpResCode::Ok => "HTTP/1.1 200 OK",
|
HttpResCode::Ok => "HTTP/1.1 200 OK",
|
||||||
HttpResCode::NoContent => "HTTP/1.1 204 NO CONTENT",
|
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::NotFound => "HTTP/1.1 404 NOT FOUND",
|
||||||
HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN",
|
HttpResCode::Forbidden => "HTTP/1.1 403 FORBIDDEN",
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user