use crate::command::IRCCommand;
use crate::error::{MessageError, MessageErrorDetails};
#[derive(Debug)]
pub struct Message {
pub source: Option<String>,
pub command: IRCCommand,
pub params: Vec<String>,
pub valid: bool,
pub error: Option<MessageError>,
}
impl Message {
pub fn parse(raw_input: Vec<u8>, source_client: Option<String>) -> Result<Self, MessageError> {
if raw_input.len() < 1 {
return Err(MessageError {
detail: MessageErrorDetails::NoData,
});
}
let split_message: Vec<Vec<u8>> = raw_input.into_iter().fold(Vec::new(), |mut acc, x| {
if x == 32 || acc.is_empty() {
acc.push(Vec::new());
}
if x != 32 {
acc.last_mut().unwrap().push(x);
}
acc
});
let mut source = source_client.clone();
let mut command_index = 0;
if split_message[0][0] == 58 {
command_index = 1;
let parsed_source = match Message::parse_prefix(split_message[0].clone()) {
Ok(x) => x,
Err(y) => return Err(y),
};
source = source_client.or_else(|| Some(parsed_source));
}
if split_message.len() < command_index + 1 {
return Err(MessageError {
detail: MessageErrorDetails::NoCommand,
});
}
let irc_command = match Message::parse_command(split_message[command_index].clone()) {
Ok(x) => x,
Err(y) => return Err(y),
};
Ok(Message {
source: source,
command: irc_command,
valid: true,
params: Vec::new(),
error: None,
})
}
fn parse_command(command_input: Vec<u8>) -> Result<IRCCommand, MessageError> {
let raw_command = match String::from_utf8(command_input) {
Ok(x) => x,
Err(_) => {
return Err(MessageError {
detail: MessageErrorDetails::FailedCommandParse,
})
}
};
match raw_command.as_str() {
"NAMES" => return Ok(IRCCommand::NAMES),
"NICK" => return Ok(IRCCommand::NICK),
"PRIVMSG" => return Ok(IRCCommand::PRIVMSG),
_ => {
return Err(MessageError {
detail: MessageErrorDetails::InvalidCommand,
})
}
}
}
fn parse_prefix(prefix_input: Vec<u8>) -> Result<String, MessageError> {
if prefix_input.len() < 2 {
return Err(MessageError {
detail: MessageErrorDetails::NoClient,
});
}
if prefix_input[0] == 58 {
match String::from_utf8(prefix_input.clone().split_off(1)) {
Ok(x) => return Ok(x),
Err(_) => {
return Err(MessageError {
detail: MessageErrorDetails::FailedParse,
});
}
}
} else {
return Err(MessageError {
detail: MessageErrorDetails::NoPrefix,
});
}
}
}
#[test]
fn test_valid_command() {
let message = "NAMES".as_bytes().to_vec();
let command = Message::parse_command(message);
assert_eq!(command, Ok(IRCCommand::NAMES));
}
#[test]
fn test_invalid_command() {
let message = "NAMES2".as_bytes().to_vec();
let command = Message::parse_command(message);
assert!(command.is_err());
}
#[test]
fn test_blank_command() {
let message = "".as_bytes().to_vec();
let command = Message::parse_command(message);
assert!(command.is_err());
}
#[test]
fn test_valid_source() {
let message = ":TestClient".as_bytes().to_vec();
let source = Message::parse_prefix(message);
let source_string = match source {
Ok(x) => x,
Err(_) => "None".to_string(),
};
assert_eq!(source_string, "TestClient");
}
#[test]
fn test_invalid_source() {
let message = ":".as_bytes().to_vec();
let source = Message::parse_prefix(message);
let source_string = match source {
Ok(x) => x,
Err(y) => y.detail.error_text().to_string(),
};
assert_eq!(source_string, "No client identifier");
}
#[test]
fn test_empty_source() {
let message = Vec::new();
let source = Message::parse_prefix(message);
let source_string = match source {
Ok(x) => x,
Err(y) => y.detail.error_text().to_string(),
};
assert_eq!(source_string, "No client identifier");
}
#[test]
fn test_format_source() {
let message = "TestClient".as_bytes().to_vec();
let source = Message::parse_prefix(message);
let source_string = match source {
Ok(x) => x,
Err(y) => y.detail.error_text().to_string(),
};
assert_eq!(source_string, "Missing : character");
}