use std::mem;
use std::io::{Read, Write};
use byteorder::{ReadBytesExt, WriteBytesExt};
use super::header::Header;
use super::header::OpCode;
use super::error::Result;
#[derive(Debug)]
pub struct Message {
header: Header,
target: String,
origin: String,
content_type: String,
body: Vec<u8>
}
impl Message {
pub fn new(request_id: i32, response_to: i32, op_code: OpCode, target: String, origin: String, content_type: String, body: Vec<u8>) -> Result<Message> {
let header_length = mem::size_of::<Header>();
let target_length = target.len() + 1;
let origin_length = origin.len() + 1;
let content_type_length = content_type.len() + 1;
let body_length = body.len();
let total_length = header_length + target_length + origin_length + content_type_length + body_length;
let header = Header::new(total_length as i32, request_id, response_to, op_code);
Ok(Message {
header: header,
target: target,
origin: origin,
content_type: content_type,
body: body
})
}
pub fn get_opcode(&self) -> &OpCode {
&self.header.op_code
}
pub fn len(&self) -> usize {
self.header.message_length as usize
}
pub fn write<W: Write>(&self, buffer: &mut W) -> Result<()> {
self.header.write(buffer)?;
write_cstring(buffer, &self.target)?;
write_cstring(buffer, &self.origin)?;
write_cstring(buffer, &self.content_type)?;
buffer.write(&self.body)?;
Ok(())
}
pub fn read<R: Read>(buffer: &mut R) -> Result<Option<Message>> {
let header = Header::read(buffer)?;
let mut length = header.message_length as usize - mem::size_of::<Header>();
let target = read_cstring(buffer)?;
length -= target.len() + 1;
let origin = read_cstring(buffer)?;
length -= origin.len() + 1;
let content_type = read_cstring(buffer)?;
length -= content_type.len() + 1;
let mut body = vec![0u8; length];
let read_size = buffer.read(&mut body)?;
if read_size < length {
return Ok(None)
}
Ok(Some(Message {
header: header,
target: target,
origin: origin,
content_type: content_type,
body: body
}))
}
}
fn write_cstring<W>(writer: &mut W, s: &str) -> Result<()>
where W: Write + ?Sized
{
writer.write_all(s.as_bytes())?;
writer.write_u8(0)?;
Ok(())
}
fn read_cstring<R: Read + ?Sized>(reader: &mut R) -> Result<String> {
let mut v = Vec::new();
loop {
let c = reader.read_u8()?;
if c == 0 {
break;
}
v.push(c);
}
Ok(String::from_utf8(v)?)
}