add support for additional irc messages types

This commit is contained in:
Nikita Vilunov 2023-02-10 11:46:10 +01:00
parent e5d0722fe0
commit 5d57df3219
2 changed files with 101 additions and 1 deletions

View File

@ -7,13 +7,25 @@ pub enum ClientMessage {
Capability { Capability {
subcommand: CapabilitySubcommand, subcommand: CapabilitySubcommand,
}, },
/// PING /// PING <token>
Ping { Ping {
token: ByteVec, token: ByteVec,
}, },
/// PONG <token>
Pong { Pong {
token: ByteVec, token: ByteVec,
}, },
/// NICK <name>
Nick {
nickname: ByteVec,
},
User {
username: ByteVec,
realname: ByteVec,
},
Quit {
reason: ByteVec,
},
} }
pub fn client_message(input: &[u8]) -> IResult<&[u8], ClientMessage> { pub fn client_message(input: &[u8]) -> IResult<&[u8], ClientMessage> {
@ -21,6 +33,9 @@ pub fn client_message(input: &[u8]) -> IResult<&[u8], ClientMessage> {
client_message_capability, client_message_capability,
client_message_ping, client_message_ping,
client_message_pong, client_message_pong,
client_message_nick,
client_message_user,
client_message_quit,
))(input) ))(input)
} }
@ -55,6 +70,47 @@ fn client_message_pong(input: &[u8]) -> IResult<&[u8], ClientMessage> {
)) ))
} }
fn client_message_nick(input: &[u8]) -> IResult<&[u8], ClientMessage> {
let (input, _) = tag("NICK ")(input)?;
let (input, nickname) = receiver(input)?;
Ok((
input,
ClientMessage::Nick {
nickname: nickname.to_owned(),
},
))
}
fn client_message_user(input: &[u8]) -> IResult<&[u8], ClientMessage> {
let (input, _) = tag("USER ")(input)?;
let (input, username) = receiver(input)?;
let (input, _) = tag(" ")(input)?;
let (input, _) = take(1_usize)(input)?; // 0 in spec, but any in fact
let (input, _) = tag(" * :")(input)?;
let (input, realname) = token(input)?;
Ok((
input,
ClientMessage::User {
username: username.to_owned(),
realname: realname.to_owned(),
},
))
}
fn client_message_quit(input: &[u8]) -> IResult<&[u8], ClientMessage> {
let (input, _) = tag("QUIT :")(input)?;
let (input, reason) = token(input)?;
Ok((
input,
ClientMessage::Quit {
reason: reason.to_vec(),
},
))
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum CapabilitySubcommand { pub enum CapabilitySubcommand {
/// CAP LS {code} /// CAP LS {code}
@ -128,6 +184,27 @@ mod test {
token: b"1337".to_vec(), token: b"1337".to_vec(),
}; };
let result = client_message(input);
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
}
#[test]
fn test_client_message_nick() {
let input = b"NICK SomeNick";
let expected = ClientMessage::Nick {
nickname: b"SomeNick".to_vec(),
};
let result = client_message(input);
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
}
#[test]
fn test_client_message_user() {
let input = b"USER SomeNick 8 * :Real Name";
let expected = ClientMessage::User {
username: b"SomeNick".to_vec(),
realname: b"Real Name".to_vec(),
};
let result = client_message(input); let result = client_message(input);
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result)); assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
} }

View File

@ -26,3 +26,26 @@ fn receiver(input: &[u8]) -> IResult<&[u8], &[u8]> {
fn token(input: &[u8]) -> IResult<&[u8], &[u8]> { fn token(input: &[u8]) -> IResult<&[u8], &[u8]> {
take_while(|i| i != b'\n' && i != b'\r')(input) take_while(|i| i != b'\n' && i != b'\r')(input)
} }
pub enum Chan {
/// #<name> — network-global channel, available from any server in the network.
Global(ByteVec),
/// &<name> — server-local channel, available only to connections to the same server. Rarely used in practice.
Local(ByteVec),
}
fn chan(input: &[u8]) -> IResult<&[u8], Chan> {
fn chan_global(input: &[u8]) -> IResult<&[u8], Chan> {
let (input, _) = tag("#")(input)?;
let (input, name) = receiver(input)?;
Ok((input, Chan::Global(name.to_vec())))
}
fn chan_local(input: &[u8]) -> IResult<&[u8], Chan> {
let (input, _) = tag("&")(input)?;
let (input, name) = receiver(input)?;
Ok((input, Chan::Local(name.to_vec())))
}
alt((chan_global, chan_local))(input)
}