summaryrefslogtreecommitdiff
path: root/src/room/handle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/room/handle.rs')
-rw-r--r--src/room/handle.rs106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/room/handle.rs b/src/room/handle.rs
new file mode 100644
index 0000000..d397c70
--- /dev/null
+++ b/src/room/handle.rs
@@ -0,0 +1,106 @@
+use std::collections::HashSet;
+
+use super::messages::{ClientMessage, ServerMessage};
+
+// send a ServerMessage::Connections to all sockets
+pub async fn send_connections(v: &mut super::Clients, added: Option<usize>, removed: Option<usize>, frame: u64) {
+ // get the list of connection IDs
+ let connections: Vec<usize> = v.iter()
+ .enumerate()
+ .filter(|(_, n)| n.is_some())
+ .map(|(id, _)| id)
+ .collect();
+
+ super::send(v, |id, _c| {
+ Some(ServerMessage::Connections {
+ connections: connections.clone(),
+ added,
+ removed,
+ id,
+ frame,
+ })
+ }).await;
+}
+
+// handle incoming websocket messages
+pub async fn handle(
+ v: &mut super::Clients,
+ requests: &mut HashSet<(u64, Option<usize>, usize)>, // frame, connection, client id
+ pending: &mut Vec<(Option<usize>, Option<usize>)>,
+ id: usize,
+ msg: ClientMessage,
+) {
+ match msg {
+ // broadcast inputs to every other connection
+ ClientMessage::Input { data, frame } => {
+ super::broadcast(v, ServerMessage::Input {
+ data,
+ frame,
+ connection: id
+ }, Some(id)).await;
+ },
+ // a client needs the current game state, grab it from another client
+ ClientMessage::RequestState { frame, connection } => {
+ let count = super::conn_count(v);
+
+ if count < 2 { // nobody to request state *from*
+ if let Some(Some(client)) = v.get(id) {
+ client.send(ServerMessage::State {
+ state: serde_json::Value::Null,
+ frame: 0,
+ connection: None,
+ }).await.ok();
+ }
+ return;
+ }
+
+ // request state from other clients
+ requests.insert((frame, connection, id));
+
+ match connection {
+ None => {
+ super::broadcast(v, ServerMessage::RequestState { frame }, Some(id)).await;
+ },
+ Some(id) => { // it's to a specific connection
+ let Some(Some(client)) = v.get(id) else {
+ return;
+ };
+ client.send(ServerMessage::RequestState { frame }).await.ok();
+ },
+ }
+ },
+ // a client responded to a request for game state, tell all the requestees
+ ClientMessage::State { state, frame } => {
+ let mut new_requests = HashSet::new();
+ for (fr, conn, cid) in requests.drain() {
+ if
+ fr != frame || // this isn't the requested frame
+ (conn.is_some() && Some(id) != conn) // this isn't the requested connection
+ {
+ new_requests.insert((fr, conn, cid));
+ continue;
+ }
+ if let Some(Some(client)) = v.get(cid) {
+ client.send(ServerMessage::State {
+ state: state.clone(),
+ frame,
+ connection: Some(id),
+ }).await.ok();
+ }
+ }
+ *requests = new_requests;
+ },
+ // a client said what frame they're on, actually send the connections message
+ ClientMessage::Frame { frame } => {
+ for (added, removed) in pending.into_iter() {
+ send_connections(v, *added, *removed, frame).await;
+ }
+ *pending = Vec::new();
+ },
+ ClientMessage::Ping { frame } => {
+ if let Some(Some(client)) = v.get(id) {
+ client.send(ServerMessage::Pong { frame }).await.ok();
+ }
+ }
+ }
+}