move room saves to IO thread
authoralfadur
Tue, 09 Apr 2019 23:03:12 +0300
changeset 14780 65861ba8b4e8
parent 14779 f43ab2bd76ae
child 14781 01f8ab45f806
move room saves to IO thread
rust/hedgewars-server/src/server/core.rs
rust/hedgewars-server/src/server/handlers.rs
rust/hedgewars-server/src/server/handlers/inroom.rs
rust/hedgewars-server/src/server/io.rs
rust/hedgewars-server/src/server/network.rs
--- a/rust/hedgewars-server/src/server/core.rs	Tue Apr 09 21:08:35 2019 +0300
+++ b/rust/hedgewars-server/src/server/core.rs	Tue Apr 09 23:03:12 2019 +0300
@@ -8,8 +8,6 @@
 
 use log::*;
 use slab;
-use std::fs::{File, OpenOptions};
-use std::io::{Read, Write};
 use std::{borrow::BorrowMut, iter, num::NonZeroU16};
 
 type Slab<T> = slab::Slab<T>;
@@ -48,18 +46,16 @@
 pub struct HWServer {
     pub clients: IndexSlab<HWClient>,
     pub rooms: Slab<HWRoom>,
-    pub io: Box<dyn HWServerIO>,
     pub anteroom: HWAnteroom,
 }
 
 impl HWServer {
-    pub fn new(clients_limit: usize, rooms_limit: usize, io: Box<dyn HWServerIO>) -> Self {
+    pub fn new(clients_limit: usize, rooms_limit: usize) -> Self {
         let rooms = Slab::with_capacity(rooms_limit);
         let clients = IndexSlab::with_capacity(clients_limit);
         Self {
             clients,
             rooms,
-            io,
             anteroom: HWAnteroom::new(clients_limit),
         }
     }
@@ -205,48 +201,3 @@
         }
     }
 }
-
-pub trait HWServerIO {
-    fn write_file(&mut self, name: &str, content: &str) -> std::io::Result<()>;
-    fn read_file(&mut self, name: &str) -> std::io::Result<String>;
-}
-
-pub struct EmptyServerIO {}
-
-impl EmptyServerIO {
-    pub fn new() -> Self {
-        Self {}
-    }
-}
-
-impl HWServerIO for EmptyServerIO {
-    fn write_file(&mut self, _name: &str, _content: &str) -> std::io::Result<()> {
-        Ok(())
-    }
-
-    fn read_file(&mut self, _name: &str) -> std::io::Result<String> {
-        Ok("".to_string())
-    }
-}
-
-pub struct FileServerIO {}
-
-impl FileServerIO {
-    pub fn new() -> Self {
-        Self {}
-    }
-}
-
-impl HWServerIO for FileServerIO {
-    fn write_file(&mut self, name: &str, content: &str) -> std::io::Result<()> {
-        let mut writer = OpenOptions::new().create(true).write(true).open(name)?;
-        writer.write_all(content.as_bytes())
-    }
-
-    fn read_file(&mut self, name: &str) -> std::io::Result<String> {
-        let mut reader = File::open(name)?;
-        let mut result = String::new();
-        reader.read_to_string(&mut result)?;
-        Ok(result)
-    }
-}
--- a/rust/hedgewars-server/src/server/handlers.rs	Tue Apr 09 21:08:35 2019 +0300
+++ b/rust/hedgewars-server/src/server/handlers.rs	Tue Apr 09 23:03:12 2019 +0300
@@ -4,11 +4,11 @@
 use super::{
     actions::{Destination, DestinationRoom},
     core::HWServer,
-    coretypes::ClientId,
+    coretypes::{ClientId, RoomId},
     room::RoomSave,
 };
 use crate::{
-    protocol::messages::{HWProtocolMessage, HWServerMessage, HWServerMessage::*},
+    protocol::messages::{HWProtocolMessage, HWServerMessage, HWServerMessage::*, server_chat},
     server::actions::PendingMessage,
     utils,
 };
