fix voting rights
authoralfadur
Mon, 12 Feb 2024 01:19:32 +0300
changeset 16015 cd8392e52165
parent 16014 e42d1819b150
child 16016 b26c3497ea85
fix voting rights
rust/hedgewars-server/Cargo.toml
rust/hedgewars-server/src/core/server.rs
rust/hedgewars-server/src/handlers/common.rs
--- a/rust/hedgewars-server/Cargo.toml	Sun Feb 11 20:33:15 2024 +0100
+++ b/rust/hedgewars-server/Cargo.toml	Mon Feb 12 01:19:32 2024 +0300
@@ -25,7 +25,7 @@
 serde_derive = "1.0"
 sha1 = { version = "0.10.0", optional = true }
 slab = "0.4"
-tokio = { version = "1.16", features = ["full"]}
+tokio = { version = "1.36", features = ["full"]}
 tokio-native-tls = { version = "0.3", optional = true }
 
 hedgewars-network-protocol = { path = "../hedgewars-network-protocol" }
--- a/rust/hedgewars-server/src/core/server.rs	Sun Feb 11 20:33:15 2024 +0100
+++ b/rust/hedgewars-server/src/core/server.rs	Mon Feb 12 01:19:32 2024 +0300
@@ -12,6 +12,7 @@
 
 use bitflags::*;
 use log::*;
+use rand::{self, seq::SliceRandom, thread_rng, Rng};
 use slab::Slab;
 use std::{borrow::BorrowMut, cmp::min, collections::HashSet, iter, mem::replace};
 
@@ -109,9 +110,18 @@
 }
 
 #[derive(Debug)]
+pub enum VoteEffect {
+    Kicked(ClientId, LeaveRoomResult),
+    Map(String),
+    Pause,
+    NewSeed(GameCfg),
+    HedgehogsPerTeam(u8, Vec<String>),
+}
+
+#[derive(Debug)]
 pub enum VoteResult {
     Submitted,
-    Succeeded(VoteType),
+    Succeeded(VoteEffect),
     Failed,
 }
 
@@ -609,8 +619,8 @@
         HwRoomControl::new(self.server, client_id).filter(|c| c.room_id == room_id)
     }
 
-    pub fn leave_room(&mut self) -> LeaveRoomResult {
-        let (client, room) = self.get_mut();
+    fn remove_from_room(&mut self, client_id: ClientId) -> LeaveRoomResult {
+        let Some((client, room)) = self.server.client_and_room_mut(client_id);
         room.players_number -= 1;
         client.room_id = None;
 
@@ -689,6 +699,10 @@
         }
     }
 
+    pub fn leave_room(&mut self) -> LeaveRoomResult {
+        self.remove_from_room(self.client_id)
+    }
+
     pub fn change_master(
         &mut self,
         new_master_nick: String,
@@ -743,6 +757,40 @@
         }
     }
 
+    fn apply_vote(&mut self, kind: VoteType) -> Option<VoteEffect> {
+        match kind {
+            VoteType::Kick(nick) => {
+                if let Some(kicked_id) = self
+                    .server
+                    .find_client(&nick)
+                    .filter(|c| c.room_id == Some(self.room_id))
+                    .map(|c| c.id)
+                {
+                    let leave_result = self.remove_from_room(kicked_id);
+                    Some(VoteEffect::Kicked(kicked_id, leave_result))
+                } else {
+                    None
+                }
+            }
+            VoteType::Map(None) => None,
+            VoteType::Map(Some(name)) => self
+                .load_config(&name)
+                .map(|s| VoteEffect::Map(s.to_string())),
+            VoteType::Pause => Some(VoteEffect::Pause).filter(|_| self.toggle_pause()),
+            VoteType::NewSeed => {
+                let seed = thread_rng().gen_range(0..1_000_000_000).to_string();
+                let cfg = GameCfg::Seed(seed);
+                todo!("Protocol backwards compatibility");
+                self.room_mut().set_config(cfg.clone());
+                Some(VoteEffect::NewSeed(cfg))
+            }
+            VoteType::HedgehogsPerTeam(number) => {
+                let nicks = self.set_hedgehogs_number(number);
+                Some(VoteEffect::HedgehogsPerTeam(number, nicks))
+            }
+        }
+    }
+
     pub fn vote(&mut self, vote: Vote) -> Result<VoteResult, VoteError> {
         use self::{VoteError::*, VoteResult::*};
         let client_id = self.client_id;
@@ -753,9 +801,14 @@
                 let pro = i.clone().filter(|(_, v)| *v).count();
                 let contra = i.filter(|(_, v)| !*v).count();
                 let success_quota = voting.voters.len() / 2 + 1;
+                
                 if vote.is_forced && vote.is_pro || pro >= success_quota {
                     let voting = self.room_mut().voting.take().unwrap();
-                    Ok(Succeeded(voting.kind))
+                    if let Some(effect) = self.apply_vote(voting.kind) {
+                        Ok(Succeeded(effect))
+                    } else {
+                        Ok(Failed)
+                    }
                 } else if vote.is_forced && !vote.is_pro
                     || contra > voting.voters.len() - success_quota
                 {
@@ -941,7 +994,6 @@
                 }
                 cfg => cfg,
             };
