Server action refactoring part 3 of N
authoralfadur <mail@none>
Mon, 04 Feb 2019 19:22:21 +0300
changeset 14693 6e6632068a33
parent 14692 455865ccd36c
child 14694 08a8605bafaf
Server action refactoring part 3 of N
rust/hedgewars-server/src/server/core.rs
rust/hedgewars-server/src/server/handlers.rs
rust/hedgewars-server/src/server/handlers/lobby.rs
rust/hedgewars-server/src/server/handlers/loggingin.rs
rust/hedgewars-server/src/server/network.rs
--- a/rust/hedgewars-server/src/server/core.rs	Sat Feb 02 15:06:39 2019 +0300
+++ b/rust/hedgewars-server/src/server/core.rs	Mon Feb 04 19:22:21 2019 +0300
@@ -93,38 +93,13 @@
         move_to_room(&mut self.clients[client_id], &mut self.rooms[room_id])
     }
 
-    fn get_recipients(&self, client_id: ClientId, destination: &Destination) -> Vec<ClientId> {
-        let mut ids = match *destination {
-            Destination::ToSelf => vec![client_id],
-            Destination::ToId(id) => vec![id],
-            Destination::ToAll {
-                room_id: Some(id), ..
-            } => self.room_clients(id),
-            Destination::ToAll {
-                protocol: Some(proto),
-                ..
-            } => self.protocol_clients(proto),
-            Destination::ToAll { .. } => self.clients.iter().map(|(id, _)| id).collect::<Vec<_>>(),
-        };
-        if let Destination::ToAll {
-            skip_self: true, ..
-        } = destination
-        {
-            if let Some(index) = ids.iter().position(|id| *id == client_id) {
-                ids.remove(index);
-            }
-        }
-        ids
-    }
-
     pub fn send(
         &mut self,
         client_id: ClientId,
         destination: &Destination,
         message: HWServerMessage,
     ) {
-        let ids = self.get_recipients(client_id, &destination);
-        self.output.push((ids, message));
+
     }
 
     pub fn send_msg(&mut self, client_id: ClientId, message: PendingMessage) {
--- a/rust/hedgewars-server/src/server/handlers.rs	Sat Feb 02 15:06:39 2019 +0300
+++ b/rust/hedgewars-server/src/server/handlers.rs	Mon Feb 04 19:22:21 2019 +0300
@@ -2,12 +2,12 @@
 use std::{io, io::Write};
 
 use super::{
-    actions::{Action, Action::*},
+    actions::{Action, Action::*, Destination},
     core::HWServer,
     coretypes::ClientId,
 };
 use crate::{
-    protocol::messages::{HWProtocolMessage, HWServerMessage::*},
+    protocol::messages::{HWProtocolMessage, HWServerMessage, HWServerMessage::*},
     server::actions::PendingMessage,
 };
 use log::*;
@@ -31,13 +31,64 @@
         }
     }
 
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.messages.is_empty()
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.messages.len()
+    }
+
+    #[inline]
     pub fn client_id(&self) -> ClientId {
         self.client_id
     }
 
+    #[inline]
     pub fn add(&mut self, message: PendingMessage) {
         self.messages.push(message)
     }