@@ -58,10 +58,21 @@
         client_salt: String,
         server_salt: String,
     },
+    SaveRoom {
+        room_id: RoomId,
+        filename: String,
+        contents: String,
+    },
+    LoadRoom {
+        room_id: RoomId,
+        filename: String
+    }
 }
 
 pub enum IoResult {
     Account(Option<AccountInfo>),
+    SaveRoom(RoomId, bool),
+    LoadRoom(RoomId, Option<String>)
 }
 
 pub struct Response {
@@ -250,5 +261,35 @@
             response.add(Error("Authentication failed.".to_string()).send_self());
             response.remove_client(client_id);
         }
+        IoResult::SaveRoom(_, true) => {
+            response.add(server_chat("Room configs saved successfully.".to_string()).send_self());
+        }
+        IoResult::SaveRoom(_, false) => {
+            response.add(
+                Warning("Unable to save the room configs.".to_string()).send_self(),
+            );
+        }
+        IoResult::LoadRoom(room_id, Some(contents)) => {
+            if let Some(ref mut room) = server.rooms.get_mut(room_id) {
+                match room.set_saves(&contents) {
+                    Ok(_) => response.add(
+                        server_chat("Room configs loaded successfully.".to_string())
+                            .send_self(),
+                    ),
+                    Err(e) => {
+                        warn!("Error while deserializing the room configs: {}", e);
+                        response.add(
+                            Warning("Unable to deserialize the room configs.".to_string())
+                                .send_self(),
+                        );
+                    }
+                }
+            }
+        }
+        IoResult::LoadRoom(_,None) => {
+            response.add(
+                Warning("Unable to load the room configs.".to_string()).send_self(),
+            );
+        }
     }
 }
