ttt backend api kinda works
This commit is contained in:
parent
3782686d4b
commit
5a9ac5c436
@ -1,3 +1,6 @@
|
||||
use heapless::Vec;
|
||||
use pico_website::unwrap;
|
||||
|
||||
use crate::{
|
||||
apps::Content,
|
||||
socket::{HttpRequestType, HttpResCode},
|
||||
@ -22,17 +25,50 @@ impl App for IndexApp {
|
||||
"html",
|
||||
Some(include_str!("./index.html").into()),
|
||||
),
|
||||
"/ttt" => (
|
||||
HttpResCode::Ok,
|
||||
"html",
|
||||
Some(include_str!("ttt.html").into()),
|
||||
),
|
||||
"/ttt.js" => (
|
||||
HttpResCode::Ok,
|
||||
"javascript",
|
||||
Some(include_str!("ttt.js").into()),
|
||||
),
|
||||
_ => (HttpResCode::NotFound, "", None),
|
||||
path => {
|
||||
let (path, args) = path.split_once('?').unwrap_or((path, ""));
|
||||
let mut team = None;
|
||||
for arg in args.split('&') {
|
||||
match arg.split_once('=') {
|
||||
Some(("team", "0")) => team = Some("0"),
|
||||
Some(("team", "1")) => team = Some("1"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if path == "/ttt" {
|
||||
let Some(team) = team else {
|
||||
return (HttpResCode::BadRequest, "", None);
|
||||
};
|
||||
let html = include_str!("ttt.html");
|
||||
let mut content = Vec::new();
|
||||
let r: Result<(), &str> = try {
|
||||
let (html1, html2) = html.split_once("/ttt.js").ok_or("")?;
|
||||
|
||||
content.push(html1)?;
|
||||
content.push("/ttt.js?team=")?;
|
||||
content.push(team)?;
|
||||
content.push(html2)?;
|
||||
};
|
||||
unwrap(r).await;
|
||||
(HttpResCode::Ok, "html", Some(Content(content)))
|
||||
} else if path == "/ttt.js" {
|
||||
let Some(team) = team else {
|
||||
return (HttpResCode::BadRequest, "", None);
|
||||
};
|
||||
|
||||
let mut content = Vec::new();
|
||||
let r: Result<(), &str> = try {
|
||||
content.push("const team = ")?;
|
||||
content.push(team)?;
|
||||
content.push(";\n")?;
|
||||
content.push(include_str!("ttt.js"))?;
|
||||
};
|
||||
unwrap(r).await;
|
||||
(HttpResCode::Ok, "javascript", Some(Content(content)))
|
||||
} else {
|
||||
(HttpResCode::NotFound, "", None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
<h3 id="team"></h3>
|
||||
<!-- <div class="cell" style="background-color:"></div> -->
|
||||
<div id="grid">
|
||||
<div class="cell" id="cell0"></div>
|
||||
<!-- <div class="cell" id="cell0"></div>
|
||||
<div class="cell" id="cell1"></div>
|
||||
<div class="cell" id="cell2"></div>
|
||||
<div class="cell" id="cell3"></div>
|
||||
@ -38,7 +38,7 @@
|
||||
<div class="cell" id="cell6"></div>
|
||||
<div class="cell" id="cell7"></div>
|
||||
<div class="cell" id="cell8"></div>
|
||||
<div class="cell" id="cell9"></div>
|
||||
<div class="cell" id="cell9"></div> -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,12 +1,22 @@
|
||||
const team = 0;
|
||||
const teamName = "blue";
|
||||
const color = "dodgerblue";
|
||||
const otherColor = "firebrick";
|
||||
//const team = 0;
|
||||
if (team != 0 && team != 1) {
|
||||
throw "team is not 0 or 1! team=" + team;
|
||||
}
|
||||
let teamName = "blue";
|
||||
let color = "dodgerblue";
|
||||
let otherColor = "firebrick";
|
||||
let port = "8080";
|
||||
if (team === 1) {
|
||||
teamName = "red";
|
||||
color = "firebrick";
|
||||
otherColor = "dodgerblue";
|
||||
port = "8081";
|
||||
}
|
||||
|
||||
document.getElementById("team").innerHTML =
|
||||
'Team : <span style="color:' + color + '">' + teamName + "</span>";
|
||||
|
||||
const ws = new WebSocket("ws://192.254.0.2:8080/" + teamName);
|
||||
const ws = new WebSocket("ws://192.254.0.2:" + port + "/" + teamName);
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
console.log(event.data);
|
||||
|
168
src/apps/ttt.rs
168
src/apps/ttt.rs
@ -1,10 +1,11 @@
|
||||
use core::fmt::Write;
|
||||
use core::str::from_utf8_unchecked;
|
||||
use core::{ops::Not, sync::atomic::Ordering};
|
||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
use embassy_sync::mutex::Mutex;
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use heapless::{String, Vec};
|
||||
use log::info;
|
||||
use pico_website::unwrap;
|
||||
use portable_atomic::{AtomicBool, AtomicU32};
|
||||
use log::{info, warn};
|
||||
use pico_website::{unwrap, unwrap_opt};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::apps::Content;
|
||||
@ -13,61 +14,75 @@ use crate::socket::{HttpRequestType, HttpResCode};
|
||||
|
||||
use super::App;
|
||||
|
||||
static TURN: AtomicBool = AtomicBool::new(false);
|
||||
// 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
|
||||
static BOARD: AtomicU32 = AtomicU32::new(0b01000000_001000000);
|
||||
|
||||
#[derive(Debug, Serialize, Clone, PartialEq, Eq, Default)]
|
||||
struct Game {
|
||||
board: [Option<Team>; 9],
|
||||
turn: Option<Team>,
|
||||
winner: Option<Team>,
|
||||
}
|
||||
static GAME: Mutex<ThreadModeRawMutex, Game> = Mutex::new(Game {
|
||||
board: [None; 9],
|
||||
turn: Some(Team::Zero),
|
||||
winner: None,
|
||||
});
|
||||
|
||||
// {"board"=[null,null,null,null,null,null,null,null,null],"turn"=null,"winner":null}
|
||||
|
||||
pub struct TttApp {
|
||||
team: Team,
|
||||
last_board: u32,
|
||||
last_game: Game,
|
||||
end: Option<(Instant, Option<Team>)>,
|
||||
json_buf: [u8; 128],
|
||||
}
|
||||
impl TttApp {
|
||||
pub fn new(team: Team) -> Self {
|
||||
Self {
|
||||
team,
|
||||
last_board: 0,
|
||||
last_game: Game::default(),
|
||||
end: None,
|
||||
json_buf: [0; 128],
|
||||
}
|
||||
}
|
||||
pub fn is_ended(&self, board: u32) -> (bool, Option<Team>) {
|
||||
if let Some((_, t)) = self.end {
|
||||
return (true, t);
|
||||
}
|
||||
for (t, m) in [(Team::Zero, 0), (Team::One, 9)] {
|
||||
for w in [
|
||||
0b111000000,
|
||||
0b000111000,
|
||||
0b000000111,
|
||||
0b100100100,
|
||||
0b010010010,
|
||||
0b001001001,
|
||||
0b100010001,
|
||||
0b001010100,
|
||||
] {
|
||||
if board & (w << m) == (w << m) {
|
||||
return (true, Some(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((board | (board >> 9)) & 0b111111111) == 0b111111111 {
|
||||
return (true, None);
|
||||
}
|
||||
(false, None)
|
||||
}
|
||||
pub fn update_end_state(&mut self, board: &mut u32) {
|
||||
if let Some((i, _)) = self.end {
|
||||
if i + Duration::from_secs(7) < Instant::now() {
|
||||
self.end = None;
|
||||
BOARD.store(0, Ordering::Release);
|
||||
*board = 0;
|
||||
}
|
||||
} else {
|
||||
if let (true, t) = self.is_ended(*board) {
|
||||
self.end = Some((Instant::now(), t));
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub fn is_ended(&self, board: u32) -> (bool, Option<Team>) {
|
||||
// if let Some((_, t)) = self.end {
|
||||
// return (true, t);
|
||||
// }
|
||||
// for (t, m) in [(Team::Zero, 0), (Team::One, 9)] {
|
||||
// for w in [
|
||||
// 0b111000000,
|
||||
// 0b000111000,
|
||||
// 0b000000111,
|
||||
// 0b100100100,
|
||||
// 0b010010010,
|
||||
// 0b001001001,
|
||||
// 0b100010001,
|
||||
// 0b001010100,
|
||||
// ] {
|
||||
// if board & (w << m) == (w << m) {
|
||||
// return (true, Some(t));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if ((board | (board >> 9)) & 0b111111111) == 0b111111111 {
|
||||
// return (true, None);
|
||||
// }
|
||||
// (false, None)
|
||||
// }
|
||||
// pub fn update_end_state(&mut self, board: &mut u32) {
|
||||
// if let Some((i, _)) = self.end {
|
||||
// if i + Duration::from_secs(7) < Instant::now() {
|
||||
// self.end = None;
|
||||
// // BOARD.store(0, Ordering::Release);
|
||||
// *board = 0;
|
||||
// }
|
||||
// } else {
|
||||
// if let (true, t) = self.is_ended(*board) {
|
||||
// self.end = Some((Instant::now(), t));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl App for TttApp {
|
||||
@ -97,36 +112,59 @@ impl App for TttApp {
|
||||
_path: &str,
|
||||
mut ws: Ws<'a, BUF_SIZE, RES_HEAD_BUF_SIZE>,
|
||||
) {
|
||||
Timer::after_millis(500).await;
|
||||
let r: Result<(), ()> = try {
|
||||
loop {
|
||||
let board = BOARD.load(Ordering::Acquire);
|
||||
ws.send(WsMsg::Text(
|
||||
&serde_json_core::to_string::<_, 40>(&ServerMsg {
|
||||
board,
|
||||
turn: Some(Team::Zero),
|
||||
winner: None,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.await?;
|
||||
Timer::after_millis(1).await;
|
||||
let Ok(mut game) = GAME.try_lock() else {
|
||||
info!("locked");
|
||||
continue;
|
||||
};
|
||||
// match GAME.try_lock() ;
|
||||
if self.last_game != *game {
|
||||
// let json = unwrap(serde_json_core::to_string::<Game, 128>(&game)).await;
|
||||
let n = unwrap(serde_json_core::to_slice(&(*game), &mut self.json_buf)).await;
|
||||
let json =
|
||||
unsafe { from_utf8_unchecked(&unwrap_opt(self.json_buf.get(..n)).await) };
|
||||
info!("{:?}", json);
|
||||
ws.send(WsMsg::Text(json)).await?;
|
||||
self.last_game = game.clone();
|
||||
}
|
||||
if ws.last_msg.elapsed() >= Duration::from_secs(5) {
|
||||
ws.send(WsMsg::Ping(&[])).await?;
|
||||
info!("ping");
|
||||
}
|
||||
while let Some(r) = ws.rcv().await? {
|
||||
info!("{:?}", r);
|
||||
if let WsMsg::Bytes([c]) = r {
|
||||
let c = *c;
|
||||
info!("c={}", c);
|
||||
if c > 8 {}
|
||||
match game.board.get_mut(c as usize) {
|
||||
None => {
|
||||
warn!("Cell played is too big!");
|
||||
return;
|
||||
}
|
||||
Some(Some(_)) => {
|
||||
warn!("Cell is already taken!");
|
||||
return;
|
||||
}
|
||||
Some(cell) => {
|
||||
*cell = Some(self.team);
|
||||
}
|
||||
}
|
||||
info!("{:#?}", game);
|
||||
}
|
||||
}
|
||||
|
||||
Timer::after_secs(1).await;
|
||||
// Timer::after_secs(1).await;
|
||||
}
|
||||
};
|
||||
info!("{:?}", r);
|
||||
warn!("error: {:?}", r);
|
||||
Timer::after_micros(100).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ServerMsg {
|
||||
board: u32,
|
||||
turn: Option<Team>,
|
||||
winner: Option<Team>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Team {
|
||||
Zero = 0,
|
||||
|
@ -11,7 +11,7 @@ use embassy_net::{
|
||||
use embassy_time::Timer;
|
||||
use heapless::Vec;
|
||||
use log::{info, warn};
|
||||
use pico_website::unwrap;
|
||||
use pico_website::{unwrap, unwrap_opt};
|
||||
|
||||
#[embassy_executor::task(pool_size = 1)]
|
||||
pub async fn dhcp_server(stack: Stack<'static>) {
|
||||
@ -38,7 +38,8 @@ pub async fn dhcp_server(stack: Stack<'static>) {
|
||||
loop {
|
||||
let (n, _) = unwrap(socket.recv_from(&mut buf).await).await;
|
||||
|
||||
let msg = unwrap(dhcpv4::Message::new(&buf[..n])).await;
|
||||
let msg = unwrap_opt(buf.get(..n)).await;
|
||||
let msg = unwrap(dhcpv4::Message::new(&msg)).await;
|
||||
|
||||
let msg_type = unwrap(v4_options!(msg; MessageType required)).await;
|
||||
let mut rapid_commit = false;
|
||||
|
@ -5,7 +5,7 @@ use embassy_net::{
|
||||
};
|
||||
use embassy_time::Timer;
|
||||
use log::{info, warn};
|
||||
use pico_website::unwrap;
|
||||
use pico_website::{unwrap, unwrap_opt};
|
||||
|
||||
#[embassy_executor::task(pool_size = 1)]
|
||||
pub async fn dns_server(stack: Stack<'static>) {
|
||||
@ -30,7 +30,8 @@ pub async fn dns_server(stack: Stack<'static>) {
|
||||
Timer::after_secs(0).await;
|
||||
let (n, meta) = unwrap(socket.recv_from(&mut buf).await).await;
|
||||
|
||||
let msg = match dnsparse::Message::parse(&mut buf[..n]) {
|
||||
let msg = unwrap_opt(buf.get_mut(..n)).await;
|
||||
let msg = match dnsparse::Message::parse(msg) {
|
||||
Ok(msg) => msg,
|
||||
Err(e) => {
|
||||
warn!("Dns: Error while parsing DNS message : {:#?}", e);
|
||||
|
19
src/lib.rs
19
src/lib.rs
@ -1,6 +1,6 @@
|
||||
#![no_std]
|
||||
|
||||
use core::fmt::Debug;
|
||||
use core::{fmt::Debug, panic::PanicInfo};
|
||||
use embassy_time::Timer;
|
||||
use log::info;
|
||||
|
||||
@ -13,3 +13,20 @@ pub async fn unwrap<T, E: Debug>(res: Result<T, E>) -> T {
|
||||
},
|
||||
}
|
||||
}
|
||||
pub async fn unwrap_opt<T>(opt: Option<T>) -> T {
|
||||
unwrap(opt.ok_or(())).await
|
||||
}
|
||||
|
||||
pub async fn assert(condition: bool) {
|
||||
if !condition {
|
||||
let err: Result<(), &str> = Err("assert failed");
|
||||
unwrap(err).await;
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't work
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
info!("PANIC: {}", info);
|
||||
loop {}
|
||||
}
|
||||
|
15
src/main.rs
15
src/main.rs
@ -1,6 +1,12 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![allow(async_fn_in_trait)]
|
||||
#![deny(
|
||||
// clippy::unwrap_used,
|
||||
// clippy::expect_used,
|
||||
clippy::panic,
|
||||
clippy::indexing_slicing
|
||||
)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(slice_split_once)]
|
||||
#![feature(try_blocks)]
|
||||
@ -10,6 +16,8 @@
|
||||
use core::net::Ipv4Addr;
|
||||
|
||||
use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi};
|
||||
use defmt::warn;
|
||||
use defmt_rtt as _;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::{Config, StackResources};
|
||||
use embassy_rp::bind_interrupts;
|
||||
@ -23,7 +31,6 @@ use log::info;
|
||||
use pico_website::unwrap;
|
||||
use rand_core::RngCore;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[cfg(feature = "dhcp")]
|
||||
mod dhcp;
|
||||
@ -175,6 +182,12 @@ async fn main(spawner: Spawner) {
|
||||
.address
|
||||
)
|
||||
}
|
||||
// embassy_time::Timer::after_secs(5).await;
|
||||
// info!("test0");
|
||||
|
||||
// embassy_time::Timer::after_secs(3).await;
|
||||
|
||||
// panic!("test");
|
||||
|
||||
#[cfg(feature = "dhcp")]
|
||||
unwrap(spawner.spawn(dhcp::dhcp_server(stack))).await;
|
||||
|
@ -6,6 +6,7 @@ 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 sha1::{Digest, Sha1};
|
||||
|
||||
use crate::apps::Content;
|
||||
@ -71,7 +72,8 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
}
|
||||
};
|
||||
head_buf.clear();
|
||||
let (headers, content) = match from_utf8(&buf[..n]) {
|
||||
let msg = unwrap_opt(buf.get(..n)).await;
|
||||
let (headers, content) = match from_utf8(msg) {
|
||||
Ok(b) => match b.split_once("\r\n\r\n") {
|
||||
Some(t) => t,
|
||||
None => (b, ""),
|
||||
@ -82,7 +84,8 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
}
|
||||
};
|
||||
|
||||
info!("\n{:?}\n", headers);
|
||||
// info!("\n{:?}\n", headers);
|
||||
// Timer::after_micros(100).await;
|
||||
|
||||
let mut hl = headers.lines();
|
||||
let (request_type, path) = match hl.next() {
|
||||
@ -144,12 +147,13 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
host,
|
||||
path,
|
||||
);
|
||||
Timer::after_secs(0).await;
|
||||
Timer::after_micros(100).await;
|
||||
|
||||
head_buf.clear();
|
||||
let res_content: Result<Option<Content>, core::fmt::Error> = try {
|
||||
if ws_handshake {
|
||||
if !app.accept_ws(path) {
|
||||
warn!("No ws there!");
|
||||
write!(
|
||||
&mut head_buf,
|
||||
"{}\r\n\r\n",
|
||||
@ -206,7 +210,7 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
Content-Length: {}\r\n",
|
||||
res_type,
|
||||
c.len()
|
||||
)?
|
||||
)?;
|
||||
}
|
||||
write!(&mut head_buf, "\r\n\r\n")?;
|
||||
res_content
|
||||
@ -221,7 +225,8 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
}
|
||||
};
|
||||
|
||||
info!("\n{}\n", from_utf8(&head_buf).unwrap());
|
||||
info!("\n{}\n", unwrap(from_utf8(&head_buf)).await);
|
||||
Timer::after_micros(1000).await;
|
||||
|
||||
let w: Result<(), embassy_net::tcp::Error> = try {
|
||||
socket.write_all(&head_buf).await?;
|
||||
@ -229,7 +234,6 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
for s in c.0.iter() {
|
||||
socket.write_all(s.as_bytes()).await?;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
};
|
||||
|
||||
@ -239,11 +243,13 @@ pub async fn listen_task(stack: embassy_net::Stack<'static>, mut app: impl apps:
|
||||
};
|
||||
|
||||
if ws_handshake {
|
||||
ws_path = Some(String::from_str(path).unwrap());
|
||||
ws_path = Some(unwrap(String::from_str(path)).await);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(path) = ws_path {
|
||||
info!("handle ws");
|
||||
Timer::after_micros(200).await;
|
||||
app.handle_ws(
|
||||
&path,
|
||||
Ws::new(&mut socket, &mut buf, &mut head_buf, app.socket_name()),
|
||||
@ -291,11 +297,12 @@ impl Into<&str> for HttpResCode {
|
||||
|
||||
async fn compute_ws_accept(key: &str) -> Result<String<28>, EncodeSliceError> {
|
||||
let mut res = Vec::<u8, 28>::new();
|
||||
Timer::after_micros(10).await;
|
||||
res.extend_from_slice(&[0; 28]).unwrap();
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(key.as_bytes());
|
||||
hasher.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
let hash = hasher.finalize();
|
||||
BASE64_STANDARD.encode_slice(hash, &mut res)?;
|
||||
Ok(String::from_utf8(res).unwrap())
|
||||
Ok(unwrap(String::from_utf8(res)).await)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use embassy_time::{Instant, Timer};
|
||||
use embedded_io_async::{ErrorType, ReadReady, Write};
|
||||
use heapless::Vec;
|
||||
use log::{info, warn};
|
||||
use pico_website::{assert, unwrap, unwrap_opt};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum WsMsg<'a> {
|
||||
@ -38,7 +39,6 @@ impl WsMsg<'_> {
|
||||
struct WsRx<'a, const BUF_SIZE: usize> {
|
||||
socket: TcpReader<'a>,
|
||||
buf: &'a mut [u8; BUF_SIZE],
|
||||
last_msg: Instant,
|
||||
msg_in_buf: Option<(usize, usize)>, // (start, length)
|
||||
}
|
||||
struct WsTx<'a, const HEAD_BUF_SIZE: usize> {
|
||||
@ -48,15 +48,17 @@ struct WsTx<'a, const HEAD_BUF_SIZE: usize> {
|
||||
impl<'a, const HEAD_BUF_SIZE: usize> WsTx<'a, HEAD_BUF_SIZE> {
|
||||
pub async fn send<'m>(&mut self, msg: WsMsg<'m>) -> Result<(), ()> {
|
||||
self.head_buf.clear();
|
||||
self.head_buf.push(0b1000_0000 | msg.code()).unwrap();
|
||||
unwrap(self.head_buf.push(0b1000_0000 | msg.code())).await;
|
||||
if msg.len() < 126 {
|
||||
self.head_buf.push(msg.len() as u8).unwrap();
|
||||
unwrap(self.head_buf.push(msg.len() as u8)).await;
|
||||
} else {
|
||||
self.head_buf.push(0b0111_1110).unwrap();
|
||||
unwrap(self.head_buf.push(0b0111_1110)).await;
|
||||
unwrap(
|
||||
self.head_buf
|
||||
.extend_from_slice(&(msg.len() as u16).to_le_bytes())
|
||||
.unwrap();
|
||||
self.head_buf.extend_from_slice(msg.as_bytes()).unwrap();
|
||||
.extend_from_slice(&(msg.len() as u16).to_le_bytes()),
|
||||
)
|
||||
.await;
|
||||
// self.head_buf.extend_from_slice(msg.as_bytes()).unwrap();
|
||||
}
|
||||
let w: Result<(), <TcpSocket<'_> as ErrorType>::Error> = try {
|
||||
self.socket.write_all(&self.head_buf).await?;
|
||||
@ -72,6 +74,7 @@ impl<'a, const HEAD_BUF_SIZE: usize> WsTx<'a, HEAD_BUF_SIZE> {
|
||||
pub struct Ws<'a, const BUF_SIZE: usize = 1024, const RES_HEAD_BUF_SIZE: usize = 256> {
|
||||
rx: WsRx<'a, BUF_SIZE>,
|
||||
tx: WsTx<'a, RES_HEAD_BUF_SIZE>,
|
||||
pub last_msg: Instant,
|
||||
name: &'a str,
|
||||
}
|
||||
impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEAD_BUF_SIZE> {
|
||||
@ -86,13 +89,13 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
rx: WsRx {
|
||||
socket: rx,
|
||||
buf,
|
||||
last_msg: Instant::MIN,
|
||||
msg_in_buf: None,
|
||||
},
|
||||
tx: WsTx {
|
||||
socket: tx,
|
||||
head_buf,
|
||||
},
|
||||
last_msg: Instant::MIN,
|
||||
name,
|
||||
}
|
||||
}
|
||||
@ -100,8 +103,9 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
pub async fn rcv(&mut self) -> Result<Option<WsMsg>, ()> {
|
||||
let n = match self.rx.msg_in_buf.take() {
|
||||
Some(n) => {
|
||||
assert(n.0 + n.1 <= self.rx.buf.len()).await;
|
||||
self.rx.buf.copy_within(n.0..n.0 + n.1, 0);
|
||||
if self.rx.socket.read_ready().unwrap() {
|
||||
if unwrap(self.rx.socket.read_ready()).await {
|
||||
let n_rcv = match self.rx.socket.read(&mut self.rx.buf[n.1..]).await {
|
||||
Ok(0) => {
|
||||
info!("read EOF");
|
||||
@ -119,7 +123,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if self.rx.socket.read_ready().unwrap() {
|
||||
if unwrap(self.rx.socket.read_ready()).await {
|
||||
match self.rx.socket.read(self.rx.buf).await {
|
||||
Ok(0) => {
|
||||
info!("read EOF");
|
||||
@ -177,7 +181,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
{
|
||||
*x ^= mask_key[i & 0xff];
|
||||
*x ^= unwrap_opt(mask_key.get(i & 0xff)).await;
|
||||
}
|
||||
if n_after_length + 4 + (length as usize) < n {
|
||||
self.rx.msg_in_buf = Some((
|
||||
@ -199,7 +203,7 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
}
|
||||
&self.rx.buf[n_after_length..n_after_length + length as usize]
|
||||
};
|
||||
self.rx.last_msg = Instant::now();
|
||||
self.last_msg = Instant::now();
|
||||
match self.rx.buf[0] & 0b0000_1111 {
|
||||
// Text message
|
||||
1 => {
|
||||
@ -222,6 +226,8 @@ impl<'a, const BUF_SIZE: usize, const HEAD_BUF_SIZE: usize> Ws<'a, BUF_SIZE, HEA
|
||||
}
|
||||
}
|
||||
pub async fn send(&mut self, msg: WsMsg<'_>) -> Result<(), ()> {
|
||||
self.tx.send(msg).await
|
||||
self.tx.send(msg).await?;
|
||||
self.last_msg = Instant::now();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user