use std::fmt;
use std::io::{Read, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use Result;
use Error::ResponseError;
#[derive(Clone)]
pub enum OpCode {
Reply = 1,
Update = 2001,
Insert = 2002,
Query = 2004,
GetMore = 2005,
}
impl OpCode {
pub fn from_i32(i: i32) -> Option<OpCode> {
match i {
1 => Some(OpCode::Reply),
2001 => Some(OpCode::Update),
2002 => Some(OpCode::Insert),
2004 => Some(OpCode::Query),
2005 => Some(OpCode::GetMore),
_ => None,
}
}
}
impl fmt::Display for OpCode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
OpCode::Reply => write!(fmt, "OP_REPLY"),
OpCode::Update => write!(fmt, "OP_UPDATE"),
OpCode::Insert => write!(fmt, "OP_INSERT"),
OpCode::Query => write!(fmt, "OP_QUERY"),
OpCode::GetMore => write!(fmt, "OP_GET_MORE"),
}
}
}
#[derive(Clone)]
pub struct Header {
pub message_length: i32,
pub request_id: i32,
response_to: i32,
pub op_code: OpCode,
}
impl Header {
pub fn new(message_length: i32, request_id: i32, response_to: i32, op_code: OpCode) -> Header {
Header {
message_length: message_length,
request_id: request_id,
response_to: response_to,
op_code: op_code,
}
}
fn new_request(message_length: i32, request_id: i32, op_code: OpCode) -> Header {
Header::new(message_length, request_id, 0, op_code)
}
pub fn new_update(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Update)
}
pub fn new_insert(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Insert)
}
pub fn new_query(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::Query)
}
pub fn new_get_more(message_length: i32, request_id: i32) -> Header {
Header::new_request(message_length, request_id, OpCode::GetMore)
}
pub fn write(&self, buffer: &mut Write) -> Result<()> {
try!(buffer.write_i32::<LittleEndian>(self.message_length));
try!(buffer.write_i32::<LittleEndian>(self.request_id));
try!(buffer.write_i32::<LittleEndian>(self.response_to));
try!(buffer.write_i32::<LittleEndian>(self.op_code.clone() as i32));
let _ = buffer.flush();
Ok(())
}
pub fn read(buffer: &mut Read) -> Result<Header> {
let message_length = try!(buffer.read_i32::<LittleEndian>());
let request_id = try!(buffer.read_i32::<LittleEndian>());
let response_to = try!(buffer.read_i32::<LittleEndian>());
let op_code_i32 = try!(buffer.read_i32::<LittleEndian>());
let op_code = match OpCode::from_i32(op_code_i32) {
Some(code) => code,
_ => {
return Err(ResponseError(format!("Invalid header opcode from server: {}.",
op_code_i32)))
}
};
Ok(Header::new(message_length, request_id, response_to, op_code))
}
}