feat: remove the need for constant polling data

This commit is contained in:
2026-03-27 13:08:20 -04:00
Unverified
parent 73e435d5ec
commit 4e131fac31
4 changed files with 124 additions and 15 deletions

View File

@@ -326,6 +326,8 @@ async fn handle_connection(
sd.clients.write().await.remove(&username);
sd.usernames.write().await.remove(&addr);
sd.broadcast(&format!("DISCONNECT:{}", username)).await;
break;
}
}

View File

@@ -44,14 +44,21 @@ impl Server {
) -> Result<(), anyhow::Error> {
if requested_username.is_empty() {
return Err(anyhow::anyhow!(format!(
"ERROR:INVALID:ID:{}",
"ERROR:INVALID:CONNECT:{}",
requested_username
)));
}
if requested_username.chars().any(|c| matches!(c, ':' | ',' | '|') || c.is_control()) {
return Err(anyhow::anyhow!(format!(
"ERROR:INVALID:CONNECT:{}",
requested_username
)));
}
if requested_username == SERVER_PLAYER_USERNAME {
return Err(anyhow::anyhow!(format!(
"ERROR:INVALID:ID:{}",
"ERROR:INVALID:CONNECT:{}",
requested_username
)));
}
@@ -66,7 +73,7 @@ impl Server {
let existing_client = clients_guard.get(&requested_username).cloned();
if existing_client.is_some() && !reconnecting {
return Err(anyhow::anyhow!(format!(
"ERROR:INVALID:ID:{}",
"ERROR:INVALID:CONNECT:{}",
requested_username
)));
}
@@ -81,12 +88,14 @@ impl Server {
self.clients.write().await.insert(
requested_username.clone(),
Arc::new(RwLock::new(Client::new(
requested_username,
requested_username.clone(),
tx.clone(),
addr.to_string().parse()?,
))),
);
self.broadcast(&format!("CONNECT:{}", requested_username)).await;
return Ok(());
}
@@ -217,6 +226,7 @@ impl Server {
self.clients.write().await.remove(&username);
self.usernames.write().await.remove(&addr);
let _ = send(&tx, "DISCONNECT:ACK");
self.broadcast(&format!("DISCONNECT:{}", username)).await;
Ok(())
}
@@ -264,6 +274,7 @@ impl Server {
let _ = send(&tx, "READY:ACK");
drop(client);
drop(clients_guard);
self.broadcast(&format!("READY:{}:{}", username, true)).await;
if let Some(opponent_username) = self.find_reservation_opponent(&username).await {
let clients_guard = self.clients.read().await;
@@ -278,6 +289,14 @@ impl Server {
false,
)));
self.matches.write().await.insert(match_id, new_match.clone());
let match_guard = new_match.read().await;
self
.broadcast(&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
))
.await;
drop(match_guard);
client.ready = false;
client.current_match = Some(match_id);
@@ -294,6 +313,7 @@ impl Server {
opponent.ready = false;
opponent.current_match = Some(match_id);
opponent.color = !client.color;
let opponent_username = opponent.username.clone();
self
.reservations
@@ -301,6 +321,12 @@ impl Server {
.await
.retain(|(p1, p2)| !(p1 == &client.username && p2 == &opponent.username));
drop(opponent);
drop(client);
drop(clients_guard);
self.broadcast(&format!("READY:{}:{}", username, false)).await;
self.broadcast(&format!("READY:{}:{}", opponent_username, false)).await;
return Ok(());
}
@@ -316,6 +342,15 @@ impl Server {
is_demo_mode,
)));
self.matches.write().await.insert(match_id, new_match.clone());
let match_guard = new_match.read().await;
self
.broadcast(&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
))
.await;
drop(match_guard);
client.ready = false;
client.current_match = Some(match_id);
client.color = if new_match.read().await.player1 == username {
@@ -355,6 +390,9 @@ impl Server {
}
}));
}
drop(client);
self.broadcast(&format!("READY:{}:{}", username, false)).await;
}
Ok(())
@@ -1202,8 +1240,17 @@ impl Server {
false,
)));
self.matches.write().await.insert(match_id, new_match.clone());
let match_guard = new_match.read().await;
self
.broadcast(&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
))
.await;
drop(match_guard);
player1.ready = false;
let player1_name = player1.username.clone();
player1.current_match = Some(match_id);
player1.color = if new_match.read().await.player1 == player1_username {
let _ = send(&tx, "GAME:START:1");
@@ -1216,6 +1263,7 @@ impl Server {
};
player2.ready = false;
let player2_name = player2.username.clone();
player2.current_match = Some(match_id);
player2.color = !player1.color;
@@ -1224,6 +1272,12 @@ impl Server {
.write()
.await
.retain(|(p1, p2)| !(p1 == &player1_username && p2 == &player2_username));
drop(player2);
drop(player1);
drop(clients_guard);
self.broadcast(&format!("READY:{}:{}", player1_name, false)).await;
self.broadcast(&format!("READY:{}:{}", player2_name, false)).await;
}
}

