use super::{commands::*, Command, CommandError};
use bytes::Bytes;
#[derive(Debug, Clone, PartialEq)]
pub enum Op {
INFO(ServerInfo),
CONNECT(ConnectCommand),
PUB(PubCommand),
SUB(SubCommand),
UNSUB(UnsubCommand),
MSG(Message),
PING,
PONG,
OK,
ERR(ServerError),
}
macro_rules! op_from_cmd {
($buf:ident, $cmd:path, $op:path) => {{
use protocol::CommandError;
match $cmd(&$buf) {
Ok(c) => Ok($op(c)),
Err(CommandError::IncompleteCommandError) => return Err(CommandError::IncompleteCommandError),
Err(e) => return Err(e.into()),
}
}};
}
impl Op {
pub fn into_bytes(self) -> Result<Bytes, CommandError> {
Ok(match self {
Op::INFO(si) => si.into_vec()?,
Op::CONNECT(con) => con.into_vec()?,
Op::PUB(pc) => pc.into_vec()?,
Op::SUB(sc) => sc.into_vec()?,
Op::UNSUB(uc) => uc.into_vec()?,
Op::MSG(msg) => msg.into_vec()?,
Op::PING => "PING\r\n".into(),
Op::PONG => "PONG\r\n".into(),
Op::OK => "+OK\r\n".into(),
Op::ERR(se) => format!("-ERR {}\r\n", se).as_bytes().into(),
})
}
pub fn from_bytes(cmd_name: &[u8], buf: &[u8]) -> Result<Self, CommandError> {
match cmd_name {
ServerInfo::CMD_NAME => op_from_cmd!(buf, ServerInfo::try_parse, Op::INFO),
ConnectCommand::CMD_NAME => op_from_cmd!(buf, ConnectCommand::try_parse, Op::CONNECT),
Message::CMD_NAME => op_from_cmd!(buf, Message::try_parse, Op::MSG),
PubCommand::CMD_NAME => op_from_cmd!(buf, PubCommand::try_parse, Op::PUB),
SubCommand::CMD_NAME => op_from_cmd!(buf, SubCommand::try_parse, Op::SUB),
UnsubCommand::CMD_NAME => op_from_cmd!(buf, UnsubCommand::try_parse, Op::UNSUB),
b"PING" => {
if buf == b"PING\r\n" {
Ok(Op::PING)
} else {
Err(CommandError::IncompleteCommandError)
}
}
b"PONG" => {
if buf == b"PONG\r\n" {
Ok(Op::PONG)
} else {
Err(CommandError::IncompleteCommandError)
}
}
b"+OK" => {
if buf == b"+OK\r\n" {
Ok(Op::OK)
} else {
Err(CommandError::IncompleteCommandError)
}
}
b"-ERR" => {
if &buf[buf.len() - 2..] == b"\r\n" {
Ok(Op::ERR(ServerError::from(String::from_utf8(buf[1..].to_vec())?)))
} else {
Err(CommandError::IncompleteCommandError)
}
}
_ => {
if buf.len() > 7 {
Err(CommandError::CommandNotFoundOrSupported)
} else {
Err(CommandError::IncompleteCommandError)
}
}
}
}
}