From bcd5764aa03e128e06c355272b7b81eac8d4501d Mon Sep 17 00:00:00 2001
From: stale <redkugelblitzin@gmail.com>
Date: Sun, 29 May 2022 20:45:03 -0300
Subject: improved pubs listing, many minor fixes

---
 src/conn.rs        |  2 +-
 src/main.rs        | 40 +++++++++++++++++++++++++++++-----------
 src/minesweeper.rs |  4 +++-
 src/types.rs       | 15 ++++++++++-----
 4 files changed, 43 insertions(+), 18 deletions(-)

(limited to 'src')

diff --git a/src/conn.rs b/src/conn.rs
index 14777bf..d38b6ef 100644
--- a/src/conn.rs
+++ b/src/conn.rs
@@ -43,7 +43,7 @@ pub async fn lobby(socket: WebSocket, addr: SocketAddr, room: Arc<RwLock<Room>>)
                             let conn = Conn { addr, tx: tx.clone() };
                             room.write().await.players.insert_conn(conn, name.clone(), clr).await
                         };
-                        tx.send(Message::text(format!("regack {} {uid} {}", name.replace(" ", "&nbsp"), room.read().await.board_conf))).expect("couldn't send register ack");
+                        tx.send(Message::text(format!("regack {} {uid} {}", name.replace(" ", "&nbsp"), room.read().await.conf.board_conf))).expect("couldn't send register ack");
                         if let Err(e) = room.read().await.cmd_stream.send(MetaMove::Dump) {
                             println!("couldn't request game dump in behalf of {addr}: {e}");
                         }
diff --git a/src/main.rs b/src/main.rs
index 2f7d52c..3dd7f39 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,6 +14,7 @@ use types::*;
 use tokio::sync::RwLock;
 
 const FONT_FILE: &[u8] = include_bytes!("../assets/VT323-Regular.ttf");
