Compare commits
No commits in common. "chat" and "main" have entirely different histories.
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -1063,12 +1063,6 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "percent-encoding"
|
|
||||||
version = "2.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -1109,17 +1103,14 @@ dependencies = [
|
|||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"embassy-net",
|
"embassy-net",
|
||||||
"embassy-rp",
|
"embassy-rp",
|
||||||
"embassy-sync",
|
|
||||||
"embassy-time",
|
"embassy-time",
|
||||||
"embassy-usb-logger",
|
"embassy-usb-logger",
|
||||||
"embedded-io-async",
|
"embedded-io-async",
|
||||||
"heapless",
|
"heapless",
|
||||||
"log",
|
"log",
|
||||||
"panic-probe",
|
"panic-probe",
|
||||||
"percent-encoding",
|
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"ringbuffer",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde-json-core",
|
"serde-json-core",
|
||||||
"static_cell",
|
"static_cell",
|
||||||
@ -1313,12 +1304,6 @@ 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"
|
||||||
|
@ -36,7 +36,6 @@ embassy-net = { git = "https://github.com/embassy-rs/embassy", features = [
|
|||||||
"udp",
|
"udp",
|
||||||
"dhcpv4",
|
"dhcpv4",
|
||||||
] }
|
] }
|
||||||
embassy-sync = { git = "https://github.com/embassy-rs/embassy" }
|
|
||||||
cyw43-pio = { git = "https://github.com/embassy-rs/embassy" }
|
cyw43-pio = { git = "https://github.com/embassy-rs/embassy" }
|
||||||
cyw43 = { git = "https://github.com/embassy-rs/embassy" }
|
cyw43 = { git = "https://github.com/embassy-rs/embassy" }
|
||||||
|
|
||||||
@ -58,5 +57,3 @@ serde = { version = "*", optional = true, default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
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 }
|
|
||||||
percent-encoding = { version = "*", default-features = false }
|
|
@ -1,41 +0,0 @@
|
|||||||
<!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>
|
|
||||||
<form id="login-page">
|
|
||||||
Enter your name :
|
|
||||||
<input
|
|
||||||
name="username"
|
|
||||||
type="text"
|
|
||||||
autocomplete="username"
|
|
||||||
minlength="3"
|
|
||||||
maxlength="16"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
hx-post="/chat/connect"
|
|
||||||
hx-target="#login-page"
|
|
||||||
hx-swap="outerHTML"
|
|
||||||
>
|
|
||||||
Connect
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
276
src/apps/chat.rs
276
src/apps/chat.rs
@ -1,276 +0,0 @@
|
|||||||
use core::fmt::Write;
|
|
||||||
use dhcparse::dhcpv4::MAX_MESSAGE_SIZE;
|
|
||||||
use embassy_sync::{blocking_mutex::raw::ThreadModeRawMutex, mutex::Mutex};
|
|
||||||
use heapless::{String, Vec};
|
|
||||||
use log::{info, warn};
|
|
||||||
use percent_encoding::percent_decode_str;
|
|
||||||
use pico_website::unwrap;
|
|
||||||
use ringbuffer::{ConstGenericRingBuffer, RingBuffer};
|
|
||||||
|
|
||||||
use crate::socket::{HttpRequestType, HttpResCode};
|
|
||||||
|
|
||||||
use super::App;
|
|
||||||
|
|
||||||
const MEMORY_SIZE: usize = 16;
|
|
||||||
const USERNAME_MIN_SIZE: usize = 3;
|
|
||||||
const USERNAME_SIZE: usize = 16;
|
|
||||||
const MSG_SIZE: usize = 128;
|
|
||||||
|
|
||||||
static MESSAGES: Mutex<ThreadModeRawMutex, Messages> = Mutex::new(Messages::new());
|
|
||||||
|
|
||||||
pub struct ChatApp {
|
|
||||||
res_buf: Vec<u8, 1100>,
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
let mut msg_content = None;
|
|
||||||
let mut poll = false;
|
|
||||||
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)) => {
|
|
||||||
let mut name = String::<USERNAME_SIZE>::new();
|
|
||||||
for c in percent_decode_str(u) {
|
|
||||||
if let Err(_) = name.push(c as char) {
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if u.len() < USERNAME_MIN_SIZE {
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
username = Some(name);
|
|
||||||
}
|
|
||||||
Some(("msg", m)) => {
|
|
||||||
let mut msg = Vec::<u8, MSG_SIZE>::new();
|
|
||||||
let mut i = 0;
|
|
||||||
while i < m.len() {
|
|
||||||
let c = if m.as_bytes()[i] == b'%' {
|
|
||||||
let c = match m
|
|
||||||
.get(i + 1..=i + 2)
|
|
||||||
.map(|s| u8::from_str_radix(s, 16))
|
|
||||||
{
|
|
||||||
Some(Ok(c)) => c,
|
|
||||||
_ => {
|
|
||||||
warn!("Invalid percent encoding of msg argument");
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
i += 2;
|
|
||||||
c
|
|
||||||
} else {
|
|
||||||
m.as_bytes()[i]
|
|
||||||
};
|
|
||||||
if let Err(_) = msg.push(c) {
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_content = Some(match String::from_utf8(msg) {
|
|
||||||
Ok(msg) => msg,
|
|
||||||
Err(_) => {
|
|
||||||
warn!("Invalid utf8 msg argument");
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Some(("poll", "true")) => poll = true,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!(
|
|
||||||
"load:{:?} | username:{:?} | msg:{:?}",
|
|
||||||
load, username, msg_content
|
|
||||||
);
|
|
||||||
if path == "/chat/connect" && username.is_some() {
|
|
||||||
self.res_buf.clear();
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
"<input id=\"username\" style=\"display: none;\" name=\"username\" value=\"{}\">
|
|
||||||
<div id=\"messages\" >\
|
|
||||||
<div \
|
|
||||||
class=\"message\" \
|
|
||||||
hx-get=\"/chat/message/0?load={}\" \
|
|
||||||
hx-target=\"this\" \
|
|
||||||
hx-swap=\"outerHTML\" \
|
|
||||||
hx-trigger=\"load\" \
|
|
||||||
></div>\
|
|
||||||
</div>\
|
|
||||||
<form id=\"send-message\" \
|
|
||||||
hx-post=\"/chat/send\" \
|
|
||||||
hx-include=\"#username\" \
|
|
||||||
hx-target=\"this\" \
|
|
||||||
hx-swap=\"innerHTML\"\
|
|
||||||
>\
|
|
||||||
<input \
|
|
||||||
id=\"msg\" \
|
|
||||||
name=\"msg\" \
|
|
||||||
maxlength=\"{}\"\
|
|
||||||
>\
|
|
||||||
<button>Send</button>
|
|
||||||
</form>",
|
|
||||||
username.unwrap(),
|
|
||||||
MEMORY_SIZE,
|
|
||||||
MAX_MESSAGE_SIZE
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
return (HttpResCode::Ok, "html", &self.res_buf);
|
|
||||||
} else if path == "/chat/send" && username.is_some() && msg_content.is_some() {
|
|
||||||
let mut msgs = MESSAGES.lock().await;
|
|
||||||
msgs.push(Message {
|
|
||||||
author: username.unwrap(),
|
|
||||||
content: msg_content.unwrap(),
|
|
||||||
});
|
|
||||||
self.res_buf.clear();
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
"<input \
|
|
||||||
id=\"msg\" \
|
|
||||||
name=\"msg\" \
|
|
||||||
maxlength=\"{}\"\
|
|
||||||
>\
|
|
||||||
<button>Send</button>",
|
|
||||||
MAX_MESSAGE_SIZE
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
return (HttpResCode::Ok, "html", &self.res_buf);
|
|
||||||
} else if path.starts_with("/chat/message/") && path.len() > 14 {
|
|
||||||
let msg_id: u16 = match path[14..].parse() {
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(_) => return (HttpResCode::BadRequest, "", &[]),
|
|
||||||
};
|
|
||||||
let msgs = MESSAGES.lock().await;
|
|
||||||
if msg_id > msgs.next {
|
|
||||||
return (HttpResCode::BadRequest, "", &[]);
|
|
||||||
}
|
|
||||||
self.res_buf.clear();
|
|
||||||
unwrap(write!(&mut self.res_buf, "<div class=\"message\"")).await;
|
|
||||||
if msg_id == msgs.next {
|
|
||||||
if poll {
|
|
||||||
return (HttpResCode::NoContent, "", &[]);
|
|
||||||
}
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
" style=\"display: none;\" \
|
|
||||||
hx-get=\"/chat/message/{}?load={}&poll=true\" \
|
|
||||||
hx-target=\"this\" \
|
|
||||||
hx-swap=\"outerHTML\" \
|
|
||||||
hx-trigger=\"every 1s\"",
|
|
||||||
msg_id,
|
|
||||||
load.unwrap_or(0)
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
} else {
|
|
||||||
if let Some(n) = load {
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
" hx-get=\"/chat/message/{}?load={}\" \
|
|
||||||
hx-target=\"this\" \
|
|
||||||
hx-swap=\"afterend\" \
|
|
||||||
hx-trigger=\"load\"",
|
|
||||||
msg_id + 1,
|
|
||||||
n - 1,
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
match msgs.get_abs(msg_id) {
|
|
||||||
Some(msg) => {
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
"><b>{}</b>: {}</div>",
|
|
||||||
msg.author, msg.content
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if load.is_some() {
|
|
||||||
if (msg_id as isize)
|
|
||||||
== (msgs.next as isize - MEMORY_SIZE as isize - 1)
|
|
||||||
{
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
"><em>Older messages forgotten</em></div>"
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
} else {
|
|
||||||
unwrap(write!(
|
|
||||||
&mut self.res_buf,
|
|
||||||
" style=\"display: none;\"></div>"
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return (HttpResCode::NoContent, "", &[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return (HttpResCode::Ok, "html", &self.res_buf);
|
|
||||||
} else {
|
|
||||||
(HttpResCode::NotFound, "", &[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Message {
|
|
||||||
author: String<USERNAME_SIZE>,
|
|
||||||
content: String<MSG_SIZE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Messages {
|
|
||||||
inner: ConstGenericRingBuffer<Message, MEMORY_SIZE>,
|
|
||||||
next: u16,
|
|
||||||
}
|
|
||||||
impl Messages {
|
|
||||||
const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: ConstGenericRingBuffer::new(),
|
|
||||||
next: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn get_abs(&self, id: u16) -> Option<&Message> {
|
|
||||||
if (id as isize) < (self.next as isize - MEMORY_SIZE as isize) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
self.inner.get_signed((id as isize) - (self.next as isize))
|
|
||||||
}
|
|
||||||
fn push(&mut self, msg: Message) {
|
|
||||||
info!("{}: {}", msg.author, msg.content);
|
|
||||||
self.inner.push(msg);
|
|
||||||
self.next += 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
use crate::socket::{HttpRequestType, HttpResCode};
|
use crate::socket::HttpResCode;
|
||||||
|
|
||||||
use super::App;
|
use super::App;
|
||||||
|
|
||||||
@ -7,12 +7,7 @@ impl App for IndexApp {
|
|||||||
fn socket_name(&self) -> &'static str {
|
fn socket_name(&self) -> &'static str {
|
||||||
"index"
|
"index"
|
||||||
}
|
}
|
||||||
async fn handle_request<'a>(
|
async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]) {
|
||||||
&'a mut self,
|
|
||||||
path: &str,
|
|
||||||
_req_type: HttpRequestType,
|
|
||||||
_content: &str,
|
|
||||||
) -> (HttpResCode, &'static str, &'a [u8]) {
|
|
||||||
match path {
|
match path {
|
||||||
"/" | "/index" | "/index.html" => {
|
"/" | "/index" | "/index.html" => {
|
||||||
(HttpResCode::Ok, "html", include_bytes!("./index.html"))
|
(HttpResCode::Ok, "html", include_bytes!("./index.html"))
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
use crate::socket::{HttpRequestType, HttpResCode};
|
use crate::socket::HttpResCode;
|
||||||
|
|
||||||
pub mod chat;
|
|
||||||
pub mod index;
|
pub mod index;
|
||||||
pub mod ttt;
|
pub mod ttt;
|
||||||
|
|
||||||
pub trait App {
|
pub trait App {
|
||||||
fn socket_name(&self) -> &'static str;
|
fn socket_name(&self) -> &'static str;
|
||||||
async fn handle_request<'a>(
|
async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]);
|
||||||
&'a mut self,
|
|
||||||
path: &str,
|
|
||||||
req_type: HttpRequestType,
|
|
||||||
content: &str,
|
|
||||||
) -> (HttpResCode, &'static str, &'a [u8]);
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use heapless::Vec;
|
|||||||
use pico_website::unwrap;
|
use pico_website::unwrap;
|
||||||
use portable_atomic::{AtomicBool, AtomicU32};
|
use portable_atomic::{AtomicBool, AtomicU32};
|
||||||
|
|
||||||
use crate::socket::{HttpRequestType, HttpResCode};
|
use crate::socket::HttpResCode;
|
||||||
|
|
||||||
use super::App;
|
use super::App;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ static TURN: AtomicBool = AtomicBool::new(false);
|
|||||||
static BOARD: AtomicU32 = AtomicU32::new(0);
|
static BOARD: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
pub struct TttApp {
|
pub struct TttApp {
|
||||||
res_buf: Vec<u8, 2048>,
|
res_buf: Vec<u8, 4096>,
|
||||||
/// State of the board last time it has been sent
|
/// State of the board last time it has been sent
|
||||||
last_board: u32,
|
last_board: u32,
|
||||||
team: Team,
|
team: Team,
|
||||||
@ -154,12 +154,7 @@ impl App for TttApp {
|
|||||||
fn socket_name(&self) -> &'static str {
|
fn socket_name(&self) -> &'static str {
|
||||||
self.team.name()
|
self.team.name()
|
||||||
}
|
}
|
||||||
async fn handle_request<'a>(
|
async fn handle_request<'a>(&'a mut self, path: &str) -> (HttpResCode, &'static str, &'a [u8]) {
|
||||||
&'a mut self,
|
|
||||||
path: &str,
|
|
||||||
_req_type: HttpRequestType,
|
|
||||||
_content: &str,
|
|
||||||
) -> (HttpResCode, &'static str, &'a [u8]) {
|
|
||||||
match path {
|
match path {
|
||||||
"/" | "/index" | "/index.html" | "/ttt" | "/ttt.html" => {
|
"/" | "/index" | "/index.html" | "/ttt" | "/ttt.html" => {
|
||||||
(HttpResCode::Ok, "html", include_bytes!("./ttt.html"))
|
(HttpResCode::Ok, "html", include_bytes!("./ttt.html"))
|
||||||
|
19
src/main.rs
19
src/main.rs
@ -115,7 +115,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let seed = rng.next_u64();
|
let seed = rng.next_u64();
|
||||||
|
|
||||||
// Init network stack
|
// Init network stack
|
||||||
static RESOURCES: StaticCell<StackResources<20>> = StaticCell::new();
|
static RESOURCES: StaticCell<StackResources<10>> = StaticCell::new();
|
||||||
let (stack, runner) = embassy_net::new(
|
let (stack, runner) = embassy_net::new(
|
||||||
net_device,
|
net_device,
|
||||||
config,
|
config,
|
||||||
@ -170,11 +170,18 @@ 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(stack, apps::ttt::Team::Zero, 8080))).await;
|
unwrap(spawner.spawn(socket::ttt_listen_task(
|
||||||
unwrap(spawner.spawn(socket::ttt_listen_task(stack, apps::ttt::Team::One, 8081))).await;
|
stack,
|
||||||
for _ in 0..4 {
|
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, chat, index::IndexApp, ttt};
|
use crate::apps::{App, 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>, team: ttt::Team, port: u16) {
|
pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, app: ttt::TttApp, port: u16) {
|
||||||
listen_task(stack, ttt::TttApp::new(team), port).await
|
listen_task(stack, app, port).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task(pool_size = 2)]
|
#[embassy_executor::task(pool_size = 2)]
|
||||||
@ -18,20 +18,15 @@ 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 = 4)]
|
|
||||||
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; 1024];
|
let mut rx_buffer = [0; 4096];
|
||||||
let mut tx_buffer = [0; 2048];
|
let mut tx_buffer = [0; 4096];
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; 4096];
|
||||||
let mut res_head_buf = Vec::<u8, 128>::new();
|
let mut res_head_buf = Vec::<u8, 4096>::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
Timer::after_secs(0).await;
|
Timer::after_secs(0).await;
|
||||||
@ -64,31 +59,41 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (headers, content) = match from_utf8(&buf[..n]) {
|
let mut headers: &[u8] = &buf[..n];
|
||||||
Ok(b) => match b.split_once("\r\n\r\n") {
|
let mut _content: &[u8] = &[];
|
||||||
Some(t) => t,
|
for i in 0..(n - 1) {
|
||||||
None => (b, ""),
|
if &buf[i..i + 1] == b"\r\n" {
|
||||||
},
|
headers = &buf[0..i];
|
||||||
Err(_) => {
|
if i + 2 < n {
|
||||||
warn!("Non utf8 http request");
|
_content = &buf[i + 2..n];
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// let mut headers = headers.split(|x| *x == b'\n');
|
let mut headers = headers.split(|x| *x == b'\n');
|
||||||
let (request_type, path) = match headers.lines().next() {
|
let (request_type, path) = match headers.next() {
|
||||||
None => {
|
None => {
|
||||||
warn!("Empty request");
|
warn!("Empty request");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(l1) => {
|
Some(l1) => {
|
||||||
let mut l1 = l1.split(' ');
|
let mut l1 = l1.split(|x| *x == b' ');
|
||||||
(
|
(
|
||||||
match l1.next() {
|
match l1.next() {
|
||||||
Some("GET") => HttpRequestType::Get,
|
Some(b"GET") => HttpRequestType::Get,
|
||||||
Some("POST") => HttpRequestType::Post,
|
Some(b"POST") => HttpRequestType::Post,
|
||||||
Some(t) => {
|
Some(t) => {
|
||||||
warn!("Unknown request type : {}", t);
|
match from_utf8(t) {
|
||||||
|
Ok(t) => {
|
||||||
|
warn!("Unknown request type : {}", t);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!(
|
||||||
|
"Error while parsing request type : {}\nRaw type : {:?}",
|
||||||
|
e, t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -97,7 +102,16 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App,
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
match l1.next() {
|
match l1.next() {
|
||||||
Some(path) => path,
|
Some(path) => match from_utf8(path) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
warn!(
|
||||||
|
"Error while parsing requested path : {}\nRaw path : {:?}",
|
||||||
|
e, path
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
None => {
|
None => {
|
||||||
warn!("No path");
|
warn!("No path");
|
||||||
break;
|
break;
|
||||||
@ -124,7 +138,7 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App,
|
|||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
include_bytes!("../static/htmx.min.js"),
|
include_bytes!("../static/htmx.min.js"),
|
||||||
),
|
),
|
||||||
p => app.handle_request(p, request_type, content).await,
|
p => app.handle_request(p).await,
|
||||||
};
|
};
|
||||||
|
|
||||||
res_head_buf.clear();
|
res_head_buf.clear();
|
||||||
@ -160,7 +174,7 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl App,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum HttpRequestType {
|
enum HttpRequestType {
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
}
|
}
|
||||||
@ -177,7 +191,6 @@ impl Into<&str> for HttpRequestType {
|
|||||||
pub enum HttpResCode {
|
pub enum HttpResCode {
|
||||||
Ok,
|
Ok,
|
||||||
NoContent,
|
NoContent,
|
||||||
BadRequest,
|
|
||||||
NotFound,
|
NotFound,
|
||||||
Forbidden,
|
Forbidden,
|
||||||
}
|
}
|
||||||
@ -186,7 +199,6 @@ 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