--- a/rust/hedgewars-network-protocol/src/messages.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-network-protocol/src/messages.rs Wed Jun 30 00:18:53 2021 +0200
@@ -107,9 +107,9 @@
ProtocolFlags::format('-', flags)
}
-#[derive(Debug)]
+#[derive(PartialEq, Eq, Clone, Debug)]
pub enum HwServerMessage {
- Connected(u32),
+ Connected(String, u32),
Redirect(u16),
Ping,
@@ -151,7 +151,6 @@
Notice(String),
Warning(String),
Error(String),
- Unreachable,
//Deprecated messages
LegacyReady(bool, Vec<String>),
@@ -370,11 +369,7 @@
match self {
Ping => msg!["PING"],
Pong => msg!["PONG"],
- Connected(protocol_version) => msg![
- "CONNECTED",
- "Hedgewars server https://www.hedgewars.org/",
- protocol_version
- ],
+ Connected(message, protocol_version) => msg!["CONNECTED", message, protocol_version],
Redirect(port) => msg!["REDIRECT", port],
Bye(msg) => msg!["BYE", msg],
Nick(nick) => msg!["NICK", nick],
@@ -414,8 +409,6 @@
LegacyReady(is_ready, nicks) => {
construct_message(&[if *is_ready { "READY" } else { "NOT_READY" }], &nicks)
}
-
- _ => msg!["ERROR", "UNIMPLEMENTED"],
}
}
}
--- a/rust/hedgewars-network-protocol/src/parser.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-network-protocol/src/parser.rs Wed Jun 30 00:18:53 2021 +0200
@@ -23,7 +23,7 @@
str::{FromStr, Utf8Error},
};
-use crate::messages::{HwProtocolMessage, HwProtocolMessage::*};
+use crate::messages::{HwProtocolMessage, HwProtocolMessage::*, HwServerMessage};
use crate::types::{GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType};
#[derive(Debug, PartialEq)]
@@ -503,3 +503,158 @@
end_of_message,
)(input)
}
+
+pub fn server_message(input: &[u8]) -> HwResult<HwServerMessage> {
+ use HwServerMessage::*;
+
+ fn single_arg_message<'a, T, F, G>(
+ name: &'a str,
+ parser: F,
+ constructor: G,
+ ) -> impl FnMut(&'a [u8]) -> HwResult<'a, HwServerMessage>
+ where
+ F: Fn(&[u8]) -> HwResult<T>,
+ G: Fn(T) -> HwServerMessage,
+ {
+ map(
+ preceded(terminated(tag(name), newline), parser),
+ constructor,
+ )
+ }
+
+ fn list_message<'a, G>(
+ name: &'a str,
+ constructor: G,
+ ) -> impl FnMut(&'a [u8]) -> HwResult<'a, HwServerMessage>
+ where
+ G: Fn(Vec<String>) -> HwServerMessage,
+ {
+ map(
+ preceded(
+ tag(name),
+ alt((
+ map(peek(end_of_message), |_| None),
+ map(preceded(newline, separated_list0(newline, a_line)), Some),
+ )),
+ ),
+ move |values| constructor(values.unwrap_or_default()),
+ )
+ }
+
+ fn string_and_list_message<'a, G>(
+ name: &'a str,
+ constructor: G,
+ ) -> impl FnMut(&'a [u8]) -> HwResult<'a, HwServerMessage>
+ where
+ G: Fn(String, Vec<String>) -> HwServerMessage,
+ {
+ preceded(
+ pair(tag(name), newline),
+ map(
+ pair(
+ a_line,
+ alt((
+ map(peek(end_of_message), |_| None),
+ map(preceded(newline, separated_list0(newline, a_line)), Some),
+ )),
+ ),
+ move |(name, values)| constructor(name, values.unwrap_or_default()),
+ ),
+ )
+ }
+
+ fn message<'a>(
+ name: &'a str,
+ msg: HwServerMessage,
+ ) -> impl Fn(&'a [u8]) -> HwResult<'a, HwServerMessage> {
+ move |i| map(tag(name), |_| msg.clone())(i)
+ }
+
+ delimited(
+ take_while(|c| c == b'\n'),
+ alt((
+ alt((
+ message("PING", Ping),
+ message("PONG", Pong),
+ message("LOGONPASSED", LogonPassed),
+ message("KICKED", Kicked),
+ message("RUN_GAME", RunGame),
+ message("ROUND_FINISHED", RoundFinished),
+ message("REPLAY_START", ReplayStart),
+ )),
+ alt((
+ single_arg_message("REDIRECT", u16_line, Redirect),
+ single_arg_message("BYE", a_line, Bye),
+ single_arg_message("NICK", a_line, Nick),
+ single_arg_message("PROTO", u16_line, Proto),
+ single_arg_message("ASKPASSWORD", a_line, AskPassword),
+ single_arg_message("SERVER_AUTH", a_line, ServerAuth),
+ single_arg_message("ROOM\nDEL", a_line, RoomRemove),
+ single_arg_message("JOINING", a_line, Joining),
+ single_arg_message("REMOVE_TEAM", a_line, TeamRemove),
+ single_arg_message("TEAM_ACCEPTED", a_line, TeamAccepted),
+ single_arg_message("SERVER_MESSAGE", a_line, ServerMessage),
+ single_arg_message("NOTICE", a_line, Notice),
+ single_arg_message("WARNING", a_line, Warning),
+ single_arg_message("ERROR", a_line, Error),
+ )),
+ alt((
+ preceded(
+ pair(tag("LOBBY:LEFT"), newline),
+ map(pair(terminated(a_line, newline), a_line), |(nick, msg)| {
+ LobbyLeft(nick, msg)
+ }),
+ ),
+ preceded(
+ pair(tag("CHAT"), newline),
+ map(pair(terminated(a_line, newline), a_line), |(nick, msg)| {
+ ChatMsg { nick, msg }
+ }),
+ ),
+ preceded(
+ pair(tag("TEAM_COLOR"), newline),
+ map(
+ pair(terminated(a_line, newline), u8_line),
+ |(name, color)| TeamColor(name, color),
+ ),
+ ),
+ preceded(
+ pair(tag("HH_NUM"), newline),
+ map(
+ pair(terminated(a_line, newline), u8_line),
+ |(name, count)| HedgehogsNumber(name, count),
+ ),
+ ),
+ preceded(
+ pair(tag("CONNECTED"), newline),
+ map(
+ pair(terminated(a_line, newline), u32_line),
+ |(msg, server_protocol_version)| Connected(msg, server_protocol_version),
+ ),
+ ),
+ preceded(
+ pair(tag("LEFT"), newline),
+ map(pair(terminated(a_line, newline), a_line), |(nick, msg)| {
+ RoomLeft(nick, msg)
+ }),
+ ),
+ )),
+ alt((
+ string_and_list_message("CLIENT_FLAGS", ClientFlags),
+ string_and_list_message("ROOM\nUPD", RoomUpdated),
+ string_and_list_message("CFG", ConfigEntry),
+ )),
+ alt((
+ list_message("LOBBY:JOINED", LobbyJoined),
+ list_message("ROOMS", Rooms),
+ list_message("ROOM\nADD", RoomAdd),
+ list_message("JOINED", RoomJoined),
+ list_message("ADD_TEAM", TeamAdd),
+ list_message("EM", ForwardEngineMessage),
+ list_message("INFO", Info),
+ list_message("SERVER_VARS", ServerVars),
+ )),
+ )),
+ end_of_message,
+ )(input)
+}
--- a/rust/hedgewars-network-protocol/tests/parser.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-network-protocol/tests/parser.rs Wed Jun 30 00:18:53 2021 +0200
@@ -1,11 +1,13 @@
use hedgewars_network_protocol::{
- parser::message,
+ parser::HwProtocolError,
+ parser::{message, server_message},
types::GameCfg,
- {messages::HwProtocolMessage::*, parser::HwProtocolError},
};
#[test]
fn parse_test() {
+ use hedgewars_network_protocol::messages::HwProtocolMessage::*;
+
assert_eq!(message(b"PING\n\n"), Ok((&b""[..], Ping)));
assert_eq!(message(b"START_GAME\n\n"), Ok((&b""[..], StartGame)));
assert_eq!(
@@ -52,3 +54,23 @@
Err(nom::Err::Error(HwProtocolError::new()))
);
}
+
+#[test]
+fn parse_server_messages_test() {
+ use hedgewars_network_protocol::messages::HwServerMessage::*;
+
+ assert_eq!(server_message(b"PING\n\n"), Ok((&b""[..], Ping)));
+
+ assert_eq!(
+ server_message(b"JOINING\nnoone\n\n"),
+ Ok((&b""[..], Joining("noone".to_string())))
+ );
+
+ assert_eq!(
+ server_message(b"CLIENT_FLAGS\naaa\nA\nB\n\n"),
+ Ok((
+ &b""[..],
+ ClientFlags("aaa".to_string(), vec!["A".to_string(), "B".to_string()])
+ ))
+ )
+}
--- a/rust/hedgewars-network-protocol/tests/test.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-network-protocol/tests/test.rs Wed Jun 30 00:18:53 2021 +0200
@@ -4,14 +4,16 @@
strategy::{BoxedStrategy, Just, Strategy},
};
-use hedgewars_network_protocol::messages::{HwProtocolMessage, HwProtocolMessage::*};
-use hedgewars_network_protocol::parser::message;
+use hedgewars_network_protocol::messages::{HwProtocolMessage, HwServerMessage};
+use hedgewars_network_protocol::parser::{message, server_message};
use hedgewars_network_protocol::types::{GameCfg, ServerVar, TeamInfo, VoteType};
use hedgewars_network_protocol::types::testing::*;
use hedgewars_network_protocol::{proto_msg_case, proto_msg_match};
pub fn gen_proto_msg() -> BoxedStrategy<HwProtocolMessage> where {
+ use hedgewars_network_protocol::messages::HwProtocolMessage::*;
+
let res = (0..=55).no_shrink().prop_flat_map(|i| {
proto_msg_match!(i, def = Ping,
0 => Ping(),
@@ -74,10 +76,64 @@
res.boxed()
}
+pub fn gen_server_msg() -> BoxedStrategy<HwServerMessage> where {
+ use hedgewars_network_protocol::messages::HwServerMessage::*;
+
+ let res = (0..=55).no_shrink().prop_flat_map(|i| {
+ proto_msg_match!(i, def = Ping,
+ 0 => Connected(Ascii, u32),
+ 1 => Redirect(u16),
+ 2 => Ping(),
+ 3 => Pong(),
+ 4 => Bye(Ascii),
+ 5 => Nick(Ascii),
+ 6 => Proto(u16),
+ 7 => AskPassword(Ascii),
+ 8 => ServerAuth(Ascii),
+ 9 => LogonPassed(),
+ 10 => LobbyLeft(Ascii, Ascii),
+ 11 => LobbyJoined(Vec<Ascii>),
+ // 12 => ChatMsg { Ascii, Ascii },
+ 13 => ClientFlags(Ascii, Vec<Ascii>),
+ 14 => Rooms(Vec<Ascii>),
+ 15 => RoomAdd(Vec<Ascii>),
+ 16=> RoomJoined(Vec<Ascii>),
+ 17 => RoomLeft(Ascii, Ascii),
+ 18 => RoomRemove(Ascii),
+ 19 => RoomUpdated(Ascii, Vec<Ascii>),
+ 20 => Joining(Ascii),
+ 21 => TeamAdd(Vec<Ascii>),
+ 22 => TeamRemove(Ascii),
+ 23 => TeamAccepted(Ascii),
+ 24 => TeamColor(Ascii, u8),
+ 25 => HedgehogsNumber(Ascii, u8),
+ 26 => ConfigEntry(Ascii, Vec<Ascii>),
+ 27 => Kicked(),
+ 28 => RunGame(),
+ 29 => ForwardEngineMessage(Vec<Ascii>),
+ 30 => RoundFinished(),
+ 31 => ReplayStart(),
+ 32 => Info(Vec<Ascii>),
+ 33 => ServerMessage(Ascii),
+ 34 => ServerVars(Vec<Ascii>),
+ 35 => Notice(Ascii),
+ 36 => Warning(Ascii),
+ 37 => Error(Ascii)
+ )
+ });
+ res.boxed()
+}
+
proptest! {
#[test]
fn is_parser_composition_idempotent(ref msg in gen_proto_msg()) {
println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes());
assert_eq!(message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone())))
}
+
+ #[test]
+ fn is_server_message_parser_composition_idempotent(ref msg in gen_server_msg()) {
+ println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes());
+ assert_eq!(server_message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone())))
+ }
}
--- a/rust/hedgewars-server/src/handlers.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-server/src/handlers.rs Wed Jun 30 00:18:53 2021 +0200
@@ -401,7 +401,7 @@
.anteroom
.add_client(client_id, encode(&salt), is_local);
- response.add(HwServerMessage::Connected(utils::SERVER_VERSION).send_self());
+ response.add(HwServerMessage::Connected(utils::SERVER_MESSAGE.to_owned(), utils::SERVER_VERSION).send_self());
}
}
--- a/rust/hedgewars-server/src/utils.rs Sat Jun 26 00:13:28 2021 +0200
+++ b/rust/hedgewars-server/src/utils.rs Wed Jun 30 00:18:53 2021 +0200
@@ -3,6 +3,7 @@
use std::iter::Iterator;
pub const SERVER_VERSION: u32 = 3;
+pub const SERVER_MESSAGE: &str = &"Hedgewars server https://www.hedgewars.org/";
pub const SERVER_TOKEN: mio::Token = mio::Token(1_000_000_000);
pub const SECURE_SERVER_TOKEN: mio::Token = mio::Token(1_000_000_001);
pub const IO_TOKEN: mio::Token = mio::Token(1_000_000_003);