--- a/rust/hedgewars-server/src/server/handlers/inroom.rs	Tue Apr 09 21:08:35 2019 +0300
+++ b/rust/hedgewars-server/src/server/handlers/inroom.rs	Tue Apr 09 23:03:12 2019 +0300
@@ -337,20 +337,10 @@
         SaveRoom(filename) => {
             if client.is_admin() {
                 match room.get_saves() {
-                    Ok(text) => match server.io.write_file(&filename, &text) {
-                        Ok(_) => response.add(
-                            server_chat("Room configs saved successfully.".to_string()).send_self(),
-                        ),
-                        Err(e) => {
-                            warn!(
-                                "Error while writing the config file \"{}\": {}",
-                                filename, e
-                            );
-                            response.add(
-                                Warning("Unable to save the room configs.".to_string()).send_self(),
-                            );
-                        }
-                    },
+                    Ok(contents) =>
+                        response.request_io(super::IoTask::SaveRoom {
+                            room_id, filename, contents
+                        }),
                     Err(e) => {
                         warn!("Error while serializing the room configs: {}", e);
                         response.add(
@@ -363,30 +353,10 @@
         }
         LoadRoom(filename) => {
             if client.is_admin() {
-                match server.io.read_file(&filename) {
-                    Ok(text) => match room.set_saves(&text) {
-                        Ok(_) => response.add(
-                            server_chat("Room configs loaded successfully.".to_string())
-                                .send_self(),
-                        ),
-                        Err(e) => {
-                            warn!("Error while deserializing the room configs: {}", e);
-                            response.add(
-                                Warning("Unable to deserialize the room configs.".to_string())
-                                    .send_self(),
-                            );
-                        }
-                    },
-                    Err(e) => {
-                        warn!(
-                            "Error while reading the config file \"{}\": {}",
-                            filename, e
-                        );
-                        response.add(
-                            Warning("Unable to load the room configs.".to_string()).send_self(),
-                        );
-                    }
-                }
+                response.request_io(super::IoTask::LoadRoom {
+                    room_id,
+                    filename
+                });
             }
         }
         Delete(name) => {
--- a/rust/hedgewars-server/src/server/io.rs	Tue Apr 09 21:08:35 2019 +0300
+++ b/rust/hedgewars-server/src/server/io.rs	Tue Apr 09 23:03:12 2019 +0300
@@ -11,6 +11,7 @@
 };
 use mio::{Evented, Poll, PollOpt};
 use mio_extras::channel;
+use log::*;
 
 pub type RequestId = u32;
 
@@ -29,7 +30,7 @@
 
         thread::spawn(move || {
             while let Ok((request_id, task)) = io_rx.try_recv() {
-                match task {
+                let response = match task {
                     IoTask::GetAccount {
                         nick,
                         protocol,
@@ -37,17 +38,52 @@
                         client_salt,
                         server_salt,
                     } => {
-                        if let Ok(account) = db.get_account(
+                        match db.get_account(
                             &nick,
                             protocol,
                             &password_hash,
                             &client_salt,
                             &server_salt,
                         ) {
-                            io_tx.send((request_id, IoResult::Account(account)));
+                            Ok(account) => {
+                                IoResult::Account(account)
+                            }
+                            Err(..) => {
+                                warn!("Unable to get account data: {}", 0);
+                                IoResult::Account(None)
+                            }
                         }
+                    },
+
+                    IoTask::SaveRoom { room_id, filename, contents} => {
+                        let result = match save_file(&filename, &contents) {
+                            Ok(()) => true,
+                            Err(e) => {
+                                warn!(
+                                    "Error while writing the room config file \"{}\": {}",
+                                    filename, e
+                                );
+                                false
+                           }
+                        };
+                        IoResult::SaveRoom(room_id, result)
+                    },
+
+                    IoTask::LoadRoom {room_id, filename} => {
+                        let result = match load_file(&filename) {
+                            Ok(contents) => Some(contents),
+                            Err(e) => {
+                                warn!(
+                                    "Error while writing the room config file \"{}\": {}",
+                                    filename, e
+                                );
+                                None
+                            }
+                        };
+                        IoResult::LoadRoom(room_id, result)
                     }
-                }
+                };
+                io_tx.send((request_id, response));
             }
         });
 
@@ -71,3 +107,15 @@
             .register(poll, token, mio::Ready::readable(), PollOpt::edge())
     }
 }
+
+fn save_file(filename: &str, contents: &str) -> Result<()> {
+    let mut writer = OpenOptions::new().create(true).write(true).open(filename)?;
+    writer.write_all(contents.as_bytes())
+}
+
+fn load_file(filename: &str) -> Result<String> {
+    let mut reader = File::open(filename)?;
+    let mut result = String::new();
+    reader.read_to_string(&mut result)?;
+    Ok(result)
+}
\ No newline at end of file
--- a/rust/hedgewars-server/src/server/network.rs	Tue Apr 09 21:08:35 2019 +0300
+++ b/rust/hedgewars-server/src/server/network.rs	Tue Apr 09 23:03:12 2019 +0300
@@ -16,7 +16,7 @@
 use netbuf;
 use slab::Slab;
 
-use super::{core::FileServerIO, core::HWServer, coretypes::ClientId, handlers};
+use super::{core::HWServer, coretypes::ClientId, handlers};
 use crate::{
     protocol::{messages::*, ProtocolDecoder},
     utils,
@@ -303,7 +303,7 @@
 
 impl NetworkLayer {
     pub fn new(listener: TcpListener, clients_limit: usize, rooms_limit: usize) -> NetworkLayer {
-        let server = HWServer::new(clients_limit, rooms_limit, Box::new(FileServerIO::new()));
+        let server = HWServer::new(clients_limit, rooms_limit);
         let clients = Slab::with_capacity(clients_limit);
         let pending = HashSet::with_capacity(2 * clients_limit);
         let pending_cache = Vec::with_capacity(2 * clients_limit);