use bytes::Bytes;
use protocol::{Command, CommandError};
use serde_json as json;
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Builder)]
#[builder(default)]
pub struct ConnectCommand {
pub verbose: bool,
pub pedantic: bool,
pub tls_required: bool,
#[serde(skip_serializing_if = "Option::is_none")]
auth_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pass: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[builder(default = "self.default_name()?")]
pub name: Option<String>,
#[builder(default = "self.default_lang()?", setter(into))]
pub lang: String,
#[builder(default = "self.default_ver()?", setter(into))]
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
protocol: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
echo: Option<bool>,
}
impl ConnectCommand {
pub fn builder() -> ConnectCommandBuilder {
ConnectCommandBuilder::default()
}
}
impl ConnectCommandBuilder {
fn default_name(&self) -> Result<Option<String>, String> {
Ok(Some("nitox".into()))
}
fn default_ver(&self) -> Result<String, String> {
match ::std::env::var("CARGO_PKG_VERSION") {
Ok(v) => Ok(v),
Err(_) => Ok("0.1.x".into()),
}
}
fn default_lang(&self) -> Result<String, String> {
Ok("rust".into())
}
}
impl Command for ConnectCommand {
const CMD_NAME: &'static [u8] = b"CONNECT";
fn into_vec(self) -> Result<Bytes, CommandError> {
Ok(format!("CONNECT\t{}\r\n", json::to_string(&self)?).as_bytes().into())
}
fn try_parse(buf: &[u8]) -> Result<ConnectCommand, CommandError> {
let len = buf.len();
if buf[len - 2..] != [b'\r', b'\n'] {
return Err(CommandError::IncompleteCommandError);
}
if buf[..7] != *Self::CMD_NAME {
return Err(CommandError::CommandMalformed);
}
Ok(json::from_slice(&buf[7..len - 2])?)
}
}
#[cfg(test)]
mod tests {
use super::{ConnectCommand, ConnectCommandBuilder};
use protocol::Command;
static DEFAULT_CONNECT: &'static str = "CONNECT\t{\"verbose\":false,\"pedantic\":false,\"tls_required\":false,\"name\":\"nitox\",\"lang\":\"rust\",\"version\":\"1.0.0\"}\r\n";
#[test]
fn it_parses() {
let parse_res = ConnectCommand::try_parse(DEFAULT_CONNECT.as_bytes());
assert!(parse_res.is_ok());
let cmd = parse_res.unwrap();
assert_eq!(cmd.verbose, false);
assert_eq!(cmd.pedantic, false);
assert_eq!(cmd.tls_required, false);
assert!(cmd.name.is_some());
assert_eq!(&cmd.name.unwrap(), "nitox");
assert_eq!(&cmd.lang, "rust");
assert_eq!(&cmd.version, "1.0.0");
}
#[test]
fn it_stringifies() {
let cmd = ConnectCommandBuilder::default()
.lang("rust")
.version("1.0.0")
.name(Some("nitox".into()))
.build()
.unwrap();
let cmd_bytes_res = cmd.into_vec();
assert!(cmd_bytes_res.is_ok());
let cmd_bytes = cmd_bytes_res.unwrap();
assert_eq!(DEFAULT_CONNECT, cmd_bytes);
}
}