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 {
|
fn accept_ws(&self, path: &str) -> bool {
|
||||||
path == "/"
|
path == "/"
|
||||||
}
|
}
|
||||||
async fn handle_ws<'a, const BUF_SIZE: usize>(
|
async fn handle_ws<const BUF_SIZE: usize>(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
_path: &str,
|
_path: &str,
|
||||||
mut ws: crate::socket::ws::Ws<'a, BUF_SIZE>,
|
mut ws: crate::socket::ws::Ws<'_, BUF_SIZE>,
|
||||||
) {
|
) {
|
||||||
Timer::after_millis(500).await;
|
Timer::after_millis(500).await;
|
||||||
let r: Result<(), ()> = try {
|
let r: Result<(), ()> = try {
|
||||||
|
@ -21,12 +21,7 @@ pub trait App {
|
|||||||
fn accept_ws(&self, _path: &str) -> bool {
|
fn accept_ws(&self, _path: &str) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
async fn handle_ws<'a, const BUF_SIZE: usize>(
|
async fn handle_ws<const BUF_SIZE: usize>(&mut self, _path: &str, _ws: Ws<'_, BUF_SIZE>) {}
|
||||||
&'a mut self,
|
|
||||||
_path: &str,
|
|
||||||
_ws: Ws<'a, BUF_SIZE>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Content<'a>(pub Vec<&'a str, 8>);
|
pub struct Content<'a>(pub Vec<&'a str, 8>);
|
||||||
|
@ -13,8 +13,6 @@ use crate::socket::{HttpRequestType, HttpResCode};
|
|||||||
|
|
||||||
use super::App;
|
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)]
|
#[derive(Debug, Serialize, Clone, PartialEq, Eq)]
|
||||||
struct Game {
|
struct Game {
|
||||||
board: [Option<Team>; 9],
|
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::str::from_utf8;
|
||||||
use core::{fmt::Write, str::FromStr};
|
|
||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_io_async::Write as _;
|
use embedded_io_async::Write as _;
|
||||||
use heapless::{String, Vec};
|
use heapless::{String, Vec};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use pico_website::{unwrap, unwrap_opt};
|
use pico_website::unwrap;
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
use crate::apps::Content;
|
use crate::apps::Content;
|
||||||
@ -17,24 +17,32 @@ pub mod ws;
|
|||||||
#[cfg(feature = "ttt")]
|
#[cfg(feature = "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: apps::ttt::Team, port: u16) {
|
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)]
|
#[embassy_executor::task(pool_size = 2)]
|
||||||
pub async fn index_listen_task(stack: embassy_net::Stack<'static>, port: u16) {
|
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")]
|
#[cfg(feature = "chat")]
|
||||||
#[embassy_executor::task(pool_size = 4)]
|
#[embassy_executor::task(pool_size = 4)]
|
||||||
pub async fn chat_listen_task(stack: embassy_net::Stack<'static>, id: u8, port: u16) {
|
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) {
|
pub async fn listen_task<
|
||||||
let mut rx_buffer = [0; 1024];
|
const PATH_LEN: usize,
|
||||||
let mut tx_buffer = [0; 2048];
|
const BUF_LEN: usize,
|
||||||
let mut buf = [0; 1024];
|
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();
|
let mut head_buf = Vec::<u8, 256>::new();
|
||||||
loop {
|
loop {
|
||||||
Timer::after_secs(0).await;
|
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 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 {
|
loop {
|
||||||
Timer::after_secs(0).await;
|
Timer::after_secs(0).await;
|
||||||
let mut cont = &[];
|
|
||||||
rx.read_with(|msg| {
|
match rx
|
||||||
|
.read_with(|msg| {
|
||||||
let (headers, content) = match from_utf8(msg) {
|
let (headers, content) = match from_utf8(msg) {
|
||||||
Ok(b) => match b.split_once("\r\n\r\n") {
|
Ok(b) => match b.split_once("\r\n\r\n") {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
@ -69,16 +81,20 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
|||||||
return (0, Err(()));
|
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 mut hl = headers.lines();
|
||||||
let (request_type, path) = match hl.next() {
|
match hl.next() {
|
||||||
None => {
|
None => {
|
||||||
warn!("Empty request");
|
warn!("Empty request");
|
||||||
return (0, Err(()));
|
return (0, Err(()));
|
||||||
}
|
}
|
||||||
Some(l1) => {
|
Some(l1) => {
|
||||||
let mut l1 = l1.split(' ');
|
let mut l1 = l1.split(' ');
|
||||||
(
|
request_type = match l1.next() {
|
||||||
match l1.next() {
|
|
||||||
Some("GET") => HttpRequestType::Get,
|
Some("GET") => HttpRequestType::Get,
|
||||||
Some("POST") => HttpRequestType::Post,
|
Some("POST") => HttpRequestType::Post,
|
||||||
Some(t) => {
|
Some(t) => {
|
||||||
@ -89,19 +105,22 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
|||||||
warn!("No request type");
|
warn!("No request type");
|
||||||
return (0, Err(()));
|
return (0, Err(()));
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
match l1.next() {
|
path.clear();
|
||||||
|
if let Err(_) = path.push_str(match l1.next() {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => {
|
None => {
|
||||||
warn!("No path");
|
warn!("No path");
|
||||||
return (0, Err(()));
|
return (0, Err(()));
|
||||||
}
|
}
|
||||||
},
|
}) {
|
||||||
)
|
warn!("Path is too big!");
|
||||||
|
return (0, Err(()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut host = None;
|
let mut host = None;
|
||||||
let mut ws_handshake = false;
|
|
||||||
let mut ws_key = None;
|
let mut ws_key = None;
|
||||||
for h in hl {
|
for h in hl {
|
||||||
let Some((name, val)) = h.split_once(':') else {
|
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();
|
let val = val.trim();
|
||||||
match (name, val) {
|
match (name, val) {
|
||||||
("Host", _) => host = Some(val),
|
("Host", _) => host = Some(val),
|
||||||
("Upgrade", "websocket") => ws_handshake = true,
|
("Upgrade", "websocket") => is_ws = true,
|
||||||
("Sec-WebSocket-Key", _) => ws_key = Some(val),
|
("Sec-WebSocket-Key", _) => ws_key = Some(val),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Some(host) = host else {
|
let Some(host) = host else {
|
||||||
warn!("No host");
|
warn!("No host!");
|
||||||
return (0, Err(()));
|
return (0, Err(()));
|
||||||
};
|
};
|
||||||
info!(
|
info!(
|
||||||
"Socket {}: {:?}{} request for {}{}",
|
"Socket {}: {:?}{} request for {}{}",
|
||||||
app.socket_name(),
|
app.socket_name(),
|
||||||
request_type,
|
request_type,
|
||||||
if ws_handshake { " websocket" } else { "" },
|
if is_ws { " websocket" } else { "" },
|
||||||
host,
|
host,
|
||||||
path,
|
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();
|
head_buf.clear();
|
||||||
let res_content: Result<Option<Content>, core::fmt::Error> = try {
|
let res_content: Result<Option<Content>, core::fmt::Error> = try {
|
||||||
if ws_handshake {
|
if is_ws {
|
||||||
if !app.accept_ws(path) {
|
if !app.accept_ws(&path) {
|
||||||
warn!("No ws there!");
|
warn!("No ws there!");
|
||||||
write!(
|
write!(
|
||||||
&mut head_buf,
|
&mut head_buf,
|
||||||
@ -140,16 +187,8 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
|||||||
)?;
|
)?;
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
if path.len() > 16 {
|
let Ok(accept) = compute_ws_accept(&buf) else {
|
||||||
warn!("Ws socket cannot have path longer than 16 chars!");
|
break;
|
||||||
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(()));
|
|
||||||
};
|
};
|
||||||
write!(
|
write!(
|
||||||
&mut head_buf,
|
&mut head_buf,
|
||||||
@ -164,7 +203,7 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (code, res_type, res_content) =
|
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))?;
|
write!(&mut head_buf, "{}", Into::<&str>::into(code))?;
|
||||||
if let Some(ref c) = res_content {
|
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
|
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 {
|
let res_content = match res_content {
|
||||||
Ok(rc) => rc,
|
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 {
|
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 {
|
if let Some(ref c) = res_content {
|
||||||
for s in c.0.iter() {
|
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);
|
warn!("write error: {:?}", e);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ws_handshake {
|
|
||||||
ws_path = Some(unwrap(String::from_str(path)).await);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if is_ws {
|
||||||
if let Some(path) = ws_path {
|
let mut buf = buf.into_bytes();
|
||||||
app.handle_ws(&path, Ws::new(&mut socket, &mut buf, app.socket_name()))
|
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;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user