+const AREA_LIMIT: usize = 150*150;
 
 fn main() -> Result<(), Box<dyn Error>> {
     let conf = Config {
@@ -32,7 +33,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 #[tokio::main]
 async fn tokio_main(conf: Config) -> Result<(), Box<dyn Error>> {
     let rooms: RoomMap = Arc::new(RwLock::new(HashMap::new()));
-    let public_rooms = Arc::new(RwLock::new(Vec::new()));
+    let public_rooms = Arc::new(RwLock::new(HashMap::new()));
     use warp::*;
 
     let index = path::end().and(fs::file(conf.index_pg.clone()));
@@ -44,8 +45,9 @@ async fn tokio_main(conf: Config) -> Result<(), Box<dyn Error>> {
         path!("rlist").and_then(move || {
             let pubs = pubs.clone();
             async move {
-            Ok::<_,std::convert::Infallible>(
-                reply::json(&pubs.read().await.as_slice())
+                let map = pubs.read().await;
+                Ok::<_,std::convert::Infallible>(
+                    reply::json(&*map)
             )
         }})
     };
@@ -67,26 +69,36 @@ async fn tokio_main(conf: Config) -> Result<(), Box<dyn Error>> {
                     rinfo.get("ralwayssafe1move"),
                     rinfo.get("rlimit").and_then(|l| l.parse::<usize>().ok()),
                     ) {
+                    if w.get()*h.get() > AREA_LIMIT {
+                        return Err(reject::custom(BoardTooBig))
+                    }
                     let board_conf = minesweeper::BoardConf { w, h, mine_ratio: (num,denom), always_safe_first_move: asfm.is_some() };
-                    let name = rinfo.get("rname").map(|r| r.to_owned()).unwrap_or(format!("{w}x{h} room"));
-
                     let mut rooms = rooms.write().await;
                     let uid = types::RoomId::new_in(&rooms);
+                    let name = {
+                        let n = rinfo.get("rname").map(|r| r.to_owned()).unwrap();
+                        if n.is_empty() { uid.to_string() } else { n }
+                    };
                     let players = PlayerMap::default();
                     let (cmd_tx, cmd_rx) = tokio::sync::mpsc::unbounded_channel();
                     let handle = tokio::spawn(gameloop(cmd_rx, players.clone(), board_conf));
-                    rooms.insert(uid.clone(), Arc::new(RwLock::new(Room {
+                    let room_conf = RoomConf {
                         name,
-                        players,
-                        peer_limit: match limit { Some(i) => i, None => usize::MAX },
+                        player_cap: match limit { Some(i) => i, None => usize::MAX },
                         public: access.is_some(),
+                        board_conf,
+                    };
+                    let new_room = Room {
+                        conf: room_conf,
+                        players,
                         driver: handle,
                         cmd_stream: cmd_tx,
-                        board_conf,
-                    })));
+                    };
                     if access.is_some() {
-                        pubs.write().await.push(uid.clone());
+                        pubs.write().await.insert(uid.clone(), serde_json::to_string(&new_room.conf).unwrap());
                     }
+                    rooms.insert(uid.clone(), Arc::new(RwLock::new(new_room)));
+
                     Ok(
                     hyper::Response::builder()
                        .status(hyper::StatusCode::SEE_OTHER)
@@ -205,10 +217,16 @@ use warp::{ reject::{ Reject, Rejection }, reply::{ self, Reply }, http::StatusC
 struct BadFormData;
 impl Reject for BadFormData {}
 
+#[derive(Debug)]
+struct BoardTooBig;
+impl Reject for BoardTooBig {}
+
 async fn error_handler(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
     if err.is_not_found() { Ok(reply::with_status("No such file", StatusCode::NOT_FOUND)) }
     else if let Some(_e) = err.find::<BadFormData>() {
         Ok(reply::with_status("Bad form data", StatusCode::BAD_REQUEST))
+    } else if let Some(_e) = err.find::<BoardTooBig>() {
+        Ok(reply::with_status("Board too big", StatusCode::BAD_REQUEST))
     } else {
         println!("unhandled rejection: {err:?}");
         Ok(reply::with_status("Server error", StatusCode::INTERNAL_SERVER_ERROR))
diff --git a/src/minesweeper.rs b/src/minesweeper.rs
index c81aa09..a494b94 100644
--- a/src/minesweeper.rs
+++ b/src/minesweeper.rs
@@ -3,6 +3,8 @@ use std::{
     num::NonZeroUsize,
 };
 use rand::{ thread_rng, Rng, distributions::Uniform };
+use serde::Serialize;
+
 const HIDDEN_BIT: u8 = 1 << 7;
 pub const FLAGGED_BIT: u8 = 1 << 6;
 const CORRECT_BIT: u8 = 1 << 5; // grading for a rightly flagged mine
@@ -29,7 +31,7 @@ pub struct Game {
     pub board_conf: BoardConf,
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, Serialize)]
 pub struct BoardConf {
     pub w: NonZeroUsize,
     pub h: NonZeroUsize,
diff --git a/src/types.rs b/src/types.rs
index 84e7d46..d467982 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -10,6 +10,7 @@ use std::{
 };
 use warp::ws::Message;
 use tokio::sync::RwLock;
+use serde::Serialize;
 use crate::minesweeper;
 
 #[derive(Debug, Clone)]
@@ -23,15 +24,19 @@ pub struct Config {
     pub socket_addr: SocketAddr,
 }
 
-#[derive(Debug)]
-pub struct Room {
+#[derive(Debug, Serialize)]
+pub struct RoomConf {
     pub name: String,
-    pub players: PlayerMap,
-    pub peer_limit: usize,
+    pub player_cap: usize,
     pub public: bool,
+    pub board_conf: minesweeper::BoardConf,
+}
+
+pub struct Room {
+    pub conf: RoomConf,
+    pub players: PlayerMap,
     pub driver: tokio::task::JoinHandle<()>,
     pub cmd_stream: CmdTx,
-    pub board_conf: minesweeper::BoardConf,
 }
 
 #[derive(Debug)]
-- 
cgit v1.2.3