+
+    pub fn extract_messages<'a, 'b: 'a>(
+        &'b mut self,
+        server: &'a HWServer,
+    ) -> impl Iterator<Item = (Vec<ClientId>, HWServerMessage)> + 'a {
+        let client_id = self.client_id;
+        self.messages.drain(..).map(move |m| {
+            let ids = get_recipients(server, client_id, &m.destination);
+            (ids, m.message)
+        })
+    }
+}
+
+fn get_recipients(
+    server: &HWServer,
+    client_id: ClientId,
+    destination: &Destination,
+) -> Vec<ClientId> {
+    let mut ids = match *destination {
+        Destination::ToSelf => vec![client_id],
+        Destination::ToId(id) => vec![id],
+        Destination::ToAll {
+            room_id: Some(id), ..
+        } => server.room_clients(id),
+        Destination::ToAll {
+            protocol: Some(proto),
+            ..
+        } => server.protocol_clients(proto),
+        Destination::ToAll { .. } => server.clients.iter().map(|(id, _)| id).collect::<Vec<_>>(),
+    };
+    if let Destination::ToAll {
+        skip_self: true, ..
+    } = destination
+    {
+        if let Some(index) = ids.iter().position(|id| *id == client_id) {
+            ids.remove(index);
+        }
+    }
+    ids
 }
 
 pub fn handle(
@@ -49,13 +100,12 @@
     match message {
         HWProtocolMessage::Ping => {
             response.add(Pong.send_self());
-            server.react(client_id, vec![Pong.send_self().action()])
         }
         HWProtocolMessage::Quit(Some(msg)) => {
-            server.react(client_id, vec![ByeClient("User quit: ".to_string() + &msg)])
+            //ByeClient("User quit: ".to_string() + &msg)
         }
         HWProtocolMessage::Quit(None) => {
-            server.react(client_id, vec![ByeClient("User quit".to_string())])
+            //ByeClient("User quit".to_string())
         }
         HWProtocolMessage::Malformed => warn!("Malformed/unknown message"),
         HWProtocolMessage::Empty => warn!("Empty message"),
--- a/rust/hedgewars-server/src/server/handlers/lobby.rs	Sat Feb 02 15:06:39 2019 +0300
+++ b/rust/hedgewars-server/src/server/handlers/lobby.rs	Mon Feb 04 19:22:21 2019 +0300
@@ -21,12 +21,12 @@
     use crate::protocol::messages::HWProtocolMessage::*;
     match message {
         CreateRoom(name, password) => {
-            let actions = if is_name_illegal(&name) {
-                vec![Warn("Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string())]
+            if is_name_illegal(&name) {
+                response.add(Warning("Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string()).send_self());
             } else if server.has_room(&name) {
-                vec![Warn(
-                    "A room with the same name already exists.".to_string(),
-                )]
+                response.add(
+                    Warning("A room with the same name already exists.".to_string()).send_self(),
+                );
             } else {
                 let flags_msg = ClientFlags(
                     "+hr".to_string(),
@@ -45,20 +45,18 @@
                 response.add(flags_msg.send_self());
 
                 response.add(ClientFlags("+i".to_string(), vec![client.nick.clone()]).send_self());
-                vec![]
             };
-            server.react(client_id, actions);
         }
         Chat(msg) => {
-            let actions = vec![ChatMsg {
-                nick: server.clients[client_id].nick.clone(),
-                msg,
-            }
-            .send_all()
-            .in_room(server.lobby_id)
-            .but_self()
-            .action()];
-            server.react(client_id, actions);
+            response.add(
+                ChatMsg {
+                    nick: server.clients[client_id].nick.clone(),
+                    msg,
+                }
+                .send_all()
+                .in_room(server.lobby_id)
+                .but_self(),
+            );
         }
         JoinRoom(name, _password) => {
             let room = server.rooms.iter().find(|(_, r)| r.name == name);
@@ -71,17 +69,21 @@
                 .collect();
             let c = &mut server.clients[client_id];
 
-            let actions = if let Some((_, r)) = room {
+            if let Some((_, r)) = room {
                 if c.protocol_number != r.protocol_number {
-                    vec![Warn(
-                        "Room version incompatible to your Hedgewars version!".to_string(),
-                    )]
+                    response.add(
+                        Warning("Room version incompatible to your Hedgewars version!".to_string())
+                            .send_self(),
+                    );
                 } else if r.is_join_restricted() {
-                    vec![Warn(
-                        "Access denied. This room currently doesn't allow joining.".to_string(),
-                    )]
+                    response.add(
+                        Warning(
+                            "Access denied. This room currently doesn't allow joining.".to_string(),
+                        )
+                        .send_self(),
+                    );
                 } else if r.players_number == u8::max_value() {
-                    vec![Warn("This room is already full".to_string())]
+                    response.add(Warning("This room is already full".to_string()).send_self());
                 } else if let Some(room_id) = room_id {
                     let nick = c.nick.clone();
                     server.move_to_room(client_id, room_id);
@@ -101,18 +103,13 @@
                             .send_self(),
                         );
                     }
-
-                    vec![]
-                } else {
-                    vec![]
                 }
             } else {
-                vec![Warn("No such room.".to_string())]
-            };
-            server.react(client_id, actions);
+                response.add(Warning("No such room.".to_string()).send_self());
+            }
         }
         Rnd(v) => {
-            server.react(client_id, vec![rnd_reply(&v).send_self().action()]);
+            response.add(rnd_reply(&v).send_self());
         }
         List => warn!("Deprecated LIST message received"),
         _ => warn!("Incorrect command in lobby state"),
--- a/rust/hedgewars-server/src/server/handlers/loggingin.rs	Sat Feb 02 15:06:39 2019 +0300
+++ b/rust/hedgewars-server/src/server/handlers/loggingin.rs	Mon Feb 04 19:22:21 2019 +0300
@@ -46,30 +46,17 @@
         HWProtocolMessage::Nick(nick) => {
             let client = &mut server.clients[client_id];
             debug!("{} {}", nick, is_name_illegal(&nick));
-            let actions = if client.room_id != None {
+            if client.room_id != None {
                 unreachable!()
             } else if !client.nick.is_empty() {
-                vec![ProtocolError("Nickname already provided.".to_string())]
+                response.add(Error("Nickname already provided.".to_string()).send_self());
             } else if is_name_illegal(&nick) {
-                vec![ByeClient("Illegal nickname! Nicknames must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string())]
+                // ByeClient("Illegal nickname! Nicknames must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string())
             } else {
                 client.nick = nick.clone();
-                vec![Nick(nick).send_self().action(), CheckRegistered]
-            };
-
-            server.react(client_id, actions);
-        }
-        HWProtocolMessage::Proto(proto) => {
-            let client = &mut server.clients[client_id];
-            let actions = if client.protocol_number != 0 {
-                vec![ProtocolError("Protocol already known.".to_string())]
-            } else if proto == 0 {
-                vec![ProtocolError("Bad number.".to_string())]
-            } else {
-                client.protocol_number = proto;
-                vec![Proto(proto).send_self().action(), CheckRegistered]
-            };
-            server.react(client_id, actions);
+                response.add(Nick(nick).send_self());
+                //CheckRegistered
+            }
         }
         #[cfg(feature = "official-server")]
         HWProtocolMessage::Password(hash, salt) => {
@@ -77,17 +64,24 @@
 
             let client_hash = get_hash(c, &salt, &c.server_salt);
             let server_hash = get_hash(c, &c.server_salt, &salt);
-            let actions = if client_hash == server_hash {
-                vec![
-                    ServerAuth(format!("{:x}", server_hash))
-                        .send_self()
-                        .action(),
-                    JoinLobby,
-                ]
+            if client_hash == server_hash {
+                response.add(ServerAuth(format!("{:x}", server_hash)).send_self());
+            //JoinLobby
             } else {
-                vec![ByeClient("Authentication failed".to_string())]
+                //ByeClient("Authentication failed".to_string())
             };
-            server.react(client_id, actions);
+        }
+        HWProtocolMessage::Proto(proto) => {
+            let client = &mut server.clients[client_id];
+            if client.protocol_number != 0 {
+                response.add(Error("Protocol already known.".to_string()).send_self());
+            } else if proto == 0 {
+                response.add(Error("Bad number.".to_string()).send_self());
+            } else {
+                client.protocol_number = proto;
+                response.add(Proto(proto).send_self());
+                // CheckRegistered
+            }
         }
         #[cfg(feature = "official-server")]
         HWProtocolMessage::Checker(protocol, nick, password) => {
--- a/rust/hedgewars-server/src/server/network.rs	Sat Feb 02 15:06:39 2019 +0300
+++ b/rust/hedgewars-server/src/server/network.rs	Mon Feb 04 19:22:21 2019 +0300
@@ -327,9 +327,10 @@
         entry.insert(client);
     }
 
-    fn flush_server_messages(&mut self) {
-        debug!("{} pending server messages", self.server.output.len());
-        for (clients, message) in self.server.output.drain(..) {
+    fn flush_server_messages(&mut self, mut response: handlers::Response) {
+        debug!("{} pending server messages", response.len());
+        let output = response.extract_messages(&mut self.server);
+        for (clients, message) in output {
             debug!("Message {:?} to {:?}", message, clients);
             let msg_string = message.to_raw_protocol();
             for client_id in clients {
@@ -377,7 +378,7 @@
             self.create_client_socket(client_socket)?,
             addr,
         );
-        self.flush_server_messages();
+        //TODO: create response for initial messages
 
         Ok(())
     }
@@ -432,7 +433,9 @@
             )?,
         }
 
-        self.flush_server_messages();
+        if !response.is_empty() {
+            self.flush_server_messages(response);
+        }
 
         if !self.server.removed_clients.is_empty() {
             let ids: Vec<_> = self.server.removed_clients.drain(..).collect();