View File

@@ -19,6 +19,7 @@ pub struct KnockoutBracket {
pub started: bool,
pub clients: Clients,
pub matches: Matches,
pub observers: Observers,
pub usernames: Vec<String>,
}
@@ -39,12 +40,16 @@ impl KnockoutBracket {
player2_username.clone(),
false,
)));
let match_guard = new_match.read().await;
let mut player1 = clients_guard.get(&player1_username).unwrap().write().await;
let mut player1 = clients_guard.get(&player1_username).unwrap().write().await;
player1.current_match = Some(match_id);
player1.ready = false;
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player1.username.clone(), false),
)
.await;
if match_guard.player1 == player1_username {
player1.color = Color::Red;
@@ -53,13 +58,16 @@ impl KnockoutBracket {
player1.color = Color::Yellow;
let _ = send(&player1.connection, "GAME:START:0");
}
drop(player1);
let mut player2 = clients_guard.get(&player2_username).unwrap().write().await;
player2.current_match = Some(match_id);
player2.ready = false;
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player2.username.clone(), false),
)
.await;
if match_guard.player1 == player2_username {
player2.color = Color::Red;
@@ -68,10 +76,17 @@ impl KnockoutBracket {
player2.color = Color::Yellow;
let _ = send(&player2.connection, "GAME:START:0");
}
drop(player2);
self.matches.write().await.insert(match_id, new_match.clone());
broadcast_message(
&self.observers,
&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
),
)
.await;
i += 2
}
@@ -95,6 +110,7 @@ impl Tournament for KnockoutBracket {
started: false,
clients: server.clients.clone(),
matches: server.matches.clone(),
observers: server.observers.clone(),
usernames: ready_players.to_vec(),
}
}
@@ -219,6 +235,7 @@ impl Tournament for KnockoutBracket {
player1.current_match = Some(match_id);
player1.ready = false;
let player1_name = player1.username.clone();
if match_guard.player1 == player1.username {
player1.color = Color::Red;
@@ -234,6 +251,7 @@ impl Tournament for KnockoutBracket {
player2.current_match = Some(match_id);
player2.ready = false;
let player2_name = player2.username.clone();
if match_guard.player1 == player2.username {
player2.color = Color::Red;
@@ -245,8 +263,27 @@ impl Tournament for KnockoutBracket {
drop(player2);
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player1_name, false),
)
.await;
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player2_name, false),
)
.await;
self.current_matches.push(match_id);
self.matches.write().await.insert(match_id, new_match.clone());
broadcast_message(
&self.observers,
&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
),
)
.await;
}
let mut loser = String::new();

View File

@@ -16,6 +16,7 @@ pub struct RoundRobin {
pub completed: bool,
pub current_matches: Vec<ID>,
pub usernames: Vec<String>,
pub observers: Observers,
}
impl RoundRobin {
@@ -39,12 +40,16 @@ impl RoundRobin {
)));
self.current_matches.push(match_id.clone());
let match_guard = new_match.read().await;
let mut player1 = clients_guard.get(&player1_username.0).unwrap().write().await;
player1.current_match = Some(match_id);
player1.ready = false;
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player1.username.clone(), false),
)
.await;
if match_guard.player1 == player1_username.0 {
player1.color = Color::Red;
@@ -53,13 +58,16 @@ impl RoundRobin {
player1.color = Color::Yellow;
let _ = send(&player1.connection, "GAME:START:0");
}
drop(player1);
let mut player2 = clients_guard.get(&player2_addr.0).unwrap().write().await;
player2.current_match = Some(match_id);
player2.ready = false;
broadcast_message(
&self.observers,
&format!("READY:{}:{}", player2.username.clone(), false),
)
.await;
if match_guard.player1 == player2_addr.0 {
player2.color = Color::Red;
@@ -68,17 +76,24 @@ impl RoundRobin {
player2.color = Color::Yellow;
let _ = send(&player2.connection, "GAME:START:0");
}
drop(player2);
matches.write().await.insert(match_id, new_match.clone());
broadcast_message(
&self.observers,
&format!(
"GAME:START:{},{},{}",
match_id, match_guard.player1, match_guard.player2
),
)
.await;
}
}
}
#[async_trait]
impl Tournament for RoundRobin {
async fn new(ready_players: &[String], _: &Server) -> RoundRobin {
async fn new(ready_players: &[String], server: &Server) -> RoundRobin {
let mut result = RoundRobin {
players: HashMap::new(),
top_half: Vec::new(),
@@ -86,6 +101,7 @@ impl Tournament for RoundRobin {
completed: false,
current_matches: Vec::new(),
usernames: ready_players.to_vec(),
observers: server.observers.clone(),
};
let size = ready_players.len();