rust/hedgewars-server/src/protocol/parser.rs
changeset 15118 0e59abde6766
parent 15116 cce6e707172f
child 15119 901751d3cd80
equal deleted inserted replaced
15117:7c4d6246a531 15118:0e59abde6766
     8  */
     8  */
     9 use nom::{
     9 use nom::{
    10     branch::alt,
    10     branch::alt,
    11     bytes::complete::{tag, tag_no_case, take_until, take_while},
    11     bytes::complete::{tag, tag_no_case, take_until, take_while},
    12     character::complete::{newline, not_line_ending},
    12     character::complete::{newline, not_line_ending},
    13     combinator::peek,
    13     combinator::{map, peek},
    14     error::{ErrorKind, ParseError},
    14     error::{ErrorKind, ParseError},
    15     multi::separated_list,
    15     multi::separated_list,
    16     sequence::{pairc, precededc, terminatedc},
    16     sequence::{pair, preceded, terminated},
    17     Err, IResult,
    17     Err, IResult,
    18 };
    18 };
    19 
    19 
    20 use std::{
    20 use std::{
    21     num::ParseIntError,
    21     num::ParseIntError,
    91         Err(Err::Error(HwProtocolError::new()))
    91         Err(Err::Error(HwProtocolError::new()))
    92     }
    92     }
    93 }
    93 }
    94 
    94 
    95 fn a_line(input: &[u8]) -> HwResult<String> {
    95 fn a_line(input: &[u8]) -> HwResult<String> {
    96     let (i, str) = str_line(input)?;
    96     map(str_line, String::from)(input)
    97     Ok((i, str.to_string()))
       
    98 }
       
    99 
       
   100 fn hw_tag<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HwResult<'a, ()> {
       
   101     move |i| tag(tag_str)(i).map(|(i, _)| (i, ()))
       
   102 }
       
   103 
       
   104 fn hw_tag_no_case<'a>(tag_str: &'a str) -> impl Fn(&'a [u8]) -> HwResult<'a, ()> {
       
   105     move |i| tag_no_case(tag_str)(i).map(|(i, _)| (i, ()))
       
   106 }
    97 }
   107 
    98 
   108 fn cmd_arg(input: &[u8]) -> HwResult<String> {
    99 fn cmd_arg(input: &[u8]) -> HwResult<String> {
   109     let delimiters = b" \n";
   100     let delimiters = b" \n";
   110     let (i, str) = take_while(move |c| !delimiters.contains(&c))(input.clone())?;
   101     let (i, str) = take_while(move |c| !delimiters.contains(&c))(input.clone())?;
   130     Ok((i, convert_from_str(str)?.1))
   121     Ok((i, convert_from_str(str)?.1))
   131 }
   122 }
   132 
   123 
   133 fn yes_no_line(input: &[u8]) -> HwResult<bool> {
   124 fn yes_no_line(input: &[u8]) -> HwResult<bool> {
   134     alt((
   125     alt((
   135         |i| tag_no_case(b"YES")(i).map(|(i, _)| (i, true)),
   126         map(tag_no_case(b"YES"), |_| true),
   136         |i| tag_no_case(b"NO")(i).map(|(i, _)| (i, false)),
   127         map(tag_no_case(b"NO"), |_| false),
   137     ))(input)
   128     ))(input)
   138 }
   129 }
   139 
   130 
   140 fn opt_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   131 fn opt_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   141     alt((
   132     alt((
   142         |i| peek(end_of_message)(i).map(|(i, _)| (i, None)),
   133         map(peek(end_of_message), |_| None),
   143         |i| precededc(i, hw_tag("\n"), a_line).map(|(i, v)| (i, Some(v))),
   134         map(preceded(tag("\n"), a_line), Some),
   144     ))(input)
   135     ))(input)
   145 }
   136 }
   146 
   137 
   147 fn spaces(input: &[u8]) -> HwResult<&[u8]> {
   138 fn spaces(input: &[u8]) -> HwResult<&[u8]> {
   148     precededc(input, hw_tag(" "), |i| take_while(|c| c == b' ')(i))
   139     preceded(tag(" "), take_while(|c| c == b' '))(input)
   149 }
   140 }
   150 
   141 
   151 fn opt_space_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   142 fn opt_space_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> {
   152     alt((
   143     alt((
   153         |i| peek(end_of_message)(i).map(|(i, _)| (i, None)),
   144         map(peek(end_of_message), |_| None),
   154         |i| precededc(i, spaces, a_line).map(|(i, v)| (i, Some(v))),
   145         map(preceded(spaces, a_line), Some),
   155     ))(input)
   146     ))(input)
   156 }
   147 }
   157 
   148 
   158 fn hedgehog_array(input: &[u8]) -> HwResult<[HedgehogInfo; 8]> {
   149 fn hedgehog_array(input: &[u8]) -> HwResult<[HedgehogInfo; 8]> {
   159     fn hedgehog_line(input: &[u8]) -> HwResult<HedgehogInfo> {
   150     fn hedgehog_line(input: &[u8]) -> HwResult<HedgehogInfo> {
   160         let (i, name) = terminatedc(input, a_line, newline)?;
   151         let (i, name) = terminated(a_line, newline)(input)?;
   161         let (i, hat) = a_line(i)?;
   152         let (i, hat) = a_line(i)?;
   162         Ok((i, HedgehogInfo { name, hat }))
   153         Ok((i, HedgehogInfo { name, hat }))
   163     }
   154     }
   164 
   155 
   165     let (i, h1) = terminatedc(input, hedgehog_line, newline)?;
   156     let (i, h1) = terminated(hedgehog_line, newline)(input)?;
   166     let (i, h2) = terminatedc(i, hedgehog_line, newline)?;
   157     let (i, h2) = terminated(hedgehog_line, newline)(i)?;
   167     let (i, h3) = terminatedc(i, hedgehog_line, newline)?;
   158     let (i, h3) = terminated(hedgehog_line, newline)(i)?;
   168     let (i, h4) = terminatedc(i, hedgehog_line, newline)?;
   159     let (i, h4) = terminated(hedgehog_line, newline)(i)?;
   169     let (i, h5) = terminatedc(i, hedgehog_line, newline)?;
   160     let (i, h5) = terminated(hedgehog_line, newline)(i)?;
   170     let (i, h6) = terminatedc(i, hedgehog_line, newline)?;
   161     let (i, h6) = terminated(hedgehog_line, newline)(i)?;
   171     let (i, h7) = terminatedc(i, hedgehog_line, newline)?;
   162     let (i, h7) = terminated(hedgehog_line, newline)(i)?;
   172     let (i, h8) = hedgehog_line(i)?;
   163     let (i, h8) = hedgehog_line(i)?;
   173 
   164 
   174     Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8]))
   165     Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8]))
   175 }
   166 }
   176 
   167 
   177 fn voting(input: &[u8]) -> HwResult<VoteType> {
   168 fn voting(input: &[u8]) -> HwResult<VoteType> {
   178     alt((
   169     alt((
   179         |i| tag_no_case("PAUSE")(i).map(|(i, _)| (i, VoteType::Pause)),
   170         map(tag_no_case("PAUSE"), |_| VoteType::Pause),
   180         |i| tag_no_case("NEWSEED")(i).map(|(i, _)| (i, VoteType::NewSeed)),
   171         map(tag_no_case("NEWSEED"), |_| VoteType::NewSeed),
   181         |i| {
   172         map(
   182             precededc(i, |i| precededc(i, hw_tag_no_case("KICK"), spaces), a_line)
   173             preceded(pair(tag_no_case("KICK"), spaces), a_line),
   183                 .map(|(i, s)| (i, VoteType::Kick(s)))
   174             VoteType::Kick,
   184         },
   175         ),
   185         |i| {
   176         map(
   186             precededc(
   177             preceded(pair(tag_no_case("HEDGEHOGS"), spaces), u8_line),
   187                 i,
   178             VoteType::HedgehogsPerTeam,
   188                 |i| precededc(i, hw_tag_no_case("HEDGEHOGS"), spaces),
   179         ),
   189                 u8_line,
   180         map(
   190             )
   181             preceded(tag_no_case("MAP"), opt_space_arg),
   191             .map(|(i, n)| (i, VoteType::HedgehogsPerTeam(n)))
   182             VoteType::Map,
   192         },
   183         ),
   193         |i| precededc(i, hw_tag_no_case("MAP"), opt_space_arg).map(|(i, v)| (i, VoteType::Map(v))),
       
   194     ))(input)
   184     ))(input)
   195 }
   185 }
   196 
   186 
   197 fn no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   187 fn no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   198     fn messagec<'a>(
   188     fn messagec<'a>(
   199         input: &'a [u8],
   189         input: &'a [u8],
   200         name: &'a str,
   190         name: &'a str,
   201         msg: HwProtocolMessage,
   191         msg: HwProtocolMessage,
   202     ) -> HwResult<'a, HwProtocolMessage> {
   192     ) -> HwResult<'a, HwProtocolMessage> {
   203         tag(name)(input).map(|(i, _)| (i, msg.clone()))
   193         map(tag(name), |_| msg.clone())(input)
   204     }
   194     }
   205 
   195 
   206     alt((
   196     alt((
   207         |i| messagec(i, "PING", Ping),
   197         |i| messagec(i, "PING", Ping),
   208         |i| messagec(i, "PONG", Pong),
   198         |i| messagec(i, "PONG", Pong),
   226     ) -> HwResult<'a, HwProtocolMessage>
   216     ) -> HwResult<'a, HwProtocolMessage>
   227     where
   217     where
   228         F: Fn(&[u8]) -> HwResult<T>,
   218         F: Fn(&[u8]) -> HwResult<T>,
   229         G: Fn(T) -> HwProtocolMessage,
   219         G: Fn(T) -> HwProtocolMessage,
   230     {
   220     {
   231         precededc(input, hw_tag(name), parser).map(|(i, v)| (i, constructor(v)))
   221         map(preceded(tag(name), parser), constructor)(input)
   232     }
   222     }
   233 
   223 
   234     alt((
   224     alt((
   235         |i| messagec(i, "NICK\n", a_line, Nick),
   225         |i| messagec(i, "NICK\n", a_line, Nick),
   236         |i| messagec(i, "INFO\n", a_line, Info),
   226         |i| messagec(i, "INFO\n", a_line, Info),
   253     fn cmdc_no_arg<'a>(
   243     fn cmdc_no_arg<'a>(
   254         input: &'a [u8],
   244         input: &'a [u8],
   255         name: &'a str,
   245         name: &'a str,
   256         msg: HwProtocolMessage,
   246         msg: HwProtocolMessage,
   257     ) -> HwResult<'a, HwProtocolMessage> {
   247     ) -> HwResult<'a, HwProtocolMessage> {
   258         tag_no_case(name)(input).map(|(i, _)| (i, msg.clone()))
   248         map(tag_no_case(name), |_| msg.clone())(input)
   259     }
   249     }
   260 
   250 
   261     fn cmdc_single_arg<'a, T, F, G>(
   251     fn cmdc_single_arg<'a, T, F, G>(
   262         input: &'a [u8],
   252         input: &'a [u8],
   263         name: &'a str,
   253         name: &'a str,
   266     ) -> HwResult<'a, HwProtocolMessage>
   256     ) -> HwResult<'a, HwProtocolMessage>
   267     where
   257     where
   268         F: Fn(&'a [u8]) -> HwResult<'a, T>,
   258         F: Fn(&'a [u8]) -> HwResult<'a, T>,
   269         G: Fn(T) -> HwProtocolMessage,
   259         G: Fn(T) -> HwProtocolMessage,
   270     {
   260     {
   271         precededc(input, |i| pairc(i, hw_tag_no_case(name), spaces), parser)
   261         map(
   272             .map(|(i, v)| (i, constructor(v)))
   262             preceded(pair(tag_no_case(name), spaces), parser),
       
   263             constructor,
       
   264         )(input)
   273     }
   265     }
   274 
   266 
   275     fn cmd_no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   267     fn cmd_no_arg_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   276         alt((
   268         alt((
   277             |i| cmdc_no_arg(i, "STATS", Stats),
   269             |i| cmdc_no_arg(i, "STATS", Stats),
   297             |i| cmdc_single_arg(i, "MAXTEAMS", u8_line, MaxTeams),
   289             |i| cmdc_single_arg(i, "MAXTEAMS", u8_line, MaxTeams),
   298             |i| cmdc_single_arg(i, "CALLVOTE", voting, |v| CallVote(Some(v))),
   290             |i| cmdc_single_arg(i, "CALLVOTE", voting, |v| CallVote(Some(v))),
   299         ))(input)
   291         ))(input)
   300     }
   292     }
   301 
   293 
   302     precededc(
   294     preceded(
   303         input,
   295         tag("CMD\n"),
   304         hw_tag("CMD\n"),
       
   305         alt((
   296         alt((
   306             cmd_no_arg_message,
   297             cmd_no_arg_message,
   307             cmd_single_arg_message,
   298             cmd_single_arg_message,
   308             |i| tag_no_case("CALLVOTE")(i).map(|(i, _)| (i, CallVote(None))),
   299             map(tag_no_case("CALLVOTE"), |_| CallVote(None)),
   309             |i| {
   300             map(
   310                 precededc(i, hw_tag_no_case("GREETING"), opt_space_arg)
   301                 preceded(tag_no_case("GREETING"), opt_space_arg),
   311                     .map(|(i, s)| (i, Greeting(s)))
   302                 Greeting,
   312             },
   303             ),
   313             |i| precededc(i, hw_tag_no_case("PART"), opt_space_arg).map(|(i, s)| (i, Part(s))),
   304             map(preceded(tag_no_case("PART"), opt_space_arg), Part),
   314             |i| precededc(i, hw_tag_no_case("QUIT"), opt_space_arg).map(|(i, s)| (i, Quit(s))),
   305             map(preceded(tag_no_case("QUIT"), opt_space_arg), Quit),
   315             |i| {
   306             map(
   316                 precededc(i, hw_tag_no_case("SAVE"), |i| {
   307                 preceded(
   317                     pairc(
   308                     tag_no_case("SAVE"),
   318                         i,
   309                     pair(preceded(spaces, cmd_arg), preceded(spaces, cmd_arg)),
   319                         |i| precededc(i, spaces, cmd_arg),
   310                 ),
   320                         |i| precededc(i, spaces, cmd_arg),
   311                 |(n, l)| Save(n, l),
   321                     )
   312             ),
   322                 })
   313             map(
   323                 .map(|(i, (n, l))| (i, Save(n, l)))
   314                 preceded(
   324             },
   315                     tag_no_case("RND"),
   325             |i| {
   316                     alt((
   326                 let (i, _) = tag_no_case("RND")(i)?;
   317                         map(peek(end_of_message), |_| vec![]),
   327                 let (i, v) = alt((
   318                         preceded(spaces, separated_list(spaces, cmd_arg)),
   328                     |i| peek(end_of_message)(i).map(|(i, _)| (i, vec![])),
   319                     )),
   329                     |i| {
   320                 ),
   330                         let (i, _) = spaces(i)?;
   321                 Rnd,
   331                         let (i, v) = separated_list(spaces, cmd_arg)(i)?;
   322             ),
   332                         Ok((i, v))
       
   333                     },
       
   334                 ))(i)?;
       
   335                 Ok((i, Rnd(v)))
       
   336             },
       
   337         )),
   323         )),
   338     )
   324     )(input)
   339 }
   325 }
   340 
   326 
   341 fn config_message<'a>(input: &'a [u8]) -> HwResult<'a, HwProtocolMessage> {
   327 fn config_message<'a>(input: &'a [u8]) -> HwResult<'a, HwProtocolMessage> {
   342     fn cfgc_single_arg<'a, T, F, G>(
   328     fn cfgc_single_arg<'a, T, F, G>(
   343         input: &'a [u8],
   329         input: &'a [u8],
   347     ) -> HwResult<'a, GameCfg>
   333     ) -> HwResult<'a, GameCfg>
   348     where
   334     where
   349         F: Fn(&[u8]) -> HwResult<T>,
   335         F: Fn(&[u8]) -> HwResult<T>,
   350         G: Fn(T) -> GameCfg,
   336         G: Fn(T) -> GameCfg,
   351     {
   337     {
   352         precededc(input, |i| terminatedc(i, hw_tag(name), newline), parser)
   338         map(preceded(pair(tag(name), newline), parser), constructor)(input)
   353             .map(|(i, v)| (i, constructor(v)))
   339     }
   354     }
   340 
   355 
   341     let (i, cfg) = preceded(
   356     let (i, cfg) = precededc(
   342         tag("CFG\n"),
   357         input,
       
   358         hw_tag("CFG\n"),
       
   359         alt((
   343         alt((
   360             |i| cfgc_single_arg(i, "THEME", a_line, GameCfg::Theme),
   344             |i| cfgc_single_arg(i, "THEME", a_line, GameCfg::Theme),
   361             |i| cfgc_single_arg(i, "SCRIPT", a_line, GameCfg::Script),
   345             |i| cfgc_single_arg(i, "SCRIPT", a_line, GameCfg::Script),
   362             |i| cfgc_single_arg(i, "MAP", a_line, GameCfg::MapType),
   346             |i| cfgc_single_arg(i, "MAP", a_line, GameCfg::MapType),
   363             |i| cfgc_single_arg(i, "MAPGEN", u32_line, GameCfg::MapGenerator),
   347             |i| cfgc_single_arg(i, "MAPGEN", u32_line, GameCfg::MapGenerator),
   364             |i| cfgc_single_arg(i, "MAZE_SIZE", u32_line, GameCfg::MazeSize),
   348             |i| cfgc_single_arg(i, "MAZE_SIZE", u32_line, GameCfg::MazeSize),
   365             |i| cfgc_single_arg(i, "TEMPLATE", u32_line, GameCfg::Template),
   349             |i| cfgc_single_arg(i, "TEMPLATE", u32_line, GameCfg::Template),
   366             |i| cfgc_single_arg(i, "FEATURE_SIZE", u32_line, GameCfg::FeatureSize),
   350             |i| cfgc_single_arg(i, "FEATURE_SIZE", u32_line, GameCfg::FeatureSize),
   367             |i| cfgc_single_arg(i, "SEED", a_line, GameCfg::Seed),
   351             |i| cfgc_single_arg(i, "SEED", a_line, GameCfg::Seed),
   368             |i| cfgc_single_arg(i, "DRAWNMAP", a_line, GameCfg::DrawnMap),
   352             |i| cfgc_single_arg(i, "DRAWNMAP", a_line, GameCfg::DrawnMap),
   369             |i| {
   353             preceded(pair(tag("AMMO"), newline), |i| {
   370                 precededc(
   354                 let (i, name) = a_line(i)?;
   371                     i,
   355                 let (i, value) = opt_arg(i)?;
   372                     |i| terminatedc(i, hw_tag("AMMO"), newline),
   356                 Ok((i, GameCfg::Ammo(name, value)))
   373                     |i| {
   357             }),
   374                         let (i, name) = a_line(i)?;
   358             preceded(pair(tag("SCHEME"), newline), |i| {
   375                         let (i, value) = opt_arg(i)?;
   359                 let (i, name) = a_line(i)?;
   376                         Ok((i, GameCfg::Ammo(name, value)))
   360                 let (i, values) = alt((
   377                     },
   361                     map(peek(end_of_message), |_| None),
   378                 )
   362                     map(preceded(newline, separated_list(newline, a_line)), Some),
   379             },
   363                 ))(i)?;
   380             |i| {
   364                 Ok((i, GameCfg::Scheme(name, values.unwrap_or_default())))
   381                 precededc(
   365             }),
   382                     i,
       
   383                     |i| terminatedc(i, hw_tag("SCHEME"), newline),
       
   384                     |i| {
       
   385                         let (i, name) = a_line(i)?;
       
   386                         let (i, values) = alt((
       
   387                             |i| peek(end_of_message)(i).map(|(i, _)| (i, None)),
       
   388                             |i| {
       
   389                                 precededc(i, newline, |i| separated_list(newline, a_line)(i))
       
   390                                     .map(|(i, v)| (i, Some(v)))
       
   391                             },
       
   392                         ))(i)?;
       
   393                         Ok((i, GameCfg::Scheme(name, values.unwrap_or_default())))
       
   394                     },
       
   395                 )
       
   396             },
       
   397         )),
   366         )),
   398     )?;
   367     )(input)?;
   399     Ok((i, Cfg(cfg)))
   368     Ok((i, Cfg(cfg)))
   400 }
   369 }
   401 
   370 
   402 fn server_var_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   371 fn server_var_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   403     precededc(
   372     map(
   404         input,
   373         preceded(
   405         hw_tag("SET_SERVER_VAR\n"),
   374             tag("SET_SERVER_VAR\n"),
   406         alt((
   375             alt((
   407             |i| {
   376                 map(preceded(tag("MOTD_NEW\n"), a_line), ServerVar::MOTDNew),
   408                 precededc(i, hw_tag("MOTD_NEW\n"), a_line)
   377                 map(preceded(tag("MOTD_OLD\n"), a_line), ServerVar::MOTDOld),
   409                     .map(|(i, s)| (i, SetServerVar(ServerVar::MOTDNew(s))))
   378                 map(
   410             },
   379                     preceded(tag("LATEST_PROTO\n"), u16_line),
   411             |i| {
   380                     ServerVar::LatestProto,
   412                 precededc(i, hw_tag("MOTD_OLD\n"), a_line)
   381                 ),
   413                     .map(|(i, s)| (i, SetServerVar(ServerVar::MOTDOld(s))))
   382             )),
   414             },
   383         ),
   415             |i| {
   384         SetServerVar,
   416                 precededc(i, hw_tag("LATEST_PROTO\n"), u16_line)
   385     )(input)
   417                     .map(|(i, n)| (i, SetServerVar(ServerVar::LatestProto(n))))
       
   418             },
       
   419         )),
       
   420     )
       
   421 }
   386 }
   422 
   387 
   423 fn complex_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   388 fn complex_message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   424     alt((
   389     alt((
   425         |i| {
   390         preceded(pair(tag("PASSWORD"), newline), |i| {
   426             precededc(
   391             let (i, pass) = terminated(a_line, newline)(i)?;
       
   392             let (i, salt) = a_line(i)?;
       
   393             Ok((i, Password(pass, salt)))
       
   394         }),
       
   395         preceded(pair(tag("CHECKER"), newline), |i| {
       
   396             let (i, protocol) = terminated(u16_line, newline)(i)?;
       
   397             let (i, name) = terminated(a_line, newline)(i)?;
       
   398             let (i, pass) = a_line(i)?;
       
   399             Ok((i, Checker(protocol, name, pass)))
       
   400         }),
       
   401         preceded(pair(tag("CREATE_ROOM"), newline), |i| {
       
   402             let (i, name) = a_line(i)?;
       
   403             let (i, pass) = opt_arg(i)?;
       
   404             Ok((i, CreateRoom(name, pass)))
       
   405         }),
       
   406         preceded(pair(tag("JOIN_ROOM"), newline), |i| {
       
   407             let (i, name) = a_line(i)?;
       
   408             let (i, pass) = opt_arg(i)?;
       
   409             Ok((i, JoinRoom(name, pass)))
       
   410         }),
       
   411         preceded(pair(tag("ADD_TEAM"), newline), |i| {
       
   412             let (i, name) = terminated(a_line, newline)(i)?;
       
   413             let (i, color) = terminated(u8_line, newline)(i)?;
       
   414             let (i, grave) = terminated(a_line, newline)(i)?;
       
   415             let (i, fort) = terminated(a_line, newline)(i)?;
       
   416             let (i, voice_pack) = terminated(a_line, newline)(i)?;
       
   417             let (i, flag) = terminated(a_line, newline)(i)?;
       
   418             let (i, difficulty) = terminated(u8_line, newline)(i)?;
       
   419             let (i, hedgehogs) = hedgehog_array(i)?;
       
   420             Ok((
   427                 i,
   421                 i,
   428                 |i| terminatedc(i, hw_tag("PASSWORD"), newline),
   422                 AddTeam(Box::new(TeamInfo {
   429                 |i| {
   423                     owner: String::new(),
   430                     let (i, pass) = terminatedc(i, a_line, newline)?;
   424                     name,
   431                     let (i, salt) = a_line(i)?;
   425                     color,
   432                     Ok((i, Password(pass, salt)))
   426                     grave,
   433                 },
   427                     fort,
   434             )
   428                     voice_pack,
   435         },
   429                     flag,
   436         |i| {
   430                     difficulty,
   437             precededc(
   431                     hedgehogs,
   438                 i,
   432                     hedgehogs_number: 0,
   439                 |i| terminatedc(i, hw_tag("CHECKER"), newline),
   433                 })),
   440                 |i| {
   434             ))
   441                     let (i, protocol) = terminatedc(i, u16_line, newline)?;
   435         }),
   442                     let (i, name) = terminatedc(i, a_line, newline)?;
   436         preceded(pair(tag("HH_NUM"), newline), |i| {
   443                     let (i, pass) = a_line(i)?;
   437             let (i, name) = terminated(a_line, newline)(i)?;
   444                     Ok((i, Checker(protocol, name, pass)))
   438             let (i, count) = u8_line(i)?;
   445                 },
   439             Ok((i, SetHedgehogsNumber(name, count)))
   446             )
   440         }),
   447         },
   441         preceded(pair(tag("TEAM_COLOR"), newline), |i| {
   448         |i| {
   442             let (i, name) = terminated(a_line, newline)(i)?;
   449             precededc(
   443             let (i, color) = u8_line(i)?;
   450                 i,
   444             Ok((i, SetTeamColor(name, color)))
   451                 |i| terminatedc(i, hw_tag("CREATE_ROOM"), newline),
   445         }),
   452                 |i| {
   446         preceded(pair(tag("BAN"), newline), |i| {
   453                     let (i, name) = a_line(i)?;
   447             let (i, n) = terminated(a_line, newline)(i)?;
   454                     let (i, pass) = opt_arg(i)?;
   448             let (i, r) = terminated(a_line, newline)(i)?;
   455                     Ok((i, CreateRoom(name, pass)))
   449             let (i, t) = u32_line(i)?;
   456                 },
   450             Ok((i, Ban(n, r, t)))
   457             )
   451         }),
   458         },
   452         preceded(pair(tag("BAN_IP"), newline), |i| {
   459         |i| {
   453             let (i, n) = terminated(a_line, newline)(i)?;
   460             precededc(
   454             let (i, r) = terminated(a_line, newline)(i)?;
   461                 i,
   455             let (i, t) = u32_line(i)?;
   462                 |i| terminatedc(i, hw_tag("JOIN_ROOM"), newline),
   456             Ok((i, BanIP(n, r, t)))
   463                 |i| {
   457         }),
   464                     let (i, name) = a_line(i)?;
   458         preceded(pair(tag("BAN_NICK"), newline), |i| {
   465                     let (i, pass) = opt_arg(i)?;
   459             let (i, n) = terminated(a_line, newline)(i)?;
   466                     Ok((i, JoinRoom(name, pass)))
   460             let (i, r) = terminated(a_line, newline)(i)?;
   467                 },
   461             let (i, t) = u32_line(i)?;
   468             )
   462             Ok((i, BanNick(n, r, t)))
   469         },
   463         }),
   470         |i| {
       
   471             precededc(
       
   472                 i,
       
   473                 |i| terminatedc(i, hw_tag("ADD_TEAM"), newline),
       
   474                 |i| {
       
   475                     let (i, name) = terminatedc(i, a_line, newline)?;
       
   476                     let (i, color) = terminatedc(i, u8_line, newline)?;
       
   477                     let (i, grave) = terminatedc(i, a_line, newline)?;
       
   478                     let (i, fort) = terminatedc(i, a_line, newline)?;
       
   479                     let (i, voice_pack) = terminatedc(i, a_line, newline)?;
       
   480                     let (i, flag) = terminatedc(i, a_line, newline)?;
       
   481                     let (i, difficulty) = terminatedc(i, u8_line, newline)?;
       
   482                     let (i, hedgehogs) = hedgehog_array(i)?;
       
   483                     Ok((
       
   484                         i,
       
   485                         AddTeam(Box::new(TeamInfo {
       
   486                             owner: String::new(),
       
   487                             name,
       
   488                             color,
       
   489                             grave,
       
   490                             fort,
       
   491                             voice_pack,
       
   492                             flag,
       
   493                             difficulty,
       
   494                             hedgehogs,
       
   495                             hedgehogs_number: 0,
       
   496                         })),
       
   497                     ))
       
   498                 },
       
   499             )
       
   500         },
       
   501         |i| {
       
   502             precededc(
       
   503                 i,
       
   504                 |i| terminatedc(i, hw_tag("HH_NUM"), newline),
       
   505                 |i| {
       
   506                     let (i, name) = terminatedc(i, a_line, newline)?;
       
   507                     let (i, count) = u8_line(i)?;
       
   508                     Ok((i, SetHedgehogsNumber(name, count)))
       
   509                 },
       
   510             )
       
   511         },
       
   512         |i| {
       
   513             precededc(
       
   514                 i,
       
   515                 |i| terminatedc(i, hw_tag("TEAM_COLOR"), newline),
       
   516                 |i| {
       
   517                     let (i, name) = terminatedc(i, a_line, newline)?;
       
   518                     let (i, color) = u8_line(i)?;
       
   519                     Ok((i, SetTeamColor(name, color)))
       
   520                 },
       
   521             )
       
   522         },
       
   523         |i| {
       
   524             precededc(
       
   525                 i,
       
   526                 |i| terminatedc(i, hw_tag("BAN"), newline),
       
   527                 |i| {
       
   528                     let (i, n) = terminatedc(i, a_line, newline)?;
       
   529                     let (i, r) = terminatedc(i, a_line, newline)?;
       
   530                     let (i, t) = u32_line(i)?;
       
   531                     Ok((i, Ban(n, r, t)))
       
   532                 },
       
   533             )
       
   534         },
       
   535         |i| {
       
   536             precededc(
       
   537                 i,
       
   538                 |i| terminatedc(i, hw_tag("BAN_IP"), newline),
       
   539                 |i| {
       
   540                     let (i, n) = terminatedc(i, a_line, newline)?;
       
   541                     let (i, r) = terminatedc(i, a_line, newline)?;
       
   542                     let (i, t) = u32_line(i)?;
       
   543                     Ok((i, BanIP(n, r, t)))
       
   544                 },
       
   545             )
       
   546         },
       
   547         |i| {
       
   548             precededc(
       
   549                 i,
       
   550                 |i| terminatedc(i, hw_tag("BAN_NICK"), newline),
       
   551                 |i| {
       
   552                     let (i, n) = terminatedc(i, a_line, newline)?;
       
   553                     let (i, r) = terminatedc(i, a_line, newline)?;
       
   554                     let (i, t) = u32_line(i)?;
       
   555                     Ok((i, BanNick(n, r, t)))
       
   556                 },
       
   557             )
       
   558         },
       
   559     ))(input)
   464     ))(input)
   560 }
   465 }
   561 
   466 
   562 pub fn malformed_message(input: &[u8]) -> HwResult<()> {
   467 pub fn malformed_message(input: &[u8]) -> HwResult<()> {
   563     let (i, _) = terminatedc(input, |i| take_until(&b"\n\n"[..])(i), end_of_message)?;
   468     map(terminated(take_until(&b"\n\n"[..]), end_of_message), |_| ())(input)
   564     Ok((i, ()))
       
   565 }
   469 }
   566 
   470 
   567 pub fn message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   471 pub fn message(input: &[u8]) -> HwResult<HwProtocolMessage> {
   568     precededc(
   472     preceded(
   569         input,
   473         take_while(|c| c == b'\n'),
   570         |i| take_while(|c| c == b'\n')(i),
   474         terminated(
   571         |i| {
   475             alt((
   572             terminatedc(
   476                 no_arg_message,
   573                 i,
   477                 single_arg_message,
   574                 alt((
   478                 cmd_message,
   575                     no_arg_message,
   479                 config_message,
   576                     single_arg_message,
   480                 server_var_message,
   577                     cmd_message,
   481                 complex_message,
   578                     config_message,
   482             )),
   579                     server_var_message,
   483             end_of_message,
   580                     complex_message,
   484         ),
   581                 )),
   485     )(input)
   582                 end_of_message,
       
   583             )
       
   584         },
       
   585     )
       
   586 }
   486 }
   587 
   487 
   588 #[cfg(test)]
   488 #[cfg(test)]
   589 mod test {
   489 mod test {
   590     use super::message;
   490     use super::message;