-
             room.set_config(cfg);
             Ok(())
         }
--- a/rust/hedgewars-server/src/handlers/common.rs	Sun Feb 11 20:33:15 2024 +0100
+++ b/rust/hedgewars-server/src/handlers/common.rs	Mon Feb 12 01:19:32 2024 +0300
@@ -9,7 +9,7 @@
         room::HwRoom,
         server::{
             EndGameResult, HwRoomControl, HwServer, JoinRoomError, LeaveRoomResult, StartGameError,
-            VoteError, VoteResult,
+            VoteEffect, VoteError, VoteResult,
         },
         types::{ClientId, RoomId},
     },
@@ -510,76 +510,58 @@
 }
 
 pub fn handle_vote(
-    mut room_control: HwRoomControl,
+    room_control: HwRoomControl,
     result: Result<VoteResult, VoteError>,
     response: &mut super::Response,
 ) {
-    todo!("voting result needs to be processed with raised privileges");
     let room_id = room_control.room().id;
-    super::common::get_vote_data(room_control.room().id, &result, response);
+    get_vote_data(room_control.room().id, &result, response);
 
-    if let Ok(VoteResult::Succeeded(kind)) = result {
-        match kind {
-            VoteType::Kick(nick) => {
-                if let Some(kicked_client) = room_control.server().find_client(&nick) {
-                    let kicked_id = kicked_client.id;
-                    if let Some(mut room_control) = room_control.change_client(kicked_id) {
-                        response.add(Kicked.send(kicked_id));
-                        let result = room_control.leave_room();
-                        super::common::get_room_leave_result(
-                            room_control.server(),
-                            room_control.room(),
-                            "kicked",
-                            result,
-                            response,
-                        );
-                    }
-                }
+    if let Ok(VoteResult::Succeeded(effect)) = result {
+        match effect {
+            VoteEffect::Kicked(kicked_id, leave_result) => {
+                response.add(Kicked.send(kicked_id));
+                get_room_leave_result(
+                    room_control.server(),
+                    room_control.room(),
+                    "kicked",
+                    leave_result,
+                    response,
+                );
             }
-            VoteType::Map(None) => (),
-            VoteType::Map(Some(name)) => {
-                if let Some(location) = room_control.load_config(&name) {
-                    let msg = server_chat(location.to_string());
-                    let room = room_control.room();
-                    response.add(msg.send_all().in_room(room.id));
+            VoteEffect::Map(location) => {
+                let msg = server_chat(location.to_string());
+                let room = room_control.room();
+                response.add(msg.send_all().in_room(room.id));
 
-                    let room_master = room.master_id.map(|id| room_control.server().client(id));
+                let room_master = room.master_id.map(|id| room_control.server().client(id));
 
-                    super::common::get_room_update(None, room, room_master, response);
+                get_room_update(None, room, room_master, response);
 
-                    let room_destination = Destination::ToAll {
-                        group: DestinationGroup::Room(room.id),
-                        skip_self: false,
-                    };
-                    super::common::get_active_room_config(room, room_destination, response);
-                }
+                let room_destination = Destination::ToAll {
+                    group: DestinationGroup::Room(room.id),
+                    skip_self: false,
+                };
+                get_active_room_config(room, room_destination, response);
             }
-            VoteType::Pause => {
-                if room_control.toggle_pause() {
-                    response.add(
-                        server_chat("Pause toggled.".to_string())
-                            .send_all()
-                            .in_room(room_id),
-                    );
-                    response.add(
-                        ForwardEngineMessage(vec![to_engine_msg(once(b'I'))])
-                            .send_all()
-                            .in_room(room_id),
-                    );
-                }
+            VoteEffect::Pause => {
+                response.add(
+                    server_chat("Pause toggled.".to_string())
+                        .send_all()
+                        .in_room(room_id),
+                );
+                response.add(
+                    ForwardEngineMessage(vec![to_engine_msg(once(b'I'))])
+                        .send_all()
+                        .in_room(room_id),
+                );
             }
-            VoteType::NewSeed => {
-                let seed = thread_rng().gen_range(0..1_000_000_000).to_string();
-                let cfg = GameCfg::Seed(seed);
+            VoteEffect::NewSeed(cfg) => {
                 response.add(cfg.to_server_msg().send_all().in_room(room_id));
-                room_control
-                    .set_config(cfg)
-                    .expect("Apparently, you cannot just set room config");
             }
-            VoteType::HedgehogsPerTeam(number) => {
-                let nicks = room_control.set_hedgehogs_number(number);
+            VoteEffect::HedgehogsPerTeam(number, team_names) => {
                 response.extend(
-                    nicks
+                    team_names
                         .into_iter()
                         .map(|n| HedgehogsNumber(n, number).send_all().in_room(room_id)),
                 );