save
This commit is contained in:
parent
4cb3736e56
commit
ea43024446
@ -181,10 +181,10 @@ impl App for ChatApp {
|
||||
fn accept_ws(&self, path: &str) -> bool {
|
||||
path == "/"
|
||||
}
|
||||
async fn handle_ws<'a, const BUF_SIZE: usize>(
|
||||
&'a mut self,
|
||||
async fn handle_ws<const BUF_SIZE: usize>(
|
||||
&mut self,
|
||||
_path: &str,
|
||||
mut ws: crate::socket::ws::Ws<'a, BUF_SIZE>,
|
||||
mut ws: crate::socket::ws::Ws<'_, BUF_SIZE>,
|
||||
) {
|
||||
Timer::after_millis(500).await;
|
||||
let r: Result<(), ()> = try {
|
||||
|
@ -21,12 +21,7 @@ pub trait App {
|
||||
fn accept_ws(&self, _path: &str) -> bool {
|
||||
false
|
||||
}
|
||||
async fn handle_ws<'a, const BUF_SIZE: usize>(
|
||||
&'a mut self,
|
||||
_path: &str,
|
||||
_ws: Ws<'a, BUF_SIZE>,
|
||||
) {
|
||||
}
|
||||
async fn handle_ws<const BUF_SIZE: usize>(&mut self, _path: &str, _ws: Ws<'_, BUF_SIZE>) {}
|
||||
}
|
||||
|
||||
pub struct Content<'a>(pub Vec<&'a str, 8>);
|
||||
|
@ -13,8 +13,6 @@ use crate::socket::{HttpRequestType, HttpResCode};
|
||||
|
||||
use super::App;
|
||||
|
||||
// bits [0; 8] : player zero board / bits [9; 17] : player one board / is_ended [18] / is_draw [19] / winner [20]: 0=blue 1=green / current_turn [21]: 0=blue 1=green
|
||||
|
||||
#[derive(Debug, Serialize, Clone, PartialEq, Eq)]
|
||||
struct Game {
|
||||
board: [Option<Team>; 9],
|
||||
|
149
src/socket.rs
149
src/socket.rs
@ -1,12 +1,12 @@
|
||||
use base64::{EncodeSliceError, prelude::*};
|
||||
use base64::prelude::*;
|
||||
use core::fmt::Write;
|
||||
use core::str::from_utf8;
|
||||
use core::{fmt::Write, str::FromStr};
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embedded_io_async::Write as _;
|
||||
use heapless::{String, Vec};
|
||||
use log::{info, warn};
|
||||
use pico_website::{unwrap, unwrap_opt};
|
||||
use pico_website::unwrap;
|
||||
use sha1::{Digest, Sha1};
|
||||
|
||||
use crate::apps::Content;
|
||||
@ -17,24 +17,32 @@ pub mod ws;
|
||||
#[cfg(feature = "ttt")]
|
||||
#[embassy_executor::task(pool_size = 2)]
|
||||
pub async fn ttt_listen_task(stack: embassy_net::Stack<'static>, team: apps::ttt::Team, port: u16) {
|
||||
listen_task(stack, apps::ttt::TttApp::new(team), port).await
|
||||
listen_task::<32, 32, 256, 256>(stack, apps::ttt::TttApp::new(team), port).await
|
||||
}
|
||||
|
||||
#[embassy_executor::task(pool_size = 2)]
|
||||
pub async fn index_listen_task(stack: embassy_net::Stack<'static>, port: u16) {
|
||||
listen_task(stack, apps::index::IndexApp, port).await
|
||||
listen_task::<64, 0, 1024, 1024>(stack, apps::index::IndexApp, port).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "chat")]
|
||||
#[embassy_executor::task(pool_size = 4)]
|
||||
pub async fn chat_listen_task(stack: embassy_net::Stack<'static>, id: u8, port: u16) {
|
||||
listen_task(stack, apps::chat::ChatApp::new(id), port).await
|
||||
listen_task::<64, 512, 512, 512>(stack, apps::chat::ChatApp::new(id), port).await
|
||||
}
|
||||
|
||||
pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps::App, port: u16) {
|
||||
let mut rx_buffer = [0; 1024];
|
||||
let mut tx_buffer = [0; 2048];
|
||||
let mut buf = [0; 1024];
|
||||
pub async fn listen_task<
|
||||
const PATH_LEN: usize,
|
||||
const BUF_LEN: usize,
|
||||
const RX_LEN: usize,
|
||||
const TX_LEN: usize,
|
||||
>(
|
||||
stack: embassy_net::Stack<'static>,
|
||||
mut app: impl apps::App,
|
||||
port: u16,
|
||||
) {
|
||||
let mut rx_buffer = [0; RX_LEN];
|
||||
let mut tx_buffer = [0; TX_LEN];
|
||||
let mut head_buf = Vec::<u8, 256>::new();
|
||||
loop {
|
||||
Timer::after_secs(0).await;
|
||||
@ -54,11 +62,15 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
);
|
||||
|
||||
let (mut rx, mut tx) = socket.split();
|
||||
let mut ws_path: Option<String<16>> = None;
|
||||
let mut buf = String::<BUF_LEN>::new();
|
||||
let mut path = String::<PATH_LEN>::new();
|
||||
let mut request_type = HttpRequestType::Get;
|
||||
let mut is_ws = false;
|
||||
loop {
|
||||
Timer::after_secs(0).await;
|
||||
let mut cont = &[];
|
||||
rx.read_with(|msg| {
|
||||
|
||||
match rx
|
||||
.read_with(|msg| {
|
||||
let (headers, content) = match from_utf8(msg) {
|
||||
Ok(b) => match b.split_once("\r\n\r\n") {
|
||||
Some(t) => t,
|
||||
@ -69,16 +81,20 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
return (0, Err(()));
|
||||
}
|
||||
};
|
||||
buf.clear();
|
||||
if let Err(_) = buf.push_str(content) {
|
||||
warn!("Received content is bigger than maximum content!");
|
||||
return (0, Err(()));
|
||||
}
|
||||
let mut hl = headers.lines();
|
||||
let (request_type, path) = match hl.next() {
|
||||
match hl.next() {
|
||||
None => {
|
||||
warn!("Empty request");
|
||||
return (0, Err(()));
|
||||
}
|
||||
Some(l1) => {
|
||||
let mut l1 = l1.split(' ');
|
||||
(
|
||||
match l1.next() {
|
||||
request_type = match l1.next() {
|
||||
Some("GET") => HttpRequestType::Get,
|
||||
Some("POST") => HttpRequestType::Post,
|
||||
Some(t) => {
|
||||
@ -89,19 +105,22 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
warn!("No request type");
|
||||
return (0, Err(()));
|
||||
}
|
||||
},
|
||||
match l1.next() {
|
||||
};
|
||||
path.clear();
|
||||
if let Err(_) = path.push_str(match l1.next() {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
warn!("No path");
|
||||
return (0, Err(()));
|
||||
}
|
||||
},
|
||||
)
|
||||
}) {
|
||||
warn!("Path is too big!");
|
||||
return (0, Err(()));
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut host = None;
|
||||
let mut ws_handshake = false;
|
||||
|
||||
let mut ws_key = None;
|
||||
for h in hl {
|
||||
let Some((name, val)) = h.split_once(':') else {
|
||||
@ -111,27 +130,55 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
let val = val.trim();
|
||||
match (name, val) {
|
||||
("Host", _) => host = Some(val),
|
||||
("Upgrade", "websocket") => ws_handshake = true,
|
||||
("Upgrade", "websocket") => is_ws = true,
|
||||
("Sec-WebSocket-Key", _) => ws_key = Some(val),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let Some(host) = host else {
|
||||
warn!("No host");
|
||||
warn!("No host!");
|
||||
return (0, Err(()));
|
||||
};
|
||||
info!(
|
||||
"Socket {}: {:?}{} request for {}{}",
|
||||
app.socket_name(),
|
||||
request_type,
|
||||
if ws_handshake { " websocket" } else { "" },
|
||||
if is_ws { " websocket" } else { "" },
|
||||
host,
|
||||
path,
|
||||
);
|
||||
buf.clear();
|
||||
if is_ws {
|
||||
let Some(key) = ws_key else {
|
||||
warn!("No ws key!");
|
||||
return (0, Err(()));
|
||||
};
|
||||
if let Err(_) = buf.push_str(key) {
|
||||
warn!("Ws key is too long!");
|
||||
return (0, Err(()));
|
||||
}
|
||||
} else {
|
||||
if let Err(_) = buf.push_str(content) {
|
||||
warn!("Content is too long!");
|
||||
return (0, Err(()));
|
||||
}
|
||||
}
|
||||
(msg.len(), Ok(()))
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(())) => break,
|
||||
Err(e) => {
|
||||
warn!("Error while receiving : {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
head_buf.clear();
|
||||
let res_content: Result<Option<Content>, core::fmt::Error> = try {
|
||||
if ws_handshake {
|
||||
if !app.accept_ws(path) {
|
||||
if is_ws {
|
||||
if !app.accept_ws(&path) {
|
||||
warn!("No ws there!");
|
||||
write!(
|
||||
&mut head_buf,
|
||||
@ -140,16 +187,8 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
)?;
|
||||
None
|
||||
} else {
|
||||
if path.len() > 16 {
|
||||
warn!("Ws socket cannot have path longer than 16 chars!");
|
||||
return (0, Err(()));
|
||||
}
|
||||
let Some(key) = ws_key else {
|
||||
warn!("No ws key!");
|
||||
return (0, Err(()));
|
||||
};
|
||||
let Ok(accept) = compute_ws_accept(key) else {
|
||||
return (0, Err(()));
|
||||
let Ok(accept) = compute_ws_accept(&buf) else {
|
||||
break;
|
||||
};
|
||||
write!(
|
||||
&mut head_buf,
|
||||
@ -164,7 +203,7 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
}
|
||||
} else {
|
||||
let (code, res_type, res_content) =
|
||||
app.handle_request(path, request_type, content).await;
|
||||
app.handle_request(&path, request_type, &buf).await;
|
||||
|
||||
write!(&mut head_buf, "{}", Into::<&str>::into(code))?;
|
||||
if let Some(ref c) = res_content {
|
||||
@ -181,20 +220,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
res_content
|
||||
}
|
||||
};
|
||||
(msg.len(), Ok(()))
|
||||
})
|
||||
.await;
|
||||
let n = match socket.read(&mut buf).await {
|
||||
Ok(0) => {
|
||||
warn!("read EOF");
|
||||
break;
|
||||
}
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
warn!("Socket {}: read error: {:?}", app.socket_name(), e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let res_content = match res_content {
|
||||
Ok(rc) => rc,
|
||||
@ -205,10 +230,10 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
};
|
||||
|
||||
let w: Result<(), embassy_net::tcp::Error> = try {
|
||||
socket.write_all(&head_buf).await?;
|
||||
tx.write_all(&head_buf).await?;
|
||||
if let Some(ref c) = res_content {
|
||||
for s in c.0.iter() {
|
||||
socket.write_all(s.as_bytes()).await?;
|
||||
tx.write_all(s.as_bytes()).await?;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -217,14 +242,18 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
warn!("write error: {:?}", e);
|
||||
break;
|
||||
};
|
||||
|
||||
if ws_handshake {
|
||||
ws_path = Some(unwrap(String::from_str(path)).await);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(path) = ws_path {
|
||||
app.handle_ws(&path, Ws::new(&mut socket, &mut buf, app.socket_name()))
|
||||
if is_ws {
|
||||
let mut buf = buf.into_bytes();
|
||||
unwrap(buf.resize_default(BUF_LEN)).await;
|
||||
app.handle_ws::<BUF_LEN>(
|
||||
&path,
|
||||
Ws::new(
|
||||
&mut socket,
|
||||
&mut unwrap(buf.into_array()).await,
|
||||
app.socket_name(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user