# HG changeset patch # User unc0rr # Date 1544915549 -3600 # Node ID 98ef2913ec738e2370383343310f54d20d8b93aa # Parent a077aac9df01fe449fd34a2d2fc0aaff82312f3d Apply rustfmt to all files diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/main.rs --- a/rust/hedgewars-server/src/main.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/main.rs Sun Dec 16 00:12:29 2018 +0100 @@ -4,13 +4,13 @@ //use std::io::*; //use rand::Rng; //use std::cmp::Ordering; +use log::*; use mio::net::*; use mio::*; -use log::*; +mod protocol; +mod server; mod utils; -mod server; -mod protocol; use crate::server::network::NetworkLayer; use std::time::Duration; @@ -18,7 +18,10 @@ fn main() { env_logger::init(); - info!("Hedgewars game server, protocol {}", utils::PROTOCOL_VERSION); + info!( + "Hedgewars game server, protocol {}", + utils::PROTOCOL_VERSION + ); let address = "0.0.0.0:46631".parse().unwrap(); let listener = TcpListener::bind(&address).unwrap(); @@ -50,12 +53,12 @@ Token(tok) => hw_network.client_writable(&poll, tok).unwrap(), } } -// if event.kind().is_hup() || event.kind().is_error() { -// match event.token() { -// utils::SERVER => unreachable!(), -// Token(tok) => server.client_error(&poll, tok).unwrap(), -// } -// } + // if event.kind().is_hup() || event.kind().is_error() { + // match event.token() { + // utils::SERVER => unreachable!(), + // Token(tok) => server.client_error(&poll, tok).unwrap(), + // } + // } } hw_network.on_idle(&poll).unwrap(); } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/protocol.rs --- a/rust/hedgewars-server/src/protocol.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/protocol.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,15 +1,11 @@ use netbuf; -use std::{ - io::{Read, Result} -}; -use nom::{ - IResult, Err -}; +use nom::{Err, IResult}; +use std::io::{Read, Result}; pub mod messages; +mod parser; #[cfg(test)] pub mod test; -mod parser; pub struct ProtocolDecoder { buf: netbuf::Buf, @@ -34,7 +30,7 @@ Ok((tail, msgs)) => { self.consumed = self.buf.len() - self.consumed - tail.len(); msgs - }, + } Err(Err::Incomplete(_)) => unreachable!(), Err(Err::Error(_)) | Err(Err::Failure(_)) => unreachable!(), } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/protocol/messages.rs --- a/rust/hedgewars-server/src/protocol/messages.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/protocol/messages.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,8 +1,5 @@ -use crate::server::coretypes::{ - ServerVar, GameCfg, TeamInfo, - HedgehogInfo, VoteType -}; -use std::{ops, convert::From, iter::once}; +use crate::server::coretypes::{GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType}; +use std::{convert::From, iter::once, ops}; #[derive(PartialEq, Eq, Clone, Debug)] pub enum HWProtocolMessage { @@ -80,7 +77,7 @@ ServerAuth(String), LobbyLeft(String, String), LobbyJoined(Vec), - ChatMsg {nick: String, msg: String}, + ChatMsg { nick: String, msg: String }, ClientFlags(String, Vec), Rooms(Vec), RoomAdd(Vec), @@ -107,11 +104,14 @@ Unreachable, //Deprecated messages - LegacyReady(bool, Vec) + LegacyReady(bool, Vec), } -pub fn server_chat(msg: String) -> HWServerMessage { - HWServerMessage::ChatMsg{ nick: "[server]".to_string(), msg } +pub fn server_chat(msg: String) -> HWServerMessage { + HWServerMessage::ChatMsg { + nick: "[server]".to_string(), + msg, + } } impl GameCfg { @@ -135,7 +135,7 @@ }), Script(s) => ("SCRIPT".to_string(), vec![s.to_string()]), Theme(t) => ("THEME".to_string(), vec![t.to_string()]), - DrawnMap(m) => ("DRAWNMAP".to_string(), vec![m.to_string()]) + DrawnMap(m) => ("DRAWNMAP".to_string(), vec![m.to_string()]), } } @@ -147,7 +147,9 @@ } macro_rules! const_braces { - ($e: expr) => { "{}\n" } + ($e: expr) => { + "{}\n" + }; } macro_rules! msg { @@ -178,7 +180,7 @@ Global(msg) => msg!["CMD", format!("GLOBAL {}", msg)], Watch(name) => msg!["CMD", format!("WATCH {}", name)], ToggleServerRegisteredOnly => msg!["CMD", "REGISTERED_ONLY"], - SuperPower => msg!["CMD", "SUPER_POWER"], + SuperPower => msg!["CMD", "SUPER_POWER"], Info(info) => msg!["CMD", format!("INFO {}", info)], Nick(nick) => msg!("NICK", nick), Proto(version) => msg!["PROTO", version], @@ -187,22 +189,21 @@ List => msg!["LIST"], Chat(msg) => msg!["CHAT", msg], CreateRoom(name, None) => msg!["CREATE_ROOM", name], - CreateRoom(name, Some(password)) => - msg!["CREATE_ROOM", name, password], + CreateRoom(name, Some(password)) => msg!["CREATE_ROOM", name, password], JoinRoom(name, None) => msg!["JOIN_ROOM", name], - JoinRoom(name, Some(password)) => - msg!["JOIN_ROOM", name, password], + JoinRoom(name, Some(password)) => msg!["JOIN_ROOM", name, password], Follow(name) => msg!["FOLLOW", name], - Rnd(args) => if args.is_empty() { - msg!["CMD", "RND"] - } else { - msg!["CMD", format!("RND {}", args.join(" "))] - }, + Rnd(args) => { + if args.is_empty() { + msg!["CMD", "RND"] + } else { + msg!["CMD", format!("RND {}", args.join(" "))] + } + } Kick(name) => msg!["KICK", name], Ban(name, reason, time) => msg!["BAN", name, reason, time], BanIP(ip, reason, time) => msg!["BAN_IP", ip, reason, time], - BanNick(nick, reason, time) => - msg!("BAN_NICK", nick, reason, time), + BanNick(nick, reason, time) => msg!("BAN_NICK", nick, reason, time), BanList => msg!["BANLIST"], Unban(name) => msg!["UNBAN", name], //SetServerVar(ServerVar), ??? @@ -214,13 +215,22 @@ Cfg(config) => { let (name, args) = config.to_protocol(); msg!["CFG", name, args.join("\n")] - }, - AddTeam(info) => - msg!["ADD_TEAM", info.name, info.color, info.grave, info.fort, - info.voice_pack, info.flag, info.difficulty, - info.hedgehogs.iter() - .flat_map(|h| several![&h.name[..], &h.hat[..]]) - .collect::>().join("\n")], + } + AddTeam(info) => msg![ + "ADD_TEAM", + info.name, + info.color, + info.grave, + info.fort, + info.voice_pack, + info.flag, + info.difficulty, + info.hedgehogs + .iter() + .flat_map(|h| several![&h.name[..], &h.hat[..]]) + .collect::>() + .join("\n") + ], RemoveTeam(name) => msg!["REMOVE_TEAM", name], SetHedgehogsNumber(team, number) => msg!["HH_NUM", team, number], SetTeamColor(team, color) => msg!["TEAM_COLOR", team, color], @@ -234,20 +244,20 @@ RoomName(name) => msg!["ROOM_NAME", name], Delegate(name) => msg!["CMD", format!("DELEGATE {}", name)], TeamChat(msg) => msg!["TEAMCHAT", msg], - MaxTeams(count) => msg!["CMD", format!("MAXTEAMS {}", count)] , + MaxTeams(count) => msg!["CMD", format!("MAXTEAMS {}", count)], Fix => msg!["CMD", "FIX"], Unfix => msg!["CMD", "UNFIX"], Greeting(msg) => msg!["CMD", format!("GREETING {}", msg)], //CallVote(Option<(String, Option)>) =>, ?? - Vote(msg) => msg!["CMD", format!("VOTE {}", if *msg {"YES"} else {"NO"})], - ForceVote(msg) => msg!["CMD", format!("FORCE {}", if *msg {"YES"} else {"NO"})], + Vote(msg) => msg!["CMD", format!("VOTE {}", if *msg { "YES" } else { "NO" })], + ForceVote(msg) => msg!["CMD", format!("FORCE {}", if *msg { "YES" } else { "NO" })], Save(name, location) => msg!["CMD", format!("SAVE {} {}", name, location)], Delete(name) => msg!["CMD", format!("DELETE {}", name)], SaveRoom(name) => msg!["CMD", format!("SAVEROOM {}", name)], LoadRoom(name) => msg!["CMD", format!("LOADROOM {}", name)], Malformed => msg!["A", "QUICK", "BROWN", "HOG", "JUMPS", "OVER", "THE", "LAZY", "DOG"], Empty => msg![""], - _ => panic!("Protocol message not yet implemented") + _ => panic!("Protocol message not yet implemented"), } } } @@ -268,47 +278,40 @@ Connected(protocol_version) => msg![ "CONNECTED", "Hedgewars server https://www.hedgewars.org/", - protocol_version], + protocol_version + ], Bye(msg) => msg!["BYE", msg], Nick(nick) => msg!["NICK", nick], Proto(proto) => msg!["PROTO", proto], ServerAuth(hash) => msg!["SERVER_AUTH", hash], LobbyLeft(nick, msg) => msg!["LOBBY:LEFT", nick, msg], - LobbyJoined(nicks) => - construct_message(&["LOBBY:JOINED"], &nicks), - ClientFlags(flags, nicks) => - construct_message(&["CLIENT_FLAGS", flags], &nicks), - Rooms(info) => - construct_message(&["ROOMS"], &info), - RoomAdd(info) => - construct_message(&["ROOM", "ADD"], &info), - RoomJoined(nicks) => - construct_message(&["JOINED"], &nicks), + LobbyJoined(nicks) => construct_message(&["LOBBY:JOINED"], &nicks), + ClientFlags(flags, nicks) => construct_message(&["CLIENT_FLAGS", flags], &nicks), + Rooms(info) => construct_message(&["ROOMS"], &info), + RoomAdd(info) => construct_message(&["ROOM", "ADD"], &info), + RoomJoined(nicks) => construct_message(&["JOINED"], &nicks), RoomLeft(nick, msg) => msg!["LEFT", nick, msg], RoomRemove(name) => msg!["ROOM", "DEL", name], - RoomUpdated(name, info) => - construct_message(&["ROOM", "UPD", name], &info), - TeamAdd(info) => - construct_message(&["ADD_TEAM"], &info), + RoomUpdated(name, info) => construct_message(&["ROOM", "UPD", name], &info), + TeamAdd(info) => construct_message(&["ADD_TEAM"], &info), TeamRemove(name) => msg!["REMOVE_TEAM", name], TeamAccepted(name) => msg!["TEAM_ACCEPTED", name], TeamColor(name, color) => msg!["TEAM_COLOR", name, color], HedgehogsNumber(name, number) => msg!["HH_NUM", name, number], - ConfigEntry(name, values) => - construct_message(&["CFG", name], &values), + ConfigEntry(name, values) => construct_message(&["CFG", name], &values), Kicked => msg!["KICKED"], RunGame => msg!["RUN_GAME"], - ForwardEngineMessage(em) => - construct_message(&["EM"], &em), + ForwardEngineMessage(em) => construct_message(&["EM"], &em), RoundFinished => msg!["ROUND_FINISHED"], - ChatMsg {nick, msg} => msg!["CHAT", nick, msg], + ChatMsg { nick, msg } => msg!["CHAT", nick, msg], ServerMessage(msg) => msg!["SERVER_MESSAGE", msg], Notice(msg) => msg!["NOTICE", msg], Warning(msg) => msg!["WARNING", msg], Error(msg) => msg!["ERROR", msg], - LegacyReady(is_ready, nicks) => - construct_message(&[if *is_ready {"READY"} else {"NOT_READY"}], &nicks), + LegacyReady(is_ready, nicks) => { + construct_message(&[if *is_ready { "READY" } else { "NOT_READY" }], &nicks) + } _ => msg!["ERROR", "UNIMPLEMENTED"], } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/protocol/parser.rs --- a/rust/hedgewars-server/src/protocol/parser.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/protocol/parser.rs Sun Dec 16 00:12:29 2018 +0100 @@ -6,23 +6,15 @@ * For example, a nullary command like PING will be actually sent as `PING\n\n`. * A unary command, such as `START_GAME nick` will be actually sent as `START_GAME\nnick\n\n`. */ - use nom::*; -use std::{ - str, str::FromStr, - ops::Range -}; -use super::{ - messages::{HWProtocolMessage, HWProtocolMessage::*} -}; +use super::messages::{HWProtocolMessage, HWProtocolMessage::*}; +use crate::server::coretypes::{GameCfg, HedgehogInfo, TeamInfo, VoteType, MAX_HEDGEHOGS_PER_TEAM}; +use std::{ops::Range, str, str::FromStr}; #[cfg(test)] use { super::test::gen_proto_msg, - proptest::{proptest, proptest_helper} -}; -use crate::server::coretypes::{ - HedgehogInfo, TeamInfo, GameCfg, VoteType, MAX_HEDGEHOGS_PER_TEAM + proptest::{proptest, proptest_helper}, }; named!(end_of_message, tag!("\n\n")); @@ -257,17 +249,32 @@ #[test] fn parse_test() { - assert_eq!(message(b"PING\n\n"), Ok((&b""[..], Ping))); - assert_eq!(message(b"START_GAME\n\n"), Ok((&b""[..], StartGame))); - assert_eq!(message(b"NICK\nit's me\n\n"), Ok((&b""[..], Nick("it's me".to_string())))); - assert_eq!(message(b"PROTO\n51\n\n"), Ok((&b""[..], Proto(51)))); - assert_eq!(message(b"QUIT\nbye-bye\n\n"), Ok((&b""[..], Quit(Some("bye-bye".to_string()))))); - assert_eq!(message(b"QUIT\n\n"), Ok((&b""[..], Quit(None)))); - assert_eq!(message(b"CMD\nwatch demo\n\n"), Ok((&b""[..], Watch("demo".to_string())))); - assert_eq!(message(b"BAN\nme\nbad\n77\n\n"), Ok((&b""[..], Ban("me".to_string(), "bad".to_string(), 77)))); + assert_eq!(message(b"PING\n\n"), Ok((&b""[..], Ping))); + assert_eq!(message(b"START_GAME\n\n"), Ok((&b""[..], StartGame))); + assert_eq!( + message(b"NICK\nit's me\n\n"), + Ok((&b""[..], Nick("it's me".to_string()))) + ); + assert_eq!(message(b"PROTO\n51\n\n"), Ok((&b""[..], Proto(51)))); + assert_eq!( + message(b"QUIT\nbye-bye\n\n"), + Ok((&b""[..], Quit(Some("bye-bye".to_string())))) + ); + assert_eq!(message(b"QUIT\n\n"), Ok((&b""[..], Quit(None)))); + assert_eq!( + message(b"CMD\nwatch demo\n\n"), + Ok((&b""[..], Watch("demo".to_string()))) + ); + assert_eq!( + message(b"BAN\nme\nbad\n77\n\n"), + Ok((&b""[..], Ban("me".to_string(), "bad".to_string(), 77))) + ); - assert_eq!(message(b"CMD\nPART\n\n"), Ok((&b""[..], Part(None)))); - assert_eq!(message(b"CMD\nPART _msg_\n\n"), Ok((&b""[..], Part(Some("_msg_".to_string()))))); + assert_eq!(message(b"CMD\nPART\n\n"), Ok((&b""[..], Part(None)))); + assert_eq!( + message(b"CMD\nPART _msg_\n\n"), + Ok((&b""[..], Part(Some("_msg_".to_string())))) + ); assert_eq!(message(b"CMD\nRND\n\n"), Ok((&b""[..], Rnd(vec![])))); assert_eq!( @@ -275,10 +282,25 @@ Ok((&b""[..], Rnd(vec![String::from("A"), String::from("B")]))) ); - assert_eq!(extract_messages(b"QUIT\n1\n2\n\n"), Ok((&b""[..], vec![Malformed]))); + assert_eq!( + extract_messages(b"QUIT\n1\n2\n\n"), + Ok((&b""[..], vec![Malformed])) + ); - assert_eq!(extract_messages(b"PING\n\nPING\n\nP"), Ok((&b"P"[..], vec![Ping, Ping]))); - assert_eq!(extract_messages(b"SING\n\nPING\n\n"), Ok((&b""[..], vec![Malformed, Ping]))); - assert_eq!(extract_messages(b"\n\n\n\nPING\n\n"), Ok((&b""[..], vec![Empty, Empty, Ping]))); - assert_eq!(extract_messages(b"\n\n\nPING\n\n"), Ok((&b""[..], vec![Empty, Empty, Ping]))); + assert_eq!( + extract_messages(b"PING\n\nPING\n\nP"), + Ok((&b"P"[..], vec![Ping, Ping])) + ); + assert_eq!( + extract_messages(b"SING\n\nPING\n\n"), + Ok((&b""[..], vec![Malformed, Ping])) + ); + assert_eq!( + extract_messages(b"\n\n\n\nPING\n\n"), + Ok((&b""[..], vec![Empty, Empty, Ping])) + ); + assert_eq!( + extract_messages(b"\n\n\nPING\n\n"), + Ok((&b""[..], vec![Empty, Empty, Ping])) + ); } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/protocol/test.rs --- a/rust/hedgewars-server/src/protocol/test.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/protocol/test.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,37 +1,51 @@ use proptest::{ - test_runner::{TestRunner, Reason}, arbitrary::{any, any_with, Arbitrary, StrategyFor}, - strategy::{Strategy, BoxedStrategy, Just, Map} + strategy::{BoxedStrategy, Just, Map, Strategy}, + test_runner::{Reason, TestRunner}, }; -use crate::server::coretypes::{GameCfg, TeamInfo, HedgehogInfo}; +use crate::server::coretypes::{GameCfg, HedgehogInfo, TeamInfo}; -use super::messages::{ - HWProtocolMessage, HWProtocolMessage::* -}; +use super::messages::{HWProtocolMessage, HWProtocolMessage::*}; // Due to inability to define From between Options -trait Into2: Sized { fn into2(self) -> T; } -impl Into2 for T { fn into2(self) -> T { self } } +trait Into2: Sized { + fn into2(self) -> T; +} +impl Into2 for T { + fn into2(self) -> T { + self + } +} impl Into2> for Vec { fn into2(self) -> Vec { self.into_iter().map(|x| x.0).collect() } } -impl Into2 for Ascii { fn into2(self) -> String { self.0 } } -impl Into2> for Option{ - fn into2(self) -> Option { self.map(|x| {x.0}) } +impl Into2 for Ascii { + fn into2(self) -> String { + self.0 + } +} +impl Into2> for Option { + fn into2(self) -> Option { + self.map(|x| x.0) + } } macro_rules! proto_msg_case { - ($val: ident()) => - (Just($val)); - ($val: ident($arg: ty)) => - (any::<$arg>().prop_map(|v| {$val(v.into2())})); - ($val: ident($arg1: ty, $arg2: ty)) => - (any::<($arg1, $arg2)>().prop_map(|v| {$val(v.0.into2(), v.1.into2())})); - ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => - (any::<($arg1, $arg2, $arg3)>().prop_map(|v| {$val(v.0.into2(), v.1.into2(), v.2.into2())})); + ($val: ident()) => { + Just($val) + }; + ($val: ident($arg: ty)) => { + any::<$arg>().prop_map(|v| $val(v.into2())) + }; + ($val: ident($arg1: ty, $arg2: ty)) => { + any::<($arg1, $arg2)>().prop_map(|v| $val(v.0.into2(), v.1.into2())) + }; + ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => { + any::<($arg1, $arg2, $arg3)>().prop_map(|v| $val(v.0.into2(), v.1.into2(), v.2.into2())) + }; } macro_rules! proto_msg_match { @@ -62,8 +76,10 @@ fn arbitrary_with(_args: ::Parameters) -> ::Strategy { use crate::server::coretypes::GameCfg::*; - (0..10).no_shrink().prop_flat_map(|i| { - proto_msg_match!(i, def = FeatureSize(0), + (0..10) + .no_shrink() + .prop_flat_map(|i| { + proto_msg_match!(i, def = FeatureSize(0), 0 => FeatureSize(u32), 1 => MapType(Ascii), 2 => MapGenerator(u32), @@ -75,7 +91,8 @@ 8 => Script(Ascii), 9 => Theme(Ascii), 10 => DrawnMap(Ascii)) - }).boxed() + }) + .boxed() } type Strategy = BoxedStrategy; @@ -85,18 +102,45 @@ type Parameters = (); fn arbitrary_with(_args: ::Parameters) -> ::Strategy { - ("[a-z]+", 0u8..127u8, "[a-z]+", "[a-z]+", "[a-z]+", "[a-z]+", 0u8..127u8) + ( + "[a-z]+", + 0u8..127u8, + "[a-z]+", + "[a-z]+", + "[a-z]+", + "[a-z]+", + 0u8..127u8, + ) .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| { fn hog(n: u8) -> HedgehogInfo { - HedgehogInfo { name: format!("hog{}", n), hat: format!("hat{}", n)} + HedgehogInfo { + name: format!("hog{}", n), + hat: format!("hat{}", n), + } } - let hedgehogs = [hog(1), hog(2), hog(3), hog(4), hog(5), hog(6), hog(7), hog(8)]; + let hedgehogs = [ + hog(1), + hog(2), + hog(3), + hog(4), + hog(5), + hog(6), + hog(7), + hog(8), + ]; TeamInfo { - name, color, grave, fort, - voice_pack, flag,difficulty, - hedgehogs, hedgehogs_number: 0 + name, + color, + grave, + fort, + voice_pack, + flag, + difficulty, + hedgehogs, + hedgehogs_number: 0, } - }).boxed() + }) + .boxed() } type Strategy = BoxedStrategy; @@ -105,64 +149,65 @@ pub fn gen_proto_msg() -> BoxedStrategy where { let res = (0..58).no_shrink().prop_flat_map(|i| { proto_msg_match!(i, def = Malformed, - 0 => Ping(), - 1 => Pong(), - 2 => Quit(Option), - //3 => Cmd - 4 => Global(Ascii), - 5 => Watch(Ascii), - 6 => ToggleServerRegisteredOnly(), - 7 => SuperPower(), - 8 => Info(Ascii), - 9 => Nick(Ascii), - 10 => Proto(u16), - 11 => Password(Ascii, Ascii), - 12 => Checker(u16, Ascii, Ascii), - 13 => List(), - 14 => Chat(Ascii), - 15 => CreateRoom(Ascii, Option), - 16 => JoinRoom(Ascii, Option), - 17 => Follow(Ascii), - 18 => Rnd(Vec), - 19 => Kick(Ascii), - 20 => Ban(Ascii, Ascii, u32), - 21 => BanIP(Ascii, Ascii, u32), - 22 => BanNick(Ascii, Ascii, u32), - 23 => BanList(), - 24 => Unban(Ascii), - //25 => SetServerVar(ServerVar), - 26 => GetServerVar(), - 27 => RestartServer(), - 28 => Stats(), - 29 => Part(Option), - 30 => Cfg(GameCfg), - 31 => AddTeam(Box), - 32 => RemoveTeam(Ascii), - 33 => SetHedgehogsNumber(Ascii, u8), - 34 => SetTeamColor(Ascii, u8), - 35 => ToggleReady(), - 36 => StartGame(), - 37 => EngineMessage(Ascii), - 38 => RoundFinished(), - 39 => ToggleRestrictJoin(), - 40 => ToggleRestrictTeams(), - 41 => ToggleRegisteredOnly(), - 42 => RoomName(Ascii), - 43 => Delegate(Ascii), - 44 => TeamChat(Ascii), - 45 => MaxTeams(u8), - 46 => Fix(), - 47 => Unfix(), - 48 => Greeting(Ascii), - //49 => CallVote(Option<(String, Option)>), - 50 => Vote(bool), - 51 => ForceVote(bool), - 52 => Save(Ascii, Ascii), - 53 => Delete(Ascii), - 54 => SaveRoom(Ascii), - 55 => LoadRoom(Ascii), - 56 => Malformed(), - 57 => Empty() - )}); + 0 => Ping(), + 1 => Pong(), + 2 => Quit(Option), + //3 => Cmd + 4 => Global(Ascii), + 5 => Watch(Ascii), + 6 => ToggleServerRegisteredOnly(), + 7 => SuperPower(), + 8 => Info(Ascii), + 9 => Nick(Ascii), + 10 => Proto(u16), + 11 => Password(Ascii, Ascii), + 12 => Checker(u16, Ascii, Ascii), + 13 => List(), + 14 => Chat(Ascii), + 15 => CreateRoom(Ascii, Option), + 16 => JoinRoom(Ascii, Option), + 17 => Follow(Ascii), + 18 => Rnd(Vec), + 19 => Kick(Ascii), + 20 => Ban(Ascii, Ascii, u32), + 21 => BanIP(Ascii, Ascii, u32), + 22 => BanNick(Ascii, Ascii, u32), + 23 => BanList(), + 24 => Unban(Ascii), + //25 => SetServerVar(ServerVar), + 26 => GetServerVar(), + 27 => RestartServer(), + 28 => Stats(), + 29 => Part(Option), + 30 => Cfg(GameCfg), + 31 => AddTeam(Box), + 32 => RemoveTeam(Ascii), + 33 => SetHedgehogsNumber(Ascii, u8), + 34 => SetTeamColor(Ascii, u8), + 35 => ToggleReady(), + 36 => StartGame(), + 37 => EngineMessage(Ascii), + 38 => RoundFinished(), + 39 => ToggleRestrictJoin(), + 40 => ToggleRestrictTeams(), + 41 => ToggleRegisteredOnly(), + 42 => RoomName(Ascii), + 43 => Delegate(Ascii), + 44 => TeamChat(Ascii), + 45 => MaxTeams(u8), + 46 => Fix(), + 47 => Unfix(), + 48 => Greeting(Ascii), + //49 => CallVote(Option<(String, Option)>), + 50 => Vote(bool), + 51 => ForceVote(bool), + 52 => Save(Ascii, Ascii), + 53 => Delete(Ascii), + 54 => SaveRoom(Ascii), + 55 => LoadRoom(Ascii), + 56 => Malformed(), + 57 => Empty() + ) + }); res.boxed() } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server.rs --- a/rust/hedgewars-server/src/server.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,10 +1,10 @@ -pub mod core; +mod actions; pub mod client; -pub mod io; -pub mod room; -pub mod network; +pub mod core; pub mod coretypes; -mod actions; -mod handlers; #[cfg(feature = "official-server")] mod database; +mod handlers; +pub mod io; +pub mod network; +pub mod room; diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/actions.rs --- a/rust/hedgewars-server/src/server/actions.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/actions.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,26 +1,17 @@ -use std::{ - io, io::Write, - iter::once, - mem::replace -}; use super::{ + client::HWClient, core::HWServer, + coretypes::{ClientId, GameCfg, RoomId, VoteType}, + handlers, + room::HWRoom, room::{GameInfo, RoomFlags}, - client::HWClient, - coretypes::{ClientId, RoomId, GameCfg, VoteType}, - room::HWRoom, - handlers }; use crate::{ - protocol::messages::{ - HWProtocolMessage, - HWServerMessage, - HWServerMessage::*, - server_chat - }, - utils::to_engine_msg + protocol::messages::{server_chat, HWProtocolMessage, HWServerMessage, HWServerMessage::*}, + utils::to_engine_msg, }; -use rand::{thread_rng, Rng, distributions::Uniform}; +use rand::{distributions::Uniform, thread_rng, Rng}; +use std::{io, io::Write, iter::once, mem::replace}; #[cfg(feature = "official-server")] use super::database; @@ -31,22 +22,28 @@ ToAll { room_id: Option, protocol: Option, - skip_self: bool - } + skip_self: bool, + }, } pub struct PendingMessage { pub destination: Destination, - pub message: HWServerMessage + pub message: HWServerMessage, } impl PendingMessage { pub fn send(message: HWServerMessage, client_id: ClientId) -> PendingMessage { - PendingMessage{ destination: Destination::ToId(client_id), message} + PendingMessage { + destination: Destination::ToId(client_id), + message, + } } pub fn send_self(message: HWServerMessage) -> PendingMessage { - PendingMessage{ destination: Destination::ToSelf, message } + PendingMessage { + destination: Destination::ToSelf, + message, + } } pub fn send_all(message: HWServerMessage) -> PendingMessage { @@ -55,41 +52,63 @@ protocol: None, skip_self: false, }; - PendingMessage{ destination, message } + PendingMessage { + destination, + message, + } } pub fn in_room(mut self, clients_room_id: RoomId) -> PendingMessage { - if let Destination::ToAll {ref mut room_id, ..} = self.destination { + if let Destination::ToAll { + ref mut room_id, .. + } = self.destination + { *room_id = Some(clients_room_id) } self } pub fn with_protocol(mut self, protocol_number: u16) -> PendingMessage { - if let Destination::ToAll {ref mut protocol, ..} = self.destination { + if let Destination::ToAll { + ref mut protocol, .. + } = self.destination + { *protocol = Some(protocol_number) } self } pub fn but_self(mut self) -> PendingMessage { - if let Destination::ToAll {ref mut skip_self, ..} = self.destination { + if let Destination::ToAll { + ref mut skip_self, .. + } = self.destination + { *skip_self = true } self } - pub fn action(self) -> Action { Send(self) } + pub fn action(self) -> Action { + Send(self) + } } impl Into for PendingMessage { - fn into(self) -> Action { self.action() } + fn into(self) -> Action { + self.action() + } } impl HWServerMessage { - pub fn send(self, client_id: ClientId) -> PendingMessage { PendingMessage::send(self, client_id) } - pub fn send_self(self) -> PendingMessage { PendingMessage::send_self(self) } - pub fn send_all(self) -> PendingMessage { PendingMessage::send_all(self) } + pub fn send(self, client_id: ClientId) -> PendingMessage { + PendingMessage::send(self, client_id) + } + pub fn send_self(self) -> PendingMessage { + PendingMessage::send_self(self) + } + pub fn send_all(self) -> PendingMessage { + PendingMessage::send_all(self) + } } pub enum Action { @@ -110,11 +129,19 @@ StartRoomGame(RoomId), SendTeamRemovalMessage(String), FinishRoomGame(RoomId), - SendRoomData{to: ClientId, teams: bool, config: bool, flags: bool}, - AddVote{vote: bool, is_forced: bool}, + SendRoomData { + to: ClientId, + teams: bool, + config: bool, + flags: bool, + }, + AddVote { + vote: bool, + is_forced: bool, + }, ApplyVoting(VoteType, RoomId), Warn(String), - ProtocolError(String) + ProtocolError(String), } use self::Action::*; @@ -126,31 +153,38 @@ let c = &server.clients[client_id]; let nick = c.nick.clone(); - if let Some(id) = c.room_id{ + if let Some(id) = c.room_id { if id != server.lobby_id { - server.react(client_id, vec![ - MoveToLobby(format!("quit: {}", msg.clone()))]); + server.react( + client_id, + vec![MoveToLobby(format!("quit: {}", msg.clone()))], + ); } } - server.react(client_id, vec![ - LobbyLeft(nick, msg.clone()).send_all().action(), - Bye(msg).send_self().action(), - RemoveClient]); - }, + server.react( + client_id, + vec![ + LobbyLeft(nick, msg.clone()).send_all().action(), + Bye(msg).send_self().action(), + RemoveClient, + ], + ); + } RemoveClient => { server.removed_clients.push(client_id); if server.clients.contains(client_id) { server.clients.remove(client_id); } - }, - ReactProtocolMessage(msg) => - handlers::handle(server, client_id, msg), + } + ReactProtocolMessage(msg) => handlers::handle(server, client_id, msg), CheckRegistered => { let client = &server.clients[client_id]; if client.protocol_number > 0 && client.nick != "" { - let has_nick_clash = server.clients.iter().any( - |(id, c)| id != client_id && c.nick == client.nick); + let has_nick_clash = server + .clients + .iter() + .any(|(id, c)| id != client_id && c.nick == client.nick); let actions = if !client.is_checker() && has_nick_clash { if client.protocol_number < 38 { @@ -164,7 +198,7 @@ }; server.react(client_id, actions); } - }, + } JoinLobby => { server.clients[client_id].room_id = Some(server.lobby_id); @@ -179,24 +213,33 @@ let everyone_msg = LobbyJoined(vec![server.clients[client_id].nick.clone()]); let flags_msg = ClientFlags( "+i".to_string(), - server.clients.iter() + server + .clients + .iter() .filter(|(_, c)| c.room_id.is_some()) .map(|(_, c)| c.nick.clone()) - .collect()); + .collect(), + ); let server_msg = ServerMessage("\u{1f994} is watching".to_string()); - let rooms_msg = Rooms(server.rooms.iter() - .filter(|(id, _)| *id != server.lobby_id) - .flat_map(|(_, r)| - r.info(r.master_id.map(|id| &server.clients[id]))) - .collect()); - server.react(client_id, vec![ - everyone_msg.send_all().but_self().action(), - joined_msg.send_self().action(), - flags_msg.send_self().action(), - server_msg.send_self().action(), - rooms_msg.send_self().action(), - ]); - }, + let rooms_msg = Rooms( + server + .rooms + .iter() + .filter(|(id, _)| *id != server.lobby_id) + .flat_map(|(_, r)| r.info(r.master_id.map(|id| &server.clients[id]))) + .collect(), + ); + server.react( + client_id, + vec![ + everyone_msg.send_all().but_self().action(), + joined_msg.send_self().action(), + flags_msg.send_self().action(), + server_msg.send_self().action(), + rooms_msg.send_self().action(), + ], + ); + } AddRoom(name, password) => { let room_id = server.add_room();; @@ -208,16 +251,21 @@ r.protocol_number = c.protocol_number; let actions = vec![ - RoomAdd(r.info(Some(&c))).send_all() - .with_protocol(r.protocol_number).action(), - MoveToRoom(room_id)]; + RoomAdd(r.info(Some(&c))) + .send_all() + .with_protocol(r.protocol_number) + .action(), + MoveToRoom(room_id), + ]; server.react(client_id, actions); - }, + } RemoveRoom(room_id) => { let r = &mut server.rooms[room_id]; - let actions = vec![RoomRemove(r.name.clone()).send_all() - .with_protocol(r.protocol_number).action()]; + let actions = vec![RoomRemove(r.name.clone()) + .send_all() + .with_protocol(r.protocol_number) + .action()]; server.rooms.remove(room_id); server.react(client_id, actions); } @@ -237,13 +285,25 @@ } let mut v = vec![ - RoomJoined(vec![c.nick.clone()]).send_all().in_room(room_id).action(), - ClientFlags("+i".to_string(), vec![c.nick.clone()]).send_all().action(), - SendRoomUpdate(None)]; + RoomJoined(vec![c.nick.clone()]) + .send_all() + .in_room(room_id) + .action(), + ClientFlags("+i".to_string(), vec![c.nick.clone()]) + .send_all() + .action(), + SendRoomUpdate(None), + ]; if !r.greeting.is_empty() { - v.push(ChatMsg {nick: "[greeting]".to_string(), msg: r.greeting.clone()} - .send_self().action()); + v.push( + ChatMsg { + nick: "[greeting]".to_string(), + msg: r.greeting.clone(), + } + .send_self() + .action(), + ); } if !c.is_master() { @@ -260,49 +320,82 @@ } if !team_names.is_empty() { - info.left_teams.retain(|name| - !team_names.contains(&name)); + info.left_teams.retain(|name| !team_names.contains(&name)); info.teams_in_game += team_names.len() as u8; - r.teams = info.teams_at_start.iter() + r.teams = info + .teams_at_start + .iter() .filter(|(_, t)| !team_names.contains(&t.name)) - .cloned().collect(); + .cloned() + .collect(); } } else { team_names = Vec::new(); } - v.push(SendRoomData{ to: client_id, teams: true, config: true, flags: true}); + v.push(SendRoomData { + to: client_id, + teams: true, + config: true, + flags: true, + }); if let Some(ref info) = r.game_info { v.push(RunGame.send_self().action()); - v.push(ClientFlags("+g".to_string(), vec![c.nick.clone()]) - .send_all().in_room(r.id).action()); - v.push(ForwardEngineMessage( - vec![to_engine_msg("e$spectate 1".bytes())]) - .send_self().action()); - v.push(ForwardEngineMessage(info.msg_log.clone()) - .send_self().action()); + v.push( + ClientFlags("+g".to_string(), vec![c.nick.clone()]) + .send_all() + .in_room(r.id) + .action(), + ); + v.push( + ForwardEngineMessage(vec![to_engine_msg("e$spectate 1".bytes())]) + .send_self() + .action(), + ); + v.push( + ForwardEngineMessage(info.msg_log.clone()) + .send_self() + .action(), + ); for name in &team_names { - v.push(ForwardEngineMessage( - vec![to_engine_msg(once(b'G').chain(name.bytes()))]) - .send_all().in_room(r.id).action()); + v.push( + ForwardEngineMessage(vec![to_engine_msg( + once(b'G').chain(name.bytes()), + )]) + .send_all() + .in_room(r.id) + .action(), + ); } if info.is_paused { - v.push(ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) - .send_all().in_room(r.id).action()) + v.push( + ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) + .send_all() + .in_room(r.id) + .action(), + ) } } } server.react(client_id, v); } - SendRoomData {to, teams, config, flags} => { + SendRoomData { + to, + teams, + config, + flags, + } => { let mut actions = Vec::new(); let room_id = server.clients[client_id].room_id; if let Some(r) = room_id.and_then(|id| server.rooms.get(id)) { if config { - actions.push(ConfigEntry("FULLMAPCONFIG".to_string(), r.map_config()) - .send(to).action()); + actions.push( + ConfigEntry("FULLMAPCONFIG".to_string(), r.map_config()) + .send(to) + .action(), + ); for cfg in r.game_config() { actions.push(cfg.to_server_msg().send(to).action()); } @@ -310,41 +403,54 @@ if teams { let current_teams = match r.game_info { Some(ref info) => &info.teams_at_start, - None => &r.teams + None => &r.teams, }; for (owner_id, team) in current_teams.iter() { - actions.push(TeamAdd(HWRoom::team_info(&server.clients[*owner_id], &team)) - .send(to).action()); - actions.push(TeamColor(team.name.clone(), team.color) - .send(to).action()); - actions.push(HedgehogsNumber(team.name.clone(), team.hedgehogs_number) - .send(to).action()); + actions.push( + TeamAdd(HWRoom::team_info(&server.clients[*owner_id], &team)) + .send(to) + .action(), + ); + actions.push(TeamColor(team.name.clone(), team.color).send(to).action()); + actions.push( + HedgehogsNumber(team.name.clone(), team.hedgehogs_number) + .send(to) + .action(), + ); } } if flags { if let Some(id) = r.master_id { - actions.push(ClientFlags("+h".to_string(), vec![server.clients[id].nick.clone()]) - .send(to).action()); + actions.push( + ClientFlags("+h".to_string(), vec![server.clients[id].nick.clone()]) + .send(to) + .action(), + ); } - let nicks: Vec<_> = server.clients.iter() + let nicks: Vec<_> = server + .clients + .iter() .filter(|(_, c)| c.room_id == Some(r.id) && c.is_ready()) - .map(|(_, c)| c.nick.clone()).collect(); + .map(|(_, c)| c.nick.clone()) + .collect(); if !nicks.is_empty() { - actions.push(ClientFlags("+r".to_string(), nicks) - .send(to).action()); + actions.push(ClientFlags("+r".to_string(), nicks).send(to).action()); } } } server.react(client_id, actions); } - AddVote{vote, is_forced} => { + AddVote { vote, is_forced } => { let mut actions = Vec::new(); if let Some(r) = server.room(client_id) { let mut result = None; if let Some(ref mut voting) = r.voting { if is_forced || voting.votes.iter().all(|(id, _)| client_id != *id) { - actions.push(server_chat("Your vote has been counted.".to_string()) - .send_self().action()); + actions.push( + server_chat("Your vote has been counted.".to_string()) + .send_self() + .action(), + ); voting.votes.push((client_id, vote)); let i = voting.votes.iter(); let pro = i.clone().filter(|(_, v)| *v).count(); @@ -352,21 +458,32 @@ let success_quota = voting.voters.len() / 2 + 1; if is_forced && vote || pro >= success_quota { result = Some(true); - } else if is_forced && !vote || contra > voting.voters.len() - success_quota { + } else if is_forced && !vote || contra > voting.voters.len() - success_quota + { result = Some(false); } } else { - actions.push(server_chat("You already have voted.".to_string()) - .send_self().action()); + actions.push( + server_chat("You already have voted.".to_string()) + .send_self() + .action(), + ); } } else { - actions.push(server_chat("There's no voting going on.".to_string()) - .send_self().action()); + actions.push( + server_chat("There's no voting going on.".to_string()) + .send_self() + .action(), + ); } if let Some(res) = result { - actions.push(server_chat("Voting closed.".to_string()) - .send_all().in_room(r.id).action()); + actions.push( + server_chat("Voting closed.".to_string()) + .send_all() + .in_room(r.id) + .action(), + ); let voting = replace(&mut r.voting, None).unwrap(); if res { actions.push(ApplyVoting(voting.kind, r.id)); @@ -388,44 +505,62 @@ actions.push(MoveToLobby("kicked".to_string())); } } - }, + } VoteType::Map(None) => (), VoteType::Map(Some(name)) => { if let Some(location) = server.rooms[room_id].load_config(&name) { - actions.push(server_chat(location.to_string()) - .send_all().in_room(room_id).action()); + actions.push( + server_chat(location.to_string()) + .send_all() + .in_room(room_id) + .action(), + ); actions.push(SendRoomUpdate(None)); for (_, c) in server.clients.iter() { if c.room_id == Some(room_id) { - actions.push(SendRoomData{ - to: c.id, teams: false, - config: true, flags: false}) + actions.push(SendRoomData { + to: c.id, + teams: false, + config: true, + flags: false, + }) } } } - }, + } VoteType::Pause => { if let Some(ref mut info) = server.rooms[room_id].game_info { info.is_paused = !info.is_paused; - actions.push(server_chat("Pause toggled.".to_string()) - .send_all().in_room(room_id).action()); - actions.push(ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) - .send_all().in_room(room_id).action()); + actions.push( + server_chat("Pause toggled.".to_string()) + .send_all() + .in_room(room_id) + .action(), + ); + actions.push( + ForwardEngineMessage(vec![to_engine_msg(once(b'I'))]) + .send_all() + .in_room(room_id) + .action(), + ); } - }, + } VoteType::NewSeed => { let seed = thread_rng().gen_range(0, 1_000_000_000).to_string(); let cfg = GameCfg::Seed(seed); actions.push(cfg.to_server_msg().send_all().in_room(room_id).action()); server.rooms[room_id].set_config(cfg); - }, + } VoteType::HedgehogsPerTeam(number) => { let r = &mut server.rooms[room_id]; let nicks = r.set_hedgehogs_number(number); - actions.extend(nicks.into_iter().map(|n| - HedgehogsNumber(n, number).send_all().in_room(room_id).action() - )); - }, + actions.extend(nicks.into_iter().map(|n| { + HedgehogsNumber(n, number) + .send_all() + .in_room(room_id) + .action() + })); + } } server.react(id, actions); } @@ -440,8 +575,11 @@ if c.is_master() && (r.players_number > 0 || r.is_fixed()) { actions.push(ChangeMaster(r.id, None)); } - actions.push(ClientFlags("-i".to_string(), vec![c.nick.clone()]) - .send_all().action()); + actions.push( + ClientFlags("-i".to_string(), vec![c.nick.clone()]) + .send_all() + .action(), + ); } server.react(client_id, actions); actions = Vec::new(); @@ -452,8 +590,13 @@ actions.push(RemoveRoom(r.id)); } else { actions.push(RemoveClientTeams); - actions.push(RoomLeft(c.nick.clone(), msg) - .send_all().in_room(r.id).but_self().action()); + actions.push( + RoomLeft(c.nick.clone(), msg) + .send_all() + .in_room(r.id) + .but_self() + .action(), + ); actions.push(SendRoomUpdate(Some(r.name.clone()))); } } @@ -462,11 +605,14 @@ ChangeMaster(room_id, new_id) => { let mut actions = Vec::new(); let room_client_ids = server.room_clients(room_id); - let new_id = if server.room(client_id).map(|r| r.is_fixed()).unwrap_or(false) { + let new_id = if server + .room(client_id) + .map(|r| r.is_fixed()) + .unwrap_or(false) + { new_id } else { - new_id.or_else(|| - room_client_ids.iter().find(|id| **id != client_id).cloned()) + new_id.or_else(|| room_client_ids.iter().find(|id| **id != client_id).cloned()) }; let new_nick = new_id.map(|id| server.clients[id].nick.clone()); @@ -475,23 +621,32 @@ Some(id) if id == c.id => { c.set_is_master(false); r.master_id = None; - actions.push(ClientFlags("-h".to_string(), vec![c.nick.clone()]) - .send_all().in_room(r.id).action()); + actions.push( + ClientFlags("-h".to_string(), vec![c.nick.clone()]) + .send_all() + .in_room(r.id) + .action(), + ); } Some(_) => unreachable!(), None => {} } r.master_id = new_id; if !r.is_fixed() && c.protocol_number < 42 { - r.name.replace_range(.., new_nick.as_ref().map_or("[]", String::as_str)); + r.name + .replace_range(.., new_nick.as_ref().map_or("[]", String::as_str)); } r.set_join_restriction(false); r.set_team_add_restriction(false); let is_fixed = r.is_fixed(); r.set_unregistered_players_restriction(is_fixed); if let Some(nick) = new_nick { - actions.push(ClientFlags("+h".to_string(), vec![nick]) - .send_all().in_room(r.id).action()); + actions.push( + ClientFlags("+h".to_string(), vec![nick]) + .send_all() + .in_room(r.id) + .action(), + ); } } if let Some(id) = new_id { @@ -513,10 +668,13 @@ } } server.react(client_id, actions); - }, + } RemoveClientTeams => { if let (c, Some(r)) = server.client_and_room(client_id) { - let actions = r.client_teams(c.id).map(|t| RemoveTeam(t.name.clone())).collect(); + let actions = r + .client_teams(c.id) + .map(|t| RemoveTeam(t.name.clone())) + .collect(); server.react(client_id, actions); } } @@ -524,19 +682,28 @@ if let (c, Some(r)) = server.client_and_room(client_id) { let name = old_name.unwrap_or_else(|| r.name.clone()); let actions = vec![RoomUpdated(name, r.info(Some(&c))) - .send_all().with_protocol(r.protocol_number).action()]; + .send_all() + .with_protocol(r.protocol_number) + .action()]; server.react(client_id, actions); } - }, + } StartRoomGame(room_id) => { let actions = { - let (room_clients, room_nicks): (Vec<_>, Vec<_>) = server.clients.iter() - .map(|(id, c)| (id, c.nick.clone())).unzip(); + let (room_clients, room_nicks): (Vec<_>, Vec<_>) = server + .clients + .iter() + .map(|(id, c)| (id, c.nick.clone())) + .unzip(); let room = &mut server.rooms[room_id]; if !room.has_multiple_clans() { - vec![Warn("The game can't be started with less than two clans!".to_string())] - } else if room.protocol_number <= 43 && room.players_number != room.ready_players_number { + vec![Warn( + "The game can't be started with less than two clans!".to_string(), + )] + } else if room.protocol_number <= 43 + && room.players_number != room.ready_players_number + { vec![Warn("Not all players are ready".to_string())] } else if room.game_info.is_some() { vec![Warn("The game is already in progress".to_string())] @@ -547,10 +714,14 @@ c.set_is_in_game(false); c.team_indices = room.client_team_indices(c.id); } - vec![RunGame.send_all().in_room(room.id).action(), - SendRoomUpdate(None), - ClientFlags("+g".to_string(), room_nicks) - .send_all().in_room(room.id).action()] + vec![ + RunGame.send_all().in_room(room.id).action(), + SendRoomUpdate(None), + ClientFlags("+g".to_string(), room_nicks) + .send_all() + .in_room(room.id) + .action(), + ] } }; server.react(client_id, actions); @@ -560,8 +731,13 @@ if let Some(r) = server.room(client_id) { if let Some(ref mut info) = r.game_info { let msg = once(b'F').chain(team_name.bytes()); - actions.push(ForwardEngineMessage(vec![to_engine_msg(msg)]). - send_all().in_room(r.id).but_self().action()); + actions.push( + ForwardEngineMessage(vec![to_engine_msg(msg)]) + .send_all() + .in_room(r.id) + .but_self() + .action(), + ); info.teams_in_game -= 1; if info.teams_in_game == 0 { actions.push(FinishRoomGame(r.id)); @@ -574,8 +750,13 @@ info.sync_msg = None } info.msg_log.push(remove_msg.clone()); - actions.push(ForwardEngineMessage(vec![remove_msg]) - .send_all().in_room(r.id).but_self().action()); + actions.push( + ForwardEngineMessage(vec![remove_msg]) + .send_all() + .in_room(r.id) + .but_self() + .action(), + ); } } server.react(client_id, actions); @@ -591,28 +772,36 @@ if let Some(info) = replace(&mut r.game_info, None) { for (_, c) in server.clients.iter() { if c.room_id == Some(room_id) && c.is_joined_mid_game() { - actions.push(SendRoomData{ - to: c.id, teams: false, - config: true, flags: false}); + actions.push(SendRoomData { + to: c.id, + teams: false, + config: true, + flags: false, + }); for name in &info.left_teams { - actions.push(TeamRemove(name.clone()) - .send(c.id).action()); + actions.push(TeamRemove(name.clone()).send(c.id).action()); } } } } - let nicks: Vec<_> = server.clients.iter_mut() + let nicks: Vec<_> = server + .clients + .iter_mut() .filter(|(_, c)| c.room_id == Some(room_id)) .map(|(_, c)| { c.set_is_ready(c.is_master()); c.set_is_joined_mid_game(false); c - }).filter_map(|c| if !c.is_master() { - Some(c.nick.clone()) - } else { - None - }).collect(); + }) + .filter_map(|c| { + if !c.is_master() { + Some(c.nick.clone()) + } else { + None + } + }) + .collect(); if !nicks.is_empty() { let msg = if r.protocol_number < 38 { @@ -627,8 +816,6 @@ Warn(msg) => { run_action(server, client_id, Warning(msg).send_self().action()); } - ProtocolError(msg) => { - run_action(server, client_id, Error(msg).send_self().action()) - } + ProtocolError(msg) => run_action(server, client_id, Error(msg).send_self().action()), } } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/client.rs --- a/rust/hedgewars-server/src/server/client.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/client.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,7 +1,7 @@ use super::coretypes::ClientId; use bitflags::*; -bitflags!{ +bitflags! { pub struct ClientFlags: u8 { const IS_ADMIN = 0b0000_0001; const IS_MASTER = 0b0000_0010; @@ -25,7 +25,7 @@ pub flags: ClientFlags, pub teams_in_game: u8, pub team_indices: Vec, - pub clan: Option + pub clan: Option, } impl HWClient { @@ -44,7 +44,7 @@ } } - fn contains(& self, mask: ClientFlags) -> bool { + fn contains(&self, mask: ClientFlags) -> bool { self.flags.contains(mask) } @@ -52,17 +52,41 @@ self.flags.set(mask, value); } - pub fn is_admin(&self)-> bool { self.contains(ClientFlags::IS_ADMIN) } - pub fn is_master(&self)-> bool { self.contains(ClientFlags::IS_MASTER) } - pub fn is_ready(&self)-> bool { self.contains(ClientFlags::IS_READY) } - pub fn is_in_game(&self)-> bool { self.contains(ClientFlags::IS_IN_GAME) } - pub fn is_joined_mid_game(&self)-> bool { self.contains(ClientFlags::IS_JOINED_MID_GAME) } - pub fn is_checker(&self)-> bool { self.contains(ClientFlags::IS_CHECKER) } + pub fn is_admin(&self) -> bool { + self.contains(ClientFlags::IS_ADMIN) + } + pub fn is_master(&self) -> bool { + self.contains(ClientFlags::IS_MASTER) + } + pub fn is_ready(&self) -> bool { + self.contains(ClientFlags::IS_READY) + } + pub fn is_in_game(&self) -> bool { + self.contains(ClientFlags::IS_IN_GAME) + } + pub fn is_joined_mid_game(&self) -> bool { + self.contains(ClientFlags::IS_JOINED_MID_GAME) + } + pub fn is_checker(&self) -> bool { + self.contains(ClientFlags::IS_CHECKER) + } - pub fn set_is_admin(&mut self, value: bool) { self.set(ClientFlags::IS_ADMIN, value) } - pub fn set_is_master(&mut self, value: bool) { self.set(ClientFlags::IS_MASTER, value) } - pub fn set_is_ready(&mut self, value: bool) { self.set(ClientFlags::IS_READY, value) } - pub fn set_is_in_game(&mut self, value: bool) { self.set(ClientFlags::IS_IN_GAME, value) } - pub fn set_is_joined_mid_game(&mut self, value: bool) { self.set(ClientFlags::IS_JOINED_MID_GAME, value) } - pub fn set_is_checker(&mut self, value: bool) { self.set(ClientFlags::IS_CHECKER, value) } -} \ No newline at end of file + pub fn set_is_admin(&mut self, value: bool) { + self.set(ClientFlags::IS_ADMIN, value) + } + pub fn set_is_master(&mut self, value: bool) { + self.set(ClientFlags::IS_MASTER, value) + } + pub fn set_is_ready(&mut self, value: bool) { + self.set(ClientFlags::IS_READY, value) + } + pub fn set_is_in_game(&mut self, value: bool) { + self.set(ClientFlags::IS_IN_GAME, value) + } + pub fn set_is_joined_mid_game(&mut self, value: bool) { + self.set(ClientFlags::IS_JOINED_MID_GAME, value) + } + pub fn set_is_checker(&mut self, value: bool) { + self.set(ClientFlags::IS_CHECKER, value) + } +} diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/core.rs --- a/rust/hedgewars-server/src/server/core.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/core.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,15 +1,18 @@ -use slab; -use crate::utils; use super::{ + actions, + actions::{Destination, PendingMessage}, + client::HWClient, + coretypes::{ClientId, RoomId}, + handlers, io::HWServerIO, - client::HWClient, room::HWRoom, actions, handlers, - coretypes::{ClientId, RoomId}, - actions::{Destination, PendingMessage} + room::HWRoom, }; use crate::protocol::messages::*; -use rand::{RngCore, thread_rng}; -use base64::{encode}; +use crate::utils; +use base64::encode; use log::*; +use rand::{thread_rng, RngCore}; +use slab; type Slab = slab::Slab; @@ -19,7 +22,7 @@ pub lobby_id: RoomId, pub output: Vec<(Vec, HWServerMessage)>, pub removed_clients: Vec, - pub io: Box + pub io: Box, } impl HWServer { @@ -27,11 +30,12 @@ let rooms = Slab::with_capacity(rooms_limit); let clients = Slab::with_capacity(clients_limit); let mut server = HWServer { - clients, rooms, + clients, + rooms, lobby_id: 0, output: vec![], removed_clients: vec![], - io + io, }; server.lobby_id = server.add_room(); server @@ -48,13 +52,20 @@ let client = HWClient::new(entry.key(), encode(&salt)); entry.insert(client); } - self.send(key, &Destination::ToSelf, HWServerMessage::Connected(utils::PROTOCOL_VERSION)); + self.send( + key, + &Destination::ToSelf, + HWServerMessage::Connected(utils::PROTOCOL_VERSION), + ); key } pub fn client_lost(&mut self, client_id: ClientId) { - actions::run_action(self, client_id, - actions::Action::ByeClient("Connection reset".to_string())); + actions::run_action( + self, + client_id, + actions::Action::ByeClient("Connection reset".to_string()), + ); } pub fn add_room(&mut self) -> RoomId { @@ -76,14 +87,19 @@ 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::>() + 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::>(), }; - if let Destination::ToAll {skip_self: true, ..} = destination { + if let Destination::ToAll { + skip_self: true, .. + } = destination + { if let Some(index) = ids.iter().position(|id| *id == client_id) { ids.remove(index); } @@ -91,7 +107,12 @@ ids } - pub fn send(&mut self, client_id: ClientId, destination: &Destination, message: HWServerMessage) { + 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)); } @@ -102,32 +123,43 @@ } } - pub fn lobby(&self) -> &HWRoom { &self.rooms[self.lobby_id] } + pub fn lobby(&self) -> &HWRoom { + &self.rooms[self.lobby_id] + } pub fn has_room(&self, name: &str) -> bool { self.rooms.iter().any(|(_, r)| r.name == name) } pub fn find_room(&self, name: &str) -> Option<&HWRoom> { - self.rooms.iter().find_map(|(_, r)| Some(r).filter(|r| r.name == name)) + self.rooms + .iter() + .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) } pub fn find_room_mut(&mut self, name: &str) -> Option<&mut HWRoom> { - self.rooms.iter_mut().find_map(|(_, r)| Some(r).filter(|r| r.name == name)) + self.rooms + .iter_mut() + .find_map(|(_, r)| Some(r).filter(|r| r.name == name)) } pub fn find_client(&self, nick: &str) -> Option<&HWClient> { - self.clients.iter().find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) + self.clients + .iter() + .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) } pub fn find_client_mut(&mut self, nick: &str) -> Option<&mut HWClient> { - self.clients.iter_mut().find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) + self.clients + .iter_mut() + .find_map(|(_, c)| Some(c).filter(|c| c.nick == nick)) } pub fn select_clients(&self, f: F) -> Vec - where F: Fn(&(usize, &HWClient)) -> bool { - self.clients.iter().filter(f) - .map(|(_, c)| c.id).collect() + where + F: Fn(&(usize, &HWClient)) -> bool, + { + self.clients.iter().filter(f).map(|(_, c)| c.id).collect() } pub fn room_clients(&self, room_id: RoomId) -> Vec { @@ -140,7 +172,7 @@ pub fn other_clients_in_room(&self, self_id: ClientId) -> Vec { let room_id = self.clients[self_id].room_id; - self.select_clients(|(id, c)| *id != self_id && c.room_id == room_id ) + self.select_clients(|(id, c)| *id != self_id && c.room_id == room_id) } pub fn client_and_room(&mut self, client_id: ClientId) -> (&mut HWClient, Option<&mut HWRoom>) { diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/coretypes.rs --- a/rust/hedgewars-server/src/server/coretypes.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/coretypes.rs Sun Dec 16 00:12:29 2018 +0100 @@ -23,7 +23,7 @@ Scheme(String, Vec), Script(String), Theme(String), - DrawnMap(String) + DrawnMap(String), } #[derive(PartialEq, Eq, Clone, Debug)] @@ -51,7 +51,7 @@ Map(Option), Pause, NewSeed, - HedgehogsPerTeam(u8) + HedgehogsPerTeam(u8), } #[derive(Clone, Debug)] @@ -59,14 +59,16 @@ pub ttl: u32, pub voters: Vec, pub votes: Vec<(ClientId, bool)>, - pub kind: VoteType + pub kind: VoteType, } impl Voting { pub fn new(kind: VoteType, voters: Vec) -> Voting { Voting { - kind, voters, ttl: 2, - votes: Vec::new() + kind, + voters, + ttl: 2, + votes: Vec::new(), } } -} \ No newline at end of file +} diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/database.rs --- a/rust/hedgewars-server/src/server/database.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/database.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,5 +1,5 @@ use mysql; -use mysql::{params, error::Error, error::DriverError}; +use mysql::{error::DriverError, error::Error, params}; struct AccountInfo { is_registered: bool, @@ -46,17 +46,24 @@ fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> { if let Some(pool) = &self.pool { - for mut stmt in pool.prepare(r"INSERT INTO gameserver_stats (players, rooms, last_update) VALUES (:players, :rooms, UNIX_TIMESTAMP())").into_iter() { - stmt.execute(params!{ - "players" => stats.players, - "rooms" => stats.rooms, - })?; - } + for mut stmt in pool + .prepare( + r"INSERT INTO gameserver_stats + (players, rooms, last_update) + VALUES + (:players, :rooms, UNIX_TIMESTAMP())", + ) + .into_iter() + { + stmt.execute(params! { + "players" => stats.players, + "rooms" => stats.rooms, + })?; + } Ok(()) } else { Err(DriverError::SetupError.into()) } - } fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> { diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers.rs --- a/rust/hedgewars-server/src/server/handlers.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers.rs Sun Dec 16 00:12:29 2018 +0100 @@ -2,43 +2,34 @@ use std::{io, io::Write}; use super::{ + actions::{Action, Action::*}, core::HWServer, - actions::{Action, Action::*}, - coretypes::ClientId + coretypes::ClientId, }; -use crate::{ - protocol::messages::{ - HWProtocolMessage, - HWServerMessage::* - } -}; +use crate::protocol::messages::{HWProtocolMessage, HWServerMessage::*}; use log::*; -mod loggingin; -mod lobby; +mod checker; +mod common; mod inroom; -mod common; -mod checker; +mod lobby; +mod loggingin; pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) { match message { - HWProtocolMessage::Ping => - server.react(client_id, vec![Pong.send_self().action()]), - HWProtocolMessage::Quit(Some(msg)) => - server.react(client_id, vec![ByeClient("User quit: ".to_string() + &msg)]), - HWProtocolMessage::Quit(None) => - server.react(client_id, vec![ByeClient("User quit".to_string())]), + HWProtocolMessage::Ping => server.react(client_id, vec![Pong.send_self().action()]), + HWProtocolMessage::Quit(Some(msg)) => { + server.react(client_id, vec![ByeClient("User quit: ".to_string() + &msg)]) + } + HWProtocolMessage::Quit(None) => { + server.react(client_id, vec![ByeClient("User quit".to_string())]) + } HWProtocolMessage::Malformed => warn!("Malformed/unknown message"), HWProtocolMessage::Empty => warn!("Empty message"), - _ => { - match server.clients[client_id].room_id { - None => - loggingin::handle(server, client_id, message), - Some(id) if id == server.lobby_id => - lobby::handle(server, client_id, message), - Some(id) => - inroom::handle(server, client_id, id, message) - } + _ => match server.clients[client_id].room_id { + None => loggingin::handle(server, client_id, message), + Some(id) if id == server.lobby_id => lobby::handle(server, client_id, message), + Some(id) => inroom::handle(server, client_id, id, message), }, } } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers/checker.rs --- a/rust/hedgewars-server/src/server/handlers/checker.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers/checker.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,17 +1,12 @@ +use log::*; use mio; -use log::*; use crate::{ - server::{ - core::HWServer, - coretypes::ClientId, - }, - protocol::messages::{ - HWProtocolMessage - }, + protocol::messages::HWProtocolMessage, + server::{core::HWServer, coretypes::ClientId}, }; -pub fn handle(server: & mut HWServer, client_id: ClientId, message: HWProtocolMessage) { +pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) { match message { _ => warn!("Unknown command"), } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers/common.rs --- a/rust/hedgewars-server/src/server/handlers/common.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers/common.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,10 +1,11 @@ use crate::{ - server::{actions::Action, core::HWServer}, protocol::messages::{ - HWProtocolMessage::{self, Rnd}, HWServerMessage::{self, ChatMsg}, - } + HWProtocolMessage::{self, Rnd}, + HWServerMessage::{self, ChatMsg}, + }, + server::{actions::Action, core::HWServer}, }; -use rand::{self, Rng, thread_rng}; +use rand::{self, thread_rng, Rng}; pub fn rnd_reply(options: &[String]) -> HWServerMessage { let mut rng = thread_rng(); @@ -25,7 +26,8 @@ use super::*; use crate::protocol::messages::HWServerMessage::ChatMsg; use crate::server::actions::{ - Action::{self, Send}, PendingMessage, + Action::{self, Send}, + PendingMessage, }; fn reply2string(r: HWServerMessage) -> String { diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers/inroom.rs --- a/rust/hedgewars-server/src/server/handlers/inroom.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers/inroom.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,36 +1,27 @@ use mio; +use super::common::rnd_reply; use crate::{ + protocol::messages::{server_chat, HWProtocolMessage, HWServerMessage::*}, server::{ - coretypes::{ - ClientId, RoomId, Voting, VoteType, GameCfg, - MAX_HEDGEHOGS_PER_TEAM - }, + actions::{Action, Action::*}, core::HWServer, + coretypes::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM}, room::{HWRoom, RoomFlags}, - actions::{Action, Action::*} }, - protocol::messages::{ - HWProtocolMessage, - HWServerMessage::*, - server_chat - }, - utils::is_name_illegal + utils::is_name_illegal, }; -use std::{ - mem::swap -}; -use base64::{encode, decode}; -use super::common::rnd_reply; +use base64::{decode, encode}; use log::*; +use std::mem::swap; #[derive(Clone)] struct ByMsg<'a> { - messages: &'a[u8] + messages: &'a [u8], } -impl <'a> Iterator for ByMsg<'a> { - type Item = &'a[u8]; +impl<'a> Iterator for ByMsg<'a> { + type Item = &'a [u8]; fn next(&mut self) -> Option<::Item> { if let Some(size) = self.messages.get(0) { @@ -44,7 +35,7 @@ } fn by_msg(source: &[u8]) -> ByMsg { - ByMsg {messages: source} + ByMsg { messages: source } } const VALID_MESSAGES: &[u8] = @@ -54,13 +45,16 @@ #[cfg(canhazslicepatterns)] fn is_msg_valid(msg: &[u8], team_indices: &[u8]) -> bool { match msg { - [size, typ, body..] => VALID_MESSAGES.contains(typ) - && match body { - [1...MAX_HEDGEHOGS_PER_TEAM, team, ..] if *typ == b'h' => - team_indices.contains(team), - _ => *typ != b'h' - }, - _ => false + [size, typ, body..] => { + VALID_MESSAGES.contains(typ) + && match body { + [1...MAX_HEDGEHOGS_PER_TEAM, team, ..] if *typ == b'h' => { + team_indices.contains(team) + } + _ => *typ != b'h', + } + } + _ => false, } } @@ -77,17 +71,22 @@ } fn is_msg_timed(msg: &[u8]) -> bool { - msg.get(1).filter(|t| !NON_TIMED_MESSAGES.contains(t)).is_some() + msg.get(1) + .filter(|t| !NON_TIMED_MESSAGES.contains(t)) + .is_some() } fn voting_description(kind: &VoteType) -> String { - format!("New voting started: {}", match kind { - VoteType::Kick(nick) => format!("kick {}", nick), - VoteType::Map(name) => format!("map {}", name.as_ref().unwrap()), - VoteType::Pause => "pause".to_string(), - VoteType::NewSeed => "new seed".to_string(), - VoteType::HedgehogsPerTeam(number) => format!("hedgehogs per team: {}", number) - }) + format!( + "New voting started: {}", + match kind { + VoteType::Kick(nick) => format!("kick {}", nick), + VoteType::Map(name) => format!("map {}", name.as_ref().unwrap()), + VoteType::Pause => "pause".to_string(), + VoteType::NewSeed => "new seed".to_string(), + VoteType::HedgehogsPerTeam(number) => format!("hedgehogs per team: {}", number), + } + ) } fn room_message_flag(msg: &HWProtocolMessage) -> RoomFlags { @@ -96,11 +95,16 @@ ToggleRestrictJoin => RoomFlags::RESTRICTED_JOIN, ToggleRestrictTeams => RoomFlags::RESTRICTED_TEAM_ADD, ToggleRegisteredOnly => RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS, - _ => RoomFlags::empty() + _ => RoomFlags::empty(), } } -pub fn handle(server: &mut HWServer, client_id: ClientId, room_id: RoomId, message: HWProtocolMessage) { +pub fn handle( + server: &mut HWServer, + client_id: ClientId, + room_id: RoomId, + message: HWProtocolMessage, +) { use crate::protocol::messages::HWProtocolMessage::*; match message { Part(None) => server.react(client_id, vec![ diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers/lobby.rs --- a/rust/hedgewars-server/src/server/handlers/lobby.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers/lobby.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,47 +1,53 @@ use mio; +use super::common::rnd_reply; use crate::{ + protocol::messages::{HWProtocolMessage, HWServerMessage::*}, server::{ + actions::{Action, Action::*}, core::HWServer, coretypes::ClientId, - actions::{Action, Action::*} }, - protocol::messages::{ - HWProtocolMessage, - HWServerMessage::* - }, - utils::is_name_illegal + utils::is_name_illegal, }; -use super::common::rnd_reply; use log::*; pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) { 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())] - } else if server.has_room(&name) { - vec![Warn("A room with the same name already exists.".to_string())] - } else { - let flags_msg = ClientFlags( - "+hr".to_string(), - vec![server.clients[client_id].nick.clone()]); - vec![AddRoom(name, password), - flags_msg.send_self().action()] - }; + 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())] + } else if server.has_room(&name) { + vec![Warn( + "A room with the same name already exists.".to_string(), + )] + } else { + let flags_msg = ClientFlags( + "+hr".to_string(), + vec![server.clients[client_id].nick.clone()], + ); + vec![AddRoom(name, password), flags_msg.send_self().action()] + }; 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()]; + 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); - }, + } JoinRoom(name, _password) => { let room = server.rooms.iter().find(|(_, r)| r.name == name); let room_id = room.map(|(_, r)| r.id); - let nicks = server.clients.iter() + let nicks = server + .clients + .iter() .filter(|(_, c)| c.room_id == room_id) .map(|(_, c)| c.nick.clone()) .collect(); @@ -49,23 +55,26 @@ let actions = if let Some((_, r)) = room { if c.protocol_number != r.protocol_number { - vec![Warn("Room version incompatible to your Hedgewars version!".to_string())] + vec![Warn( + "Room version incompatible to your Hedgewars version!".to_string(), + )] } else if r.is_join_restricted() { - vec![Warn("Access denied. This room currently doesn't allow joining.".to_string())] + vec![Warn( + "Access denied. This room currently doesn't allow joining.".to_string(), + )] } else if r.players_number == u8::max_value() { vec![Warn("This room is already full".to_string())] } else { - vec![MoveToRoom(r.id), - RoomJoined(nicks).send_self().action()] + vec![MoveToRoom(r.id), RoomJoined(nicks).send_self().action()] } } else { vec![Warn("No such room.".to_string())] }; server.react(client_id, actions); - }, + } Rnd(v) => { server.react(client_id, vec![rnd_reply(&v).send_self().action()]); - }, + } List => warn!("Deprecated LIST message received"), _ => warn!("Incorrect command in lobby state"), } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/handlers/loggingin.rs --- a/rust/hedgewars-server/src/server/handlers/loggingin.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/handlers/loggingin.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,21 +1,19 @@ use mio; use crate::{ + protocol::messages::{HWProtocolMessage, HWServerMessage::*}, server::{ + actions::{Action, Action::*}, client::HWClient, core::HWServer, coretypes::ClientId, - actions::{Action, Action::*} }, - protocol::messages::{ - HWProtocolMessage, HWServerMessage::* - }, - utils::is_name_illegal + utils::is_name_illegal, }; +use log::*; #[cfg(feature = "official-server")] use openssl::sha::sha1; use std::fmt::{Formatter, LowerHex}; -use log::*; #[derive(PartialEq)] struct Sha1Digest([u8; 20]); @@ -31,29 +29,27 @@ #[cfg(feature = "official-server")] fn get_hash(client: &HWClient, salt1: &str, salt2: &str) -> Sha1Digest { - let s = format!("{}{}{}{}{}", salt1, salt2, - client.web_password, client.protocol_number, "!hedgewars"); + let s = format!( + "{}{}{}{}{}", + salt1, salt2, client.web_password, client.protocol_number, "!hedgewars" + ); Sha1Digest(sha1(s.as_bytes())) } -pub fn handle(server: & mut HWServer, client_id: ClientId, message: HWProtocolMessage) { +pub fn handle(server: &mut HWServer, client_id: ClientId, message: HWProtocolMessage) { match message { HWProtocolMessage::Nick(nick) => { let client = &mut server.clients[client_id]; debug!("{} {}", nick, is_name_illegal(&nick)); let actions = if client.room_id != None { unreachable!() - } - else if !client.nick.is_empty() { + } else if !client.nick.is_empty() { vec![ProtocolError("Nickname already provided.".to_string())] - } - else if is_name_illegal(&nick) { + } 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())] - } - else { + } else { client.nick = nick.clone(); - vec![Nick(nick).send_self().action(), - CheckRegistered] + vec![Nick(nick).send_self().action(), CheckRegistered] }; server.react(client_id, actions); @@ -62,14 +58,11 @@ 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 { + } else if proto == 0 { vec![ProtocolError("Bad number.".to_string())] - } - else { + } else { client.protocol_number = proto; - vec![Proto(proto).send_self().action(), - CheckRegistered] + vec![Proto(proto).send_self().action(), CheckRegistered] }; server.react(client_id, actions); } @@ -80,8 +73,12 @@ 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] + vec![ + ServerAuth(format!("{:x}", server_hash)) + .send_self() + .action(), + JoinLobby, + ] } else { vec![ByeClient("Authentication failed".to_string())] }; diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/io.rs --- a/rust/hedgewars-server/src/server/io.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/io.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,6 +1,6 @@ use std::{ fs::{File, OpenOptions}, - io::{Read, Write, Result, Error, ErrorKind} + io::{Error, ErrorKind, Read, Result, Write}, }; pub trait HWServerIO { @@ -46,4 +46,4 @@ reader.read_to_string(&mut result)?; Ok(result) } -} \ No newline at end of file +} diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/network.rs --- a/rust/hedgewars-server/src/server/network.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/network.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,37 +1,33 @@ extern crate slab; use std::{ - io, io::{Error, ErrorKind, Read, Write}, - net::{SocketAddr, IpAddr, Ipv4Addr}, collections::HashSet, - mem::{swap, replace} + io, + io::{Error, ErrorKind, Read, Write}, + mem::{replace, swap}, + net::{IpAddr, Ipv4Addr, SocketAddr}, }; +use log::*; use mio::{ - net::{TcpStream, TcpListener}, - Poll, PollOpt, Ready, Token + net::{TcpListener, TcpStream}, + Poll, PollOpt, Ready, Token, }; use netbuf; use slab::Slab; -use log::*; +use super::{core::HWServer, coretypes::ClientId, io::FileServerIO}; use crate::{ + protocol::{messages::*, ProtocolDecoder}, utils, - protocol::{ProtocolDecoder, messages::*} -}; -use super::{ - io::FileServerIO, - core::{HWServer}, - coretypes::ClientId }; #[cfg(feature = "tls-connections")] use openssl::{ + error::ErrorStack, ssl::{ - SslMethod, SslContext, Ssl, SslContextBuilder, - SslVerifyMode, SslFiletype, SslOptions, - SslStreamBuilder, HandshakeError, MidHandshakeSslStream, SslStream + HandshakeError, MidHandshakeSslStream, Ssl, SslContext, SslContextBuilder, SslFiletype, + SslMethod, SslOptions, SslStream, SslStreamBuilder, SslVerifyMode, }, - error::ErrorStack }; const MAX_BYTES_PER_READ: usize = 2048; @@ -48,13 +44,13 @@ #[cfg(not(feature = "tls-connections"))] pub enum ClientSocket { - Plain(TcpStream) + Plain(TcpStream), } #[cfg(feature = "tls-connections")] pub enum ClientSocket { SslHandshake(Option>), - SslStream(SslStream) + SslStream(SslStream), } impl ClientSocket { @@ -68,7 +64,7 @@ match self { ClientSocket::SslHandshake(Some(builder)) => builder.get_ref(), ClientSocket::SslHandshake(None) => unreachable!(), - ClientSocket::SslStream(ssl_stream) => ssl_stream.get_ref() + ClientSocket::SslStream(ssl_stream) => ssl_stream.get_ref(), } } } @@ -78,24 +74,32 @@ socket: ClientSocket, peer_addr: SocketAddr, decoder: ProtocolDecoder, - buf_out: netbuf::Buf + buf_out: netbuf::Buf, } impl NetworkClient { pub fn new(id: ClientId, socket: ClientSocket, peer_addr: SocketAddr) -> NetworkClient { NetworkClient { - id, socket, peer_addr, + id, + socket, + peer_addr, decoder: ProtocolDecoder::new(), - buf_out: netbuf::Buf::new() + buf_out: netbuf::Buf::new(), } } #[cfg(feature = "tls-connections")] - fn handshake_impl(&mut self, handshake: MidHandshakeSslStream) -> io::Result { + fn handshake_impl( + &mut self, + handshake: MidHandshakeSslStream, + ) -> io::Result { match handshake.handshake() { Ok(stream) => { self.socket = ClientSocket::SslStream(stream); - debug!("TLS handshake with {} ({}) completed", self.id, self.peer_addr); + debug!( + "TLS handshake with {} ({}) completed", + self.id, self.peer_addr + ); Ok(NetworkClientState::Idle) } Err(HandshakeError::WouldBlock(new_handshake)) => { @@ -107,12 +111,16 @@ debug!("TLS handshake with {} ({}) failed", self.id, self.peer_addr); Err(Error::new(ErrorKind::Other, "Connection failure")) } - Err(HandshakeError::SetupFailure(_)) => unreachable!() + Err(HandshakeError::SetupFailure(_)) => unreachable!(), } } - fn read_impl(decoder: &mut ProtocolDecoder, source: &mut R, - id: ClientId, addr: &SocketAddr) -> NetworkResult> { + fn read_impl( + decoder: &mut ProtocolDecoder, + source: &mut R, + id: ClientId, + addr: &SocketAddr, + ) -> NetworkResult> { let mut bytes_read = 0; let result = loop { match decoder.read_from(source) { @@ -127,21 +135,19 @@ (decoder.extract_messages(), NetworkClientState::NeedsRead) }; break Ok(result); - } - else if bytes_read >= MAX_BYTES_PER_READ { - break Ok((decoder.extract_messages(), NetworkClientState::NeedsRead)) + } else if bytes_read >= MAX_BYTES_PER_READ { + break Ok((decoder.extract_messages(), NetworkClientState::NeedsRead)); } } Err(ref error) if error.kind() == ErrorKind::WouldBlock => { - let messages = if bytes_read == 0 { + let messages = if bytes_read == 0 { Vec::new() } else { decoder.extract_messages() }; break Ok((messages, NetworkClientState::Idle)); } - Err(error) => - break Err(error) + Err(error) => break Err(error), } }; decoder.sweep(); @@ -151,8 +157,9 @@ pub fn read(&mut self) -> NetworkResult> { #[cfg(not(feature = "tls-connections"))] match self.socket { - ClientSocket::Plain(ref mut stream) => - NetworkClient::read_impl(&mut self.decoder, stream, self.id, &self.peer_addr), + ClientSocket::Plain(ref mut stream) => { + NetworkClient::read_impl(&mut self.decoder, stream, self.id, &self.peer_addr) + } } #[cfg(feature = "tls-connections")] @@ -160,24 +167,27 @@ ClientSocket::SslHandshake(ref mut handshake_opt) => { let handshake = std::mem::replace(handshake_opt, None).unwrap(); Ok((Vec::new(), self.handshake_impl(handshake)?)) - }, - ClientSocket::SslStream(ref mut stream) => + } + ClientSocket::SslStream(ref mut stream) => { NetworkClient::read_impl(&mut self.decoder, stream, self.id, &self.peer_addr) + } } } fn write_impl(buf_out: &mut netbuf::Buf, destination: &mut W) -> NetworkResult<()> { let result = loop { match buf_out.write_to(destination) { - Ok(bytes) if buf_out.is_empty() || bytes == 0 => - break Ok(((), NetworkClientState::Idle)), + Ok(bytes) if buf_out.is_empty() || bytes == 0 => { + break Ok(((), NetworkClientState::Idle)) + } Ok(_) => (), - Err(ref error) if error.kind() == ErrorKind::Interrupted - || error.kind() == ErrorKind::WouldBlock => { + Err(ref error) + if error.kind() == ErrorKind::Interrupted + || error.kind() == ErrorKind::WouldBlock => + { break Ok(((), NetworkClientState::NeedsWrite)); - }, - Err(error) => - break Err(error) + } + Err(error) => break Err(error), } }; result @@ -187,18 +197,21 @@ let result = { #[cfg(not(feature = "tls-connections"))] match self.socket { - ClientSocket::Plain(ref mut stream) => + ClientSocket::Plain(ref mut stream) => { NetworkClient::write_impl(&mut self.buf_out, stream) + } } - #[cfg(feature = "tls-connections")] { + #[cfg(feature = "tls-connections")] + { match self.socket { ClientSocket::SslHandshake(ref mut handshake_opt) => { let handshake = std::mem::replace(handshake_opt, None).unwrap(); Ok(((), self.handshake_impl(handshake)?)) } - ClientSocket::SslStream(ref mut stream) => + ClientSocket::SslStream(ref mut stream) => { NetworkClient::write_impl(&mut self.buf_out, stream) + } } } }; @@ -222,7 +235,7 @@ #[cfg(feature = "tls-connections")] struct ServerSsl { - context: SslContext + context: SslContext, } pub struct NetworkLayer { @@ -232,7 +245,7 @@ pending: HashSet<(ClientId, NetworkClientState)>, pending_cache: Vec<(ClientId, NetworkClientState)>, #[cfg(feature = "tls-connections")] - ssl: ServerSsl + ssl: ServerSsl, } impl NetworkLayer { @@ -243,9 +256,13 @@ let pending_cache = Vec::with_capacity(2 * clients_limit); NetworkLayer { - listener, server, clients, pending, pending_cache, + listener, + server, + clients, + pending, + pending_cache, #[cfg(feature = "tls-connections")] - ssl: NetworkLayer::create_ssl_context() + ssl: NetworkLayer::create_ssl_context(), } } @@ -254,16 +271,26 @@ let mut builder = SslContextBuilder::new(SslMethod::tls()).unwrap(); builder.set_verify(SslVerifyMode::NONE); builder.set_read_ahead(true); - builder.set_certificate_file("ssl/cert.pem", SslFiletype::PEM).unwrap(); - builder.set_private_key_file("ssl/key.pem", SslFiletype::PEM).unwrap(); + builder + .set_certificate_file("ssl/cert.pem", SslFiletype::PEM) + .unwrap(); + builder + .set_private_key_file("ssl/key.pem", SslFiletype::PEM) + .unwrap(); builder.set_options(SslOptions::NO_COMPRESSION); builder.set_cipher_list("DEFAULT:!LOW:!RC4:!EXP").unwrap(); - ServerSsl { context: builder.build() } + ServerSsl { + context: builder.build(), + } } pub fn register_server(&self, poll: &Poll) -> io::Result<()> { - poll.register(&self.listener, utils::SERVER, Ready::readable(), - PollOpt::edge()) + poll.register( + &self.listener, + utils::SERVER, + Ready::readable(), + PollOpt::edge(), + ) } fn deregister_client(&mut self, poll: &Poll, id: ClientId) { @@ -279,11 +306,20 @@ } } - fn register_client(&mut self, poll: &Poll, id: ClientId, client_socket: ClientSocket, addr: SocketAddr) { - poll.register(client_socket.inner(), Token(id), - Ready::readable() | Ready::writable(), - PollOpt::edge()) - .expect("could not register socket with event loop"); + fn register_client( + &mut self, + poll: &Poll, + id: ClientId, + client_socket: ClientSocket, + addr: SocketAddr, + ) { + poll.register( + client_socket.inner(), + Token(id), + Ready::readable() | Ready::writable(), + PollOpt::edge(), + ) + .expect("could not register socket with event loop"); let entry = self.clients.vacant_entry(); let client = NetworkClient::new(id, client_socket, addr); @@ -299,26 +335,29 @@ for client_id in clients { if let Some(client) = self.clients.get_mut(client_id) { client.send_string(&msg_string); - self.pending.insert((client_id, NetworkClientState::NeedsWrite)); + self.pending + .insert((client_id, NetworkClientState::NeedsWrite)); } } } } fn create_client_socket(&self, socket: TcpStream) -> io::Result { - #[cfg(not(feature = "tls-connections"))] { + #[cfg(not(feature = "tls-connections"))] + { Ok(ClientSocket::Plain(socket)) } - #[cfg(feature = "tls-connections")] { + #[cfg(feature = "tls-connections")] + { let ssl = Ssl::new(&self.ssl.context).unwrap(); let mut builder = SslStreamBuilder::new(ssl, socket); builder.set_accept_state(); match builder.handshake() { - Ok(stream) => - Ok(ClientSocket::SslStream(stream)), - Err(HandshakeError::WouldBlock(stream)) => - Ok(ClientSocket::SslHandshake(Some(stream))), + Ok(stream) => Ok(ClientSocket::SslStream(stream)), + Err(HandshakeError::WouldBlock(stream)) => { + Ok(ClientSocket::SslHandshake(Some(stream))) + } Err(e) => { debug!("OpenSSL handshake failed: {}", e); Err(Error::new(ErrorKind::Other, "Connection failure")) @@ -332,13 +371,24 @@ info!("Connected: {}", addr); let client_id = self.server.add_client(); - self.register_client(poll, client_id, self.create_client_socket(client_socket)?, addr); + self.register_client( + poll, + client_id, + self.create_client_socket(client_socket)?, + addr, + ); self.flush_server_messages(); Ok(()) } - fn operation_failed(&mut self, poll: &Poll, client_id: ClientId, error: &Error, msg: &str) -> io::Result<()> { + fn operation_failed( + &mut self, + poll: &Poll, + client_id: ClientId, + error: &Error, + msg: &str, + ) -> io::Result<()> { let addr = if let Some(ref mut client) = self.clients.get_mut(client_id) { client.peer_addr } else { @@ -348,15 +398,13 @@ self.client_error(poll, client_id) } - pub fn client_readable(&mut self, poll: &Poll, - client_id: ClientId) -> io::Result<()> { - let messages = - if let Some(ref mut client) = self.clients.get_mut(client_id) { - client.read() - } else { - warn!("invalid readable client: {}", client_id); - Ok((Vec::new(), NetworkClientState::Idle)) - }; + pub fn client_readable(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { + let messages = if let Some(ref mut client) = self.clients.get_mut(client_id) { + client.read() + } else { + warn!("invalid readable client: {}", client_id); + Ok((Vec::new(), NetworkClientState::Idle)) + }; match messages { Ok((messages, state)) => { @@ -366,15 +414,17 @@ match state { NetworkClientState::NeedsRead => { self.pending.insert((client_id, state)); - }, - NetworkClientState::Closed => - self.client_error(&poll, client_id)?, + } + NetworkClientState::Closed => self.client_error(&poll, client_id)?, _ => {} }; } Err(e) => self.operation_failed( - poll, client_id, &e, - "Error while reading from client socket")? + poll, + client_id, + &e, + "Error while reading from client socket", + )?, } self.flush_server_messages(); @@ -389,31 +439,28 @@ Ok(()) } - pub fn client_writable(&mut self, poll: &Poll, - client_id: ClientId) -> io::Result<()> { - let result = - if let Some(ref mut client) = self.clients.get_mut(client_id) { - client.write() - } else { - warn!("invalid writable client: {}", client_id); - Ok(((), NetworkClientState::Idle)) - }; + pub fn client_writable(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { + let result = if let Some(ref mut client) = self.clients.get_mut(client_id) { + client.write() + } else { + warn!("invalid writable client: {}", client_id); + Ok(((), NetworkClientState::Idle)) + }; match result { Ok(((), state)) if state == NetworkClientState::NeedsWrite => { self.pending.insert((client_id, state)); - }, + } Ok(_) => {} - Err(e) => self.operation_failed( - poll, client_id, &e, - "Error while writing to client socket")? + Err(e) => { + self.operation_failed(poll, client_id, &e, "Error while writing to client socket")? + } } Ok(()) } - pub fn client_error(&mut self, poll: &Poll, - client_id: ClientId) -> io::Result<()> { + pub fn client_error(&mut self, poll: &Poll, client_id: ClientId) -> io::Result<()> { self.deregister_client(poll, client_id); self.server.client_lost(client_id); @@ -430,10 +477,8 @@ cache.extend(self.pending.drain()); for (id, state) in cache.drain(..) { match state { - NetworkClientState::NeedsRead => - self.client_readable(poll, id)?, - NetworkClientState::NeedsWrite => - self.client_writable(poll, id)?, + NetworkClientState::NeedsRead => self.client_readable(poll, id)?, + NetworkClientState::NeedsWrite => self.client_writable(poll, id)?, _ => {} } } diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/server/room.rs --- a/rust/hedgewars-server/src/server/room.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/server/room.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,32 +1,26 @@ -use std::{ - iter, collections::HashMap -}; use crate::server::{ - coretypes::{ - ClientId, RoomId, TeamInfo, GameCfg, GameCfg::*, Voting, - MAX_HEDGEHOGS_PER_TEAM - }, - client::{HWClient} + client::HWClient, + coretypes::{ClientId, GameCfg, GameCfg::*, RoomId, TeamInfo, Voting, MAX_HEDGEHOGS_PER_TEAM}, }; use bitflags::*; -use serde::{Serialize, Deserialize}; -use serde_derive::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; +use serde_derive::{Deserialize, Serialize}; use serde_yaml; +use std::{collections::HashMap, iter}; const MAX_TEAMS_IN_ROOM: u8 = 8; -const MAX_HEDGEHOGS_IN_ROOM: u8 = - MAX_HEDGEHOGS_PER_TEAM * MAX_HEDGEHOGS_PER_TEAM; +const MAX_HEDGEHOGS_IN_ROOM: u8 = MAX_HEDGEHOGS_PER_TEAM * MAX_HEDGEHOGS_PER_TEAM; #[derive(Clone, Serialize, Deserialize)] struct Ammo { name: String, - settings: Option + settings: Option, } #[derive(Clone, Serialize, Deserialize)] struct Scheme { name: String, - settings: Vec + settings: Vec, } #[derive(Clone, Serialize, Deserialize)] @@ -42,7 +36,7 @@ scheme: Scheme, script: String, theme: String, - drawn_map: Option + drawn_map: Option, } impl RoomConfig { @@ -55,25 +49,40 @@ seed: "seed".to_string(), template: 0, - ammo: Ammo {name: "Default".to_string(), settings: None }, - scheme: Scheme {name: "Default".to_string(), settings: Vec::new() }, + ammo: Ammo { + name: "Default".to_string(), + settings: None, + }, + scheme: Scheme { + name: "Default".to_string(), + settings: Vec::new(), + }, script: "Normal".to_string(), theme: "\u{1f994}".to_string(), - drawn_map: None + drawn_map: None, } } } -fn client_teams_impl(teams: &[(ClientId, TeamInfo)], client_id: ClientId) - -> impl Iterator + Clone -{ - teams.iter().filter(move |(id, _)| *id == client_id).map(|(_, t)| t) +fn client_teams_impl( + teams: &[(ClientId, TeamInfo)], + client_id: ClientId, +) -> impl Iterator + Clone { + teams + .iter() + .filter(move |(id, _)| *id == client_id) + .map(|(_, t)| t) } fn map_config_from(c: &RoomConfig) -> Vec { - vec![c.feature_size.to_string(), c.map_type.to_string(), - c.map_generator.to_string(), c.maze_size.to_string(), - c.seed.to_string(), c.template.to_string()] + vec![ + c.feature_size.to_string(), + c.map_type.to_string(), + c.map_generator.to_string(), + c.maze_size.to_string(), + c.seed.to_string(), + c.template.to_string(), + ] } fn game_config_from(c: &RoomConfig) -> Vec { @@ -82,7 +91,8 @@ Ammo(c.ammo.name.to_string(), c.ammo.settings.clone()), Scheme(c.scheme.name.to_string(), c.scheme.settings.clone()), Script(c.script.to_string()), - Theme(c.theme.to_string())]; + Theme(c.theme.to_string()), + ]; if let Some(ref m) = c.drawn_map { v.push(DrawnMap(m.to_string())) } @@ -96,7 +106,7 @@ pub msg_log: Vec, pub sync_msg: Option, pub is_paused: bool, - config: RoomConfig + config: RoomConfig, } impl GameInfo { @@ -108,7 +118,7 @@ is_paused: false, teams_in_game: teams.len() as u8, teams_at_start: teams, - config + config, } } @@ -120,10 +130,10 @@ #[derive(Serialize, Deserialize)] pub struct RoomSave { pub location: String, - config: RoomConfig + config: RoomConfig, } -bitflags!{ +bitflags! { pub struct RoomFlags: u8 { const FIXED = 0b0000_0001; const RESTRICTED_JOIN = 0b0000_0010; @@ -149,7 +159,7 @@ config: RoomConfig, pub voting: Option, pub saves: HashMap, - pub game_info: Option + pub game_info: Option, } impl HWRoom { @@ -170,7 +180,7 @@ config: RoomConfig::new(), voting: None, saves: HashMap::new(), - game_info: None + game_info: None, } } @@ -182,17 +192,27 @@ MAX_HEDGEHOGS_IN_ROOM - self.hedgehogs_number() } - pub fn add_team(&mut self, owner_id: ClientId, mut team: TeamInfo, preserve_color: bool) -> &TeamInfo { + pub fn add_team( + &mut self, + owner_id: ClientId, + mut team: TeamInfo, + preserve_color: bool, + ) -> &TeamInfo { if !preserve_color { - team.color = iter::repeat(()).enumerate() - .map(|(i, _)| i as u8).take(u8::max_value() as usize + 1) + team.color = iter::repeat(()) + .enumerate() + .map(|(i, _)| i as u8) + .take(u8::max_value() as usize + 1) .find(|i| self.teams.iter().all(|(_, t)| t.color != *i)) .unwrap_or(0u8) }; team.hedgehogs_number = if self.teams.is_empty() { self.default_hedgehog_number } else { - self.teams[0].1.hedgehogs_number.min(self.addable_hedgehogs()) + self.teams[0] + .1 + .hedgehogs_number + .min(self.addable_hedgehogs()) }; self.teams.push((owner_id, team)); &self.teams.last().unwrap().1 @@ -208,27 +228,36 @@ let mut names = Vec::new(); let teams = match self.game_info { Some(ref mut info) => &mut info.teams_at_start, - None => &mut self.teams + None => &mut self.teams, }; if teams.len() as u8 * n <= MAX_HEDGEHOGS_IN_ROOM { for (_, team) in teams.iter_mut() { team.hedgehogs_number = n; names.push(team.name.clone()) - }; + } self.default_hedgehog_number = n; } names } pub fn find_team_and_owner_mut(&mut self, f: F) -> Option<(ClientId, &mut TeamInfo)> - where F: Fn(&TeamInfo) -> bool { - self.teams.iter_mut().find(|(_, t)| f(t)).map(|(id, t)| (*id, t)) + where + F: Fn(&TeamInfo) -> bool, + { + self.teams + .iter_mut() + .find(|(_, t)| f(t)) + .map(|(id, t)| (*id, t)) } pub fn find_team(&self, f: F) -> Option<&TeamInfo> - where F: Fn(&TeamInfo) -> bool { - self.teams.iter().find_map(|(_, t)| Some(t).filter(|t| f(&t))) + where + F: Fn(&TeamInfo) -> bool, + { + self.teams + .iter() + .find_map(|(_, t)| Some(t).filter(|t| f(&t))) } pub fn client_teams(&self, client_id: ClientId) -> impl Iterator { @@ -236,13 +265,18 @@ } pub fn client_team_indices(&self, client_id: ClientId) -> Vec { - self.teams.iter().enumerate() + self.teams + .iter() + .enumerate() .filter(move |(_, (id, _))| *id == client_id) - .map(|(i, _)| i as u8).collect() + .map(|(i, _)| i as u8) + .collect() } pub fn find_team_owner(&self, team_name: &str) -> Option<(ClientId, &str)> { - self.teams.iter().find(|(_, t)| t.name == team_name) + self.teams + .iter() + .find(|(_, t)| t.name == team_name) .map(|(id, t)| (*id, &t.name[..])) } @@ -251,8 +285,8 @@ } pub fn has_multiple_clans(&self) -> bool { - self.teams.iter().min_by_key(|(_, t)| t.color) != - self.teams.iter().max_by_key(|(_, t)| t.color) + self.teams.iter().min_by_key(|(_, t)| t.color) + != self.teams.iter().max_by_key(|(_, t)| t.color) } pub fn set_config(&mut self, cfg: GameCfg) { @@ -265,18 +299,27 @@ Seed(s) => c.seed = s, Template(t) => c.template = t, - Ammo(n, s) => c.ammo = Ammo {name: n, settings: s}, - Scheme(n, s) => c.scheme = Scheme {name: n, settings: s}, + Ammo(n, s) => { + c.ammo = Ammo { + name: n, + settings: s, + } + } + Scheme(n, s) => { + c.scheme = Scheme { + name: n, + settings: s, + } + } Script(s) => c.script = s, Theme(t) => c.theme = t, - DrawnMap(m) => c.drawn_map = Some(m) + DrawnMap(m) => c.drawn_map = Some(m), }; } pub fn start_round(&mut self) { if self.game_info.is_none() { - self.game_info = Some(GameInfo::new( - self.teams.clone(), self.config.clone())); + self.game_info = Some(GameInfo::new(self.teams.clone(), self.config.clone())); } } @@ -290,7 +333,8 @@ self.flags.contains(RoomFlags::RESTRICTED_TEAM_ADD) } pub fn are_unregistered_players_restricted(&self) -> bool { - self.flags.contains(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS) + self.flags + .contains(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS) } pub fn set_is_fixed(&mut self, value: bool) { @@ -303,14 +347,21 @@ self.flags.set(RoomFlags::RESTRICTED_TEAM_ADD, value) } pub fn set_unregistered_players_restriction(&mut self, value: bool) { - self.flags.set(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS, value) + self.flags + .set(RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS, value) } fn flags_string(&self) -> String { let mut result = "-".to_string(); - if self.game_info.is_some() { result += "g" } - if self.password.is_some() { result += "p" } - if self.is_join_restricted() { result += "j" } + if self.game_info.is_some() { + result += "g" + } + if self.password.is_some() { + result += "p" + } + if self.is_join_restricted() { + result += "j" + } if self.are_unregistered_players_restricted() { result += "r" } @@ -328,26 +379,32 @@ c.map_type.to_string(), c.script.to_string(), c.scheme.name.to_string(), - c.ammo.name.to_string() + c.ammo.name.to_string(), ] } pub fn map_config(&self) -> Vec { match self.game_info { Some(ref info) => map_config_from(&info.config), - None => map_config_from(&self.config) + None => map_config_from(&self.config), } } pub fn game_config(&self) -> Vec { match self.game_info { Some(ref info) => game_config_from(&info.config), - None => game_config_from(&self.config) + None => game_config_from(&self.config), } } pub fn save_config(&mut self, name: String, location: String) { - self.saves.insert(name, RoomSave { location, config: self.config.clone() }); + self.saves.insert( + name, + RoomSave { + location, + config: self.config.clone(), + }, + ); } pub fn load_config(&mut self, name: &str) -> Option<&str> { @@ -368,10 +425,12 @@ } pub fn set_saves(&mut self, text: &str) -> Result<(), serde_yaml::Error> { - serde_yaml::from_str::<(String, HashMap)>(text).map(|(greeting, saves)| { - self.greeting = greeting; - self.saves = saves; - }) + serde_yaml::from_str::<(String, HashMap)>(text).map( + |(greeting, saves)| { + self.greeting = greeting; + self.saves = saves; + }, + ) } pub fn team_info(owner: &HWClient, team: &TeamInfo) -> Vec { @@ -382,10 +441,13 @@ team.voice_pack.clone(), team.flag.clone(), owner.nick.clone(), - team.difficulty.to_string()]; - let hogs = team.hedgehogs.iter().flat_map(|h| - iter::once(h.name.clone()).chain(iter::once(h.hat.clone()))); + team.difficulty.to_string(), + ]; + let hogs = team + .hedgehogs + .iter() + .flat_map(|h| iter::once(h.name.clone()).chain(iter::once(h.hat.clone()))); info.extend(hogs); info } -} \ No newline at end of file +} diff -r a077aac9df01 -r 98ef2913ec73 rust/hedgewars-server/src/utils.rs --- a/rust/hedgewars-server/src/utils.rs Sun Dec 16 00:09:20 2018 +0100 +++ b/rust/hedgewars-server/src/utils.rs Sun Dec 16 00:12:29 2018 +0100 @@ -1,20 +1,21 @@ -use std::iter::Iterator; +use base64::encode; use mio; -use base64::{encode}; +use std::iter::Iterator; -pub const PROTOCOL_VERSION : u32 = 3; +pub const PROTOCOL_VERSION: u32 = 3; pub const SERVER: mio::Token = mio::Token(1_000_000_000); -pub fn is_name_illegal(name: &str ) -> bool{ - name.len() > 40 || - name.trim().is_empty() || - name.chars().any(|c| - "$()*+?[]^{|}\x7F".contains(c) || - '\x00' <= c && c <= '\x1F') +pub fn is_name_illegal(name: &str) -> bool { + name.len() > 40 + || name.trim().is_empty() + || name + .chars() + .any(|c| "$()*+?[]^{|}\x7F".contains(c) || '\x00' <= c && c <= '\x1F') } pub fn to_engine_msg(msg: T) -> String - where T: Iterator + Clone +where + T: Iterator + Clone, { let mut tmp = Vec::new(); tmp.push(msg.clone().count() as u8); @@ -64,6 +65,6 @@ 56 => "0.9.25-dev", 57 => "0.9.25", 58 => "1.0.0-dev", - _ => "Unknown" + _ => "Unknown", } }