From d59ac09ca06389aa3a96a22eacb86e1693364965 Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Fri, 29 Apr 2016 11:57:04 +0200 Subject: [PATCH] Use ReadFromPacket and WriteToPacket traits to simplify packet I/O. --- Cargo.lock | 7 +- Cargo.toml | 2 +- src/proto/mod.rs | 8 +- src/proto/packet.rs | 312 ++++++++++++++++++++++------------ src/proto/server/request.rs | 72 +++----- src/proto/server/response.rs | 320 ++++++++++++++++------------------- src/result.rs | 18 +- src/user.rs | 24 ++- 8 files changed, 422 insertions(+), 341 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef2b421..1823ece 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "solstice" version = "0.1.0" dependencies = [ - "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "encoding 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -39,6 +39,11 @@ name = "byteorder" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytes" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index a481329..096796c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["letitz"] [dependencies] -byteorder = "^0.4.2" +byteorder = "^0.5.1" encoding = "^0.2" env_logger = "^0.3.2" log = "^0.3.5" diff --git a/src/proto/mod.rs b/src/proto/mod.rs index 31106cd..e3f3539 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -1,7 +1,13 @@ mod packet; pub mod server; -pub use self::packet::{PacketStream, Packet, ReadFromPacket, WriteToPacket}; +pub use self::packet::{ + Packet, + PacketReadError, + PacketStream, + ReadFromPacket, + WriteToPacket +}; use self::server::{ServerRequest, ServerResponse}; diff --git a/src/proto/packet.rs b/src/proto/packet.rs index 8a5ede4..7ebdee6 100644 --- a/src/proto/packet.rs +++ b/src/proto/packet.rs @@ -1,4 +1,8 @@ -use std::{io, mem, net}; +use std::error; +use std::fmt; +use std::io; +use std::mem; +use std::net; use std::iter::repeat; use std::io::{Read, Write}; @@ -9,30 +13,12 @@ use mio::{ Evented, EventLoop, EventSet, Handler, PollOpt, Token, TryRead, TryWrite }; -use result; - const MAX_PACKET_SIZE: usize = 1 << 20; // 1 MiB const U32_SIZE: usize = 4; const MAX_MESSAGE_SIZE: usize = MAX_PACKET_SIZE - U32_SIZE; const MAX_PORT: u32 = (1 << 16) - 1; -/*==================* - * READ FROM PACKET * - *==================*/ - -pub trait ReadFromPacket: Sized { - fn read_from_packet(&mut Packet) -> result::Result; -} - -/*=================* - * WRITE TO PACKET * - *=================*/ - -pub trait WriteToPacket: Sized { - fn write_to_packet(&self, &mut Packet) -> io::Result<()>; -} - /*========* * PACKET * *========*/ @@ -43,6 +29,27 @@ pub struct Packet { bytes: Vec, } +impl io::Read for Packet { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut slice = &self.bytes[self.cursor..]; + let result = slice.read(buf); + if let Ok(num_bytes_read) = result { + self.cursor += num_bytes_read + } + result + } +} + +impl io::Write for Packet { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.bytes.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.bytes.flush() + } +} + impl Packet { pub fn new(code: u32) -> Self { let mut bytes = Vec::new(); @@ -65,139 +72,236 @@ impl Packet { // Writing convenience - pub fn write_str(&mut self, string: &str) -> io::Result { - let bytes = match ISO_8859_1.encode(string, EncoderTrap::Strict) { - Ok(bytes) => bytes, - Err(_) => { - let copy = string.to_string(); - return Err(io::Error::new(io::ErrorKind::Other, copy)) - } - }; - try!(self.write_uint(bytes.len() as u32)); - let n = try!(self.write(&bytes)); - Ok(n + U32_SIZE) + pub fn write_port(&mut self, port: u16) -> io::Result<()> { + self.write_value(port as u32) } - pub fn write_uint(&mut self, n: u32) -> io::Result { - match self.write_u32::(n) { - Ok(()) => Ok(U32_SIZE), - Err(e) => Err(io::Error::from(e)) + /// This function is necessary because not all u16 values are encoded in + /// 4 bytes. + pub fn read_port(&mut self) -> Result { + let port: u32 = try!(self.read_value()); + if port > MAX_PORT { + return Err(PacketReadError::InvalidPortError(port)) } + Ok(port as u16) } - pub fn write_bool(&mut self, b: bool) -> io::Result { - self.write(&[b as u8]) + /// Provides the main way to read data out of a binary packet. + pub fn read_value(&mut self) + -> Result + { + T::read_from_packet(self) } - // Reading convenience + /// Provides the main way to write data into a binary packet. + pub fn write_value(&mut self, val: T) + -> io::Result<()> + { + val.write_to_packet(self) + } - pub fn read_uint(&mut self) -> io::Result { - self.read_u32::().map_err(io::Error::from) + /// Returns the number of unread bytes remaining in the packet. + pub fn bytes_remaining(&self) -> usize { + self.bytes.len() - self.cursor } - pub fn read_str(&mut self) -> io::Result { - let len = try!(self.read_uint()) as usize; - let mut buffer = vec![0; len]; - try!(self.read(&mut buffer)); - match ISO_8859_1.decode(&buffer, DecoderTrap::Strict) { - Ok(string) => Ok(string), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e.to_string())), + + pub fn as_slice(&mut self) -> &[u8] { + let bytes_len = (self.bytes.len() - U32_SIZE) as u32; + { + let mut first_word = &mut self.bytes[..U32_SIZE]; + first_word.write_u32::(bytes_len).unwrap(); } + &self.bytes } +} - pub fn read_bool(&mut self) -> io::Result { - let mut buffer = vec![0; 1]; - try!(self.read(&mut buffer)); - match buffer[0] { - 0 => Ok(false), - 1 => Ok(true), - n => Err(io::Error::new(io::ErrorKind::InvalidInput, - format!("{} is not a boolean", n))) +/*===================* + * PACKET READ ERROR * + *===================*/ + +#[derive(Debug)] +pub enum PacketReadError { + InvalidBoolError(u8), + InvalidPortError(u32), + InvalidStringError(Vec), + InvalidUserStatusError(u32), + IOError(io::Error), +} +impl fmt::Display for PacketReadError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + PacketReadError::InvalidBoolError(n) => + write!(fmt, "InvalidBoolError: {}", n), + PacketReadError::InvalidPortError(n) => + write!(fmt, "InvalidPortError: {}", n), + PacketReadError::InvalidStringError(ref bytes) => + write!(fmt, "InvalidStringError: {:?}", bytes), + PacketReadError::InvalidUserStatusError(n) => + write!(fmt, "InvalidUserStatusError: {}", n), + PacketReadError::IOError(ref err) => + write!(fmt, "IOError: {}", err), } } +} - pub fn read_array(&mut self, vector: &mut Vec, read_item: F) - -> Result - where F: Fn(&mut Self) -> Result, - E: From - { - self.read_array_with(|packet, _| { - let item = try!(read_item(packet)); - vector.push(item); - Ok(()) - }) +impl error::Error for PacketReadError { + fn description(&self) -> &str { + match *self { + PacketReadError::InvalidBoolError(_) => + "InvalidBoolError", + PacketReadError::InvalidPortError(_) => + "InvalidPortError", + PacketReadError::InvalidStringError(_) => + "InvalidStringError", + PacketReadError::InvalidUserStatusError(_) => + "InvalidUserStatusError", + PacketReadError::IOError(_) => + "IOError", + } } - pub fn read_array_with(&mut self, mut read_item: F) - -> Result - where F: FnMut(&mut Self, usize) -> Result<(), E>, - E: From - { - let num_items = try!(self.read_uint()) as usize; - for i in 0..num_items { - try!(read_item(self, i)); + fn cause(&self) -> Option<&error::Error> { + match *self { + PacketReadError::InvalidBoolError(_) => None, + PacketReadError::InvalidPortError(_) => None, + PacketReadError::InvalidStringError(_) => None, + PacketReadError::InvalidUserStatusError(_) => None, + PacketReadError::IOError(ref err) => Some(err), } - Ok(num_items) } +} - pub fn read_ipv4_addr(&mut self) -> io::Result { - let ip_u32 = try!(self.read_uint()); - Ok(net::Ipv4Addr::from(ip_u32)) +impl From for PacketReadError { + fn from(err: io::Error) -> Self { + PacketReadError::IOError(err) } +} + +/*==================* + * READ FROM PACKET * + *==================*/ + +pub trait ReadFromPacket: Sized { + fn read_from_packet(&mut Packet) -> Result; +} + +impl ReadFromPacket for u32 { + fn read_from_packet(packet: &mut Packet) -> Result { + packet.read_u32::().map_err(PacketReadError::from) + } +} + +impl ReadFromPacket for usize { + fn read_from_packet(packet: &mut Packet) -> Result { + let n: u32 = try!(packet.read_value()); + Ok(n as usize) + } +} - pub fn read_port(&mut self) -> io::Result { - let port_u32 = try!(self.read_uint()); - if port_u32 > MAX_PORT { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Invalid port number: {}", port_u32))); +impl ReadFromPacket for bool { + fn read_from_packet(packet: &mut Packet) -> Result { + let mut buffer = vec![0]; + try!(packet.read(&mut buffer)); + match buffer[0] { + 0 => Ok(false), + 1 => Ok(true), + n => Err(PacketReadError::InvalidBoolError(n)) } - Ok(port_u32 as u16) } +} - pub fn bytes_remaining(&self) -> usize { - self.bytes.len() - self.cursor +impl ReadFromPacket for net::Ipv4Addr { + fn read_from_packet(packet: &mut Packet) -> Result { + let ip: u32 = try!(packet.read_value()); + Ok(net::Ipv4Addr::from(ip)) } +} +impl ReadFromPacket for String { + fn read_from_packet(packet: &mut Packet) -> Result { + let len = try!(packet.read_value()); + let mut buffer = vec![0; len]; + try!(packet.read(&mut buffer)); + match ISO_8859_1.decode(&buffer, DecoderTrap::Strict) { + Ok(string) => Ok(string), + Err(_) => Err(PacketReadError::InvalidStringError(buffer)) + } + } +} - pub fn as_slice(&mut self) -> &[u8] { - let bytes_len = (self.bytes.len() - U32_SIZE) as u32; - { - let mut first_word = &mut self.bytes[..U32_SIZE]; - first_word.write_u32::(bytes_len).unwrap(); +impl ReadFromPacket for Vec { + fn read_from_packet(packet: &mut Packet) -> Result { + let len: usize = try!(packet.read_value()); + let mut vec = Vec::new(); + for _ in 0..len { + vec.push(try!(packet.read_value())); } - &self.bytes + Ok(vec) } } -impl io::Write for Packet { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.bytes.write(buf) +/*=================* + * WRITE TO PACKET * + *=================*/ + +pub trait WriteToPacket: Sized { + fn write_to_packet(self, &mut Packet) -> io::Result<()>; +} + +impl WriteToPacket for u32 { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + packet.write_u32::(self) } +} - fn flush(&mut self) -> io::Result<()> { - self.bytes.flush() +impl WriteToPacket for bool { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write(&[self as u8])); + Ok(()) } } -impl io::Read for Packet { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let mut slice = &self.bytes[self.cursor..]; - let result = slice.read(buf); - if let Ok(num_bytes_read) = result { - self.cursor += num_bytes_read - } - result +impl<'a> WriteToPacket for &'a str { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + let bytes = match ISO_8859_1.encode(self, EncoderTrap::Strict) { + Ok(bytes) => bytes, + Err(_) => { + let copy = self.to_string(); + return Err(io::Error::new(io::ErrorKind::Other, copy)) + } + }; + try!(packet.write_value(bytes.len() as u32)); + try!(packet.write(&bytes)); + Ok(()) } } +impl<'a> WriteToPacket for &'a String { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + packet.write_value::<&'a str>(self) + } +} + +/*===============* + * PACKET STREAM * + *===============*/ + +/// This enum defines the possible states a PacketStream state machine can be +/// in. #[derive(Debug, Clone, Copy)] enum State { + /// The PacketStream is waiting to read enough bytes to determine the + /// length of the following packet. ReadingLength, + /// The PacketStream is waiting to read enough bytes to form the entire + /// packet. ReadingPacket, } +/// This struct wraps around an mio byte stream and provides the ability to +/// read 32-bit-length-prefixed packets of bytes from it. #[derive(Debug)] pub struct PacketStream { stream: T, diff --git a/src/proto/server/request.rs b/src/proto/server/request.rs index 71b0983..b9ef8b2 100644 --- a/src/proto/server/request.rs +++ b/src/proto/server/request.rs @@ -96,16 +96,16 @@ impl LoginRequest { } } -impl WriteToPacket for LoginRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { +impl<'a> WriteToPacket for &'a LoginRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { let userpass = String::new() + &self.username + &self.password; let userpass_md5 = md5_str(&userpass); - try!(packet.write_str(&self.username)); - try!(packet.write_str(&self.password)); - try!(packet.write_uint(self.major)); - try!(packet.write_str(&userpass_md5)); - try!(packet.write_uint(self.minor)); + try!(packet.write_value(&self.username)); + try!(packet.write_value(&self.password)); + try!(packet.write_value(self.major)); + try!(packet.write_value(&userpass_md5)); + try!(packet.write_value(self.minor)); Ok(()) } @@ -117,20 +117,12 @@ impl WriteToPacket for LoginRequest { #[derive(Debug)] pub struct PeerAddressRequest { - username: String, -} - -impl PeerAddressRequest { - fn new(username: &str) -> Self { - PeerAddressRequest { - username: username.to_string(), - } - } + pub username: String, } -impl WriteToPacket for PeerAddressRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_str(&self.username)); +impl<'a> WriteToPacket for &'a PeerAddressRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_value(&self.username)); Ok(()) } } @@ -144,9 +136,9 @@ pub struct RoomJoinRequest { pub room_name: String } -impl WriteToPacket for RoomJoinRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_str(&self.room_name)); +impl<'a> WriteToPacket for &'a RoomJoinRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_value(&self.room_name)); Ok(()) } } @@ -160,9 +152,9 @@ pub struct RoomLeaveRequest { pub room_name: String } -impl WriteToPacket for RoomLeaveRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_str(&self.room_name)); +impl<'a> WriteToPacket for &'a RoomLeaveRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_value(&self.room_name)); Ok(()) } } @@ -177,10 +169,10 @@ pub struct RoomMessageRequest { pub message: String, } -impl WriteToPacket for RoomMessageRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_str(&self.room_name)); - try!(packet.write_str(&self.message)); +impl<'a> WriteToPacket for &'a RoomMessageRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_value(&self.room_name)); + try!(packet.write_value(&self.message)); Ok(()) } } @@ -191,20 +183,12 @@ impl WriteToPacket for RoomMessageRequest { #[derive(Debug)] pub struct SetListenPortRequest { - port: u16, -} - -impl SetListenPortRequest { - fn new(port: u16) -> Self { - SetListenPortRequest { - port: port, - } - } + pub port: u16, } -impl WriteToPacket for SetListenPortRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_uint(self.port as u32)); +impl<'a> WriteToPacket for &'a SetListenPortRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_port(self.port)); Ok(()) } } @@ -218,9 +202,9 @@ pub struct UserStatusRequest { pub user_name: String, } -impl WriteToPacket for UserStatusRequest { - fn write_to_packet(&self, packet: &mut Packet) -> io::Result<()> { - try!(packet.write_str(&self.user_name)); +impl<'a> WriteToPacket for &'a UserStatusRequest { + fn write_to_packet(self, packet: &mut Packet) -> io::Result<()> { + try!(packet.write_value(&self.user_name)); Ok(()) } } diff --git a/src/proto/server/response.rs b/src/proto/server/response.rs index 7b7db3f..e0c07f9 100644 --- a/src/proto/server/response.rs +++ b/src/proto/server/response.rs @@ -1,9 +1,8 @@ use std::net; use super::constants::*; -use super::super::packet::{Packet, ReadFromPacket}; +use super::super::packet::{Packet, PacketReadError, ReadFromPacket}; -use result; use user; /*=================* @@ -42,8 +41,8 @@ macro_rules! try_read_from_packet { } impl ReadFromPacket for ServerResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let code = try!(packet.read_uint()); + fn read_from_packet(packet: &mut Packet) -> Result { + let code = try!(packet.read_value()); let resp = match code { CODE_CONNECT_TO_PEER => try_read_from_packet!(ConnectToPeerResponse, packet), @@ -116,15 +115,15 @@ pub struct ConnectToPeerResponse { } impl ReadFromPacket for ConnectToPeerResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let username = try!(packet.read_str()); - let connection_type = try!(packet.read_str()); + fn read_from_packet(packet: &mut Packet) -> Result { + let username = try!(packet.read_value()); + let connection_type = try!(packet.read_value()); - let ip = try!(packet.read_ipv4_addr()); + let ip = try!(packet.read_value()); let port = try!(packet.read_port()); - let token = try!(packet.read_uint()); - let is_privileged = try!(packet.read_bool()); + let token = try!(packet.read_value()); + let is_privileged = try!(packet.read_value()); Ok(ConnectToPeerResponse { username: username, @@ -154,13 +153,13 @@ pub enum LoginResponse { } impl ReadFromPacket for LoginResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let ok = try!(packet.read_bool()); + fn read_from_packet(packet: &mut Packet) -> Result { + let ok = try!(packet.read_value()); if ok { - let motd = try!(packet.read_str()); - let ip = try!(packet.read_ipv4_addr()); + let motd = try!(packet.read_value()); + let ip = try!(packet.read_value()); - match packet.read_bool() { + match packet.read_value::() { Ok(value) => debug!("LoginResponse last field: {}", value), Err(e) => debug!("Error reading LoginResponse field: {:?}", e), } @@ -172,7 +171,7 @@ impl ReadFromPacket for LoginResponse { }) } else { Ok(LoginResponse::LoginFail { - reason: try!(packet.read_str()) + reason: try!(packet.read_value()) }) } } @@ -188,8 +187,8 @@ pub struct ParentMinSpeedResponse { } impl ReadFromPacket for ParentMinSpeedResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let value = try!(packet.read_uint()); + fn read_from_packet(packet: &mut Packet) -> Result { + let value = try!(packet.read_value()); Ok(ParentMinSpeedResponse { value: value, }) @@ -206,8 +205,8 @@ pub struct ParentSpeedRatioResponse { } impl ReadFromPacket for ParentSpeedRatioResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let value = try!(packet.read_uint()); + fn read_from_packet(packet: &mut Packet) -> Result { + let value = try!(packet.read_value()); Ok(ParentSpeedRatioResponse { value: value, }) @@ -226,9 +225,9 @@ pub struct PeerAddressResponse { } impl ReadFromPacket for PeerAddressResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let username = try!(packet.read_str()); - let ip = try!(packet.read_ipv4_addr()); + fn read_from_packet(packet: &mut Packet) -> Result { + let username = try!(packet.read_value()); + let ip = try!(packet.read_value()); let port = try!(packet.read_port()); Ok(PeerAddressResponse { @@ -249,12 +248,11 @@ pub struct PrivilegedUsersResponse { } impl ReadFromPacket for PrivilegedUsersResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let mut response = PrivilegedUsersResponse { - users: Vec::new(), - }; - try!(packet.read_array(&mut response.users, Packet::read_str)); - Ok(response) + fn read_from_packet(packet: &mut Packet) -> Result { + let users = try!(packet.read_value()); + Ok(PrivilegedUsersResponse { + users: users + }) } } @@ -271,36 +269,39 @@ pub struct RoomJoinResponse { } impl ReadFromPacket for RoomJoinResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { + fn read_from_packet(packet: &mut Packet) -> Result { let mut response = RoomJoinResponse { - room_name: try!(packet.read_str()), + room_name: try!(packet.read_value()), users: Vec::new(), owner: None, operators: Vec::new(), }; - let result: result::Result = - packet.read_array(&mut response.users, |packet| { - let name = try!(packet.read_str()); - let user = user::User { - status: user::Status::Offline, - average_speed: 0, - num_downloads: 0, - unknown: 0, - num_files: 0, - num_folders: 0, - num_free_slots: 0, - country: String::new(), - }; - Ok((name, user)) - }); - try!(result); + let num_users: usize = try!(packet.read_value()); + for _ in 0..num_users { + let name = try!(packet.read_value()); + let user = user::User { + status: user::Status::Offline, + average_speed: 0, + num_downloads: 0, + unknown: 0, + num_files: 0, + num_folders: 0, + num_free_slots: 0, + country: String::new(), + }; + response.users.push((name, user)); + } try!(response.read_user_infos(packet)); if packet.bytes_remaining() > 0 { - response.owner = Some(try!(packet.read_str())); - try!(packet.read_array(&mut response.operators, Packet::read_str)); + response.owner = Some(try!(packet.read_value())); + + let num_operators: usize = try!(packet.read_value()); + for _ in 0..num_operators { + response.operators.push(try!(packet.read_value())); + } } Ok(response) @@ -309,48 +310,39 @@ impl ReadFromPacket for RoomJoinResponse { impl RoomJoinResponse { fn read_user_infos(&mut self, packet: &mut Packet) - -> result::Result<()> + -> Result<(), PacketReadError> { - let num_statuses_res: result::Result = - packet.read_array_with(|packet, i| { - if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { - let status_u32 = try!(packet.read_uint()); - user.status = try!(user::Status::from_u32(status_u32)); - } - Ok(()) - }); - let num_statuses = try!(num_statuses_res); - - let num_infos_res: result::Result = - packet.read_array_with(|packet, i| { - if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { - user.average_speed = try!(packet.read_uint()) as usize; - user.num_downloads = try!(packet.read_uint()) as usize; - user.unknown = try!(packet.read_uint()) as usize; - user.num_files = try!(packet.read_uint()) as usize; - user.num_folders = try!(packet.read_uint()) as usize; - } - Ok(()) - }); - let num_infos = try!(num_infos_res); - - let num_free_slots_res: result::Result = - packet.read_array_with(|packet, i| { - if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { - user.num_free_slots = try!(packet.read_uint()) as usize; - } - Ok(()) - }); - let num_free_slots = try!(num_free_slots_res); - - let num_countries_res: result::Result = - packet.read_array_with(|packet, i| { - if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { - user.country = try!(packet.read_str()); - } - Ok(()) - }); - let num_countries = try!(num_countries_res); + let num_statuses: usize = try!(packet.read_value()); + for i in 0..num_statuses { + if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { + user.status = try!(packet.read_value()); + } + } + + let num_infos: usize = try!(packet.read_value()); + for i in 0..num_infos { + if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { + user.average_speed = try!(packet.read_value()); + user.num_downloads = try!(packet.read_value()); + user.unknown = try!(packet.read_value()); + user.num_files = try!(packet.read_value()); + user.num_folders = try!(packet.read_value()); + } + } + + let num_free_slots: usize = try!(packet.read_value()); + for i in 0..num_free_slots { + if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { + user.num_free_slots = try!(packet.read_value()); + } + } + + let num_countries: usize = try!(packet.read_value()); + for i in 0..num_countries { + if let Some(&mut (_, ref mut user)) = self.users.get_mut(i) { + user.country = try!(packet.read_value()); + } + } let num_users = self.users.len(); if num_users != num_statuses || @@ -379,9 +371,9 @@ pub struct RoomLeaveResponse { } impl ReadFromPacket for RoomLeaveResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { + fn read_from_packet(packet: &mut Packet) -> Result { Ok(RoomLeaveResponse { - room_name: try!(packet.read_str()), + room_name: try!(packet.read_value()), }) } } @@ -399,68 +391,46 @@ pub struct RoomListResponse { } impl ReadFromPacket for RoomListResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let mut response = RoomListResponse { - rooms: Vec::new(), - owned_private_rooms: Vec::new(), - other_private_rooms: Vec::new(), - operated_private_room_names: Vec::new(), - }; - - try!(Self::read_rooms(packet, &mut response.rooms)); - - if let Err(e) = Self::read_rooms( - packet, &mut response.owned_private_rooms) - { - warn!("Error parsing owned_private_rooms: {}", e); - return Ok(response); - } - - if let Err(e) = Self::read_rooms( - packet, &mut response.other_private_rooms) - { - warn!("Error parsing other_private_rooms: {}", e); - return Ok(response); - } - - if let Err(e) = packet.read_array( - &mut response.operated_private_room_names, Packet::read_str) - { - warn!("Error parsing operated_private_rooms: {}", e); - } - - Ok(response) + fn read_from_packet(packet: &mut Packet) -> Result { + let rooms = try!(Self::read_rooms(packet)); + let owned_private_rooms = try!(Self::read_rooms(packet)); + let other_private_rooms = try!(Self::read_rooms(packet)); + let operated_private_room_names = try!(packet.read_value()); + Ok(RoomListResponse { + rooms: rooms, + owned_private_rooms: owned_private_rooms, + other_private_rooms: other_private_rooms, + operated_private_room_names: operated_private_room_names, + }) } } impl RoomListResponse { - fn read_rooms(packet: &mut Packet, rooms: &mut Vec<(String, u32)>) - -> result::Result<()> + fn read_rooms(packet: &mut Packet) + -> Result, PacketReadError> { - let original_rooms_len = rooms.len(); - - let num_rooms_res: result::Result = - packet.read_array(rooms, |packet| { - Ok((try!(packet.read_str()), 0)) - }); - let num_rooms = try!(num_rooms_res); - - let num_user_counts_res: result::Result = - packet.read_array_with(|packet, i| { - let index = original_rooms_len + i; - if let Some(&mut (_, ref mut count)) = rooms.get_mut(index) { - *count = try!(packet.read_uint()); - } - Ok(()) - }); - let num_user_counts = try!(num_user_counts_res); + let num_rooms: usize = try!(packet.read_value()); + let mut rooms = Vec::new(); + for _ in 0..num_rooms { + let room_name = try!(packet.read_value()); + rooms.push((room_name, 0)); + } + + let num_user_counts: usize = try!(packet.read_value()); + for i in 0..num_user_counts { + if let Some(&mut (_, ref mut count)) = rooms.get_mut(i) { + *count = try!(packet.read_value()); + } + } if num_rooms != num_user_counts { - warn!("Numbers of rooms and user counts do not match: {} != {}", - num_rooms, num_user_counts); + warn!( + "Numbers of rooms and user counts do not match: {} != {}", + num_rooms, num_user_counts + ); } - Ok(()) + Ok(rooms) } } @@ -476,10 +446,10 @@ pub struct RoomMessageResponse { } impl ReadFromPacket for RoomMessageResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let room_name = try!(packet.read_str()); - let user_name = try!(packet.read_str()); - let message = try!(packet.read_str()); + fn read_from_packet(packet: &mut Packet) -> Result { + let room_name = try!(packet.read_value()); + let user_name = try!(packet.read_value()); + let message = try!(packet.read_value()); Ok(RoomMessageResponse { room_name: room_name, user_name: user_name, @@ -499,14 +469,14 @@ pub struct RoomTickersResponse { } impl ReadFromPacket for RoomTickersResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let room_name = try!(packet.read_str()); + fn read_from_packet(packet: &mut Packet) -> Result { + let room_name = try!(packet.read_value()); - let num_tickers = try!(packet.read_uint()) as usize; + let num_tickers: usize = try!(packet.read_value()); let mut tickers = Vec::new(); for _ in 0..num_tickers { - let user_name = try!(packet.read_str()); - let message = try!(packet.read_str()); + let user_name = try!(packet.read_value()); + let message = try!(packet.read_value()); tickers.push((user_name, message)) } @@ -529,21 +499,20 @@ pub struct RoomUserJoinedResponse { } impl ReadFromPacket for RoomUserJoinedResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let room_name = try!(packet.read_str()); - let user_name = try!(packet.read_str()); + fn read_from_packet(packet: &mut Packet) -> Result { + let room_name = try!(packet.read_value()); + let user_name = try!(packet.read_value()); - let status_u32 = try!(packet.read_uint()); - let status = try!(user::Status::from_u32(status_u32)); + let status = try!(packet.read_value()); - let average_speed = try!(packet.read_uint()) as usize; - let num_downloads = try!(packet.read_uint()) as usize; - let unknown = try!(packet.read_uint()) as usize; - let num_files = try!(packet.read_uint()) as usize; - let num_folders = try!(packet.read_uint()) as usize; - let num_free_slots = try!(packet.read_uint()) as usize; + let average_speed = try!(packet.read_value()); + let num_downloads = try!(packet.read_value()); + let unknown = try!(packet.read_value()); + let num_files = try!(packet.read_value()); + let num_folders = try!(packet.read_value()); + let num_free_slots = try!(packet.read_value()); - let country = try!(packet.read_str()); + let country = try!(packet.read_value()); Ok(RoomUserJoinedResponse { room_name: room_name, @@ -573,9 +542,9 @@ pub struct RoomUserLeftResponse { } impl ReadFromPacket for RoomUserLeftResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let room_name = try!(packet.read_str()); - let user_name = try!(packet.read_str()); + fn read_from_packet(packet: &mut Packet) -> Result { + let room_name = try!(packet.read_value()); + let user_name = try!(packet.read_value()); Ok(RoomUserLeftResponse { room_name: room_name, user_name: user_name, @@ -595,11 +564,10 @@ pub struct UserStatusResponse { } impl ReadFromPacket for UserStatusResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let user_name = try!(packet.read_str()); - let status_u32 = try!(packet.read_uint()); - let status = try!(user::Status::from_u32(status_u32)); - let is_privileged = try!(packet.read_bool()); + fn read_from_packet(packet: &mut Packet) -> Result { + let user_name = try!(packet.read_value()); + let status = try!(packet.read_value()); + let is_privileged = try!(packet.read_value()); Ok(UserStatusResponse { user_name: user_name, status: status, @@ -618,8 +586,8 @@ pub struct WishlistIntervalResponse { } impl ReadFromPacket for WishlistIntervalResponse { - fn read_from_packet(packet: &mut Packet) -> result::Result { - let seconds = try!(packet.read_uint()); + fn read_from_packet(packet: &mut Packet) -> Result { + let seconds = try!(packet.read_value()); Ok(WishlistIntervalResponse { seconds: seconds, }) diff --git a/src/result.rs b/src/result.rs index c5fc318..fa52c70 100644 --- a/src/result.rs +++ b/src/result.rs @@ -13,10 +13,10 @@ use proto; #[derive(Debug)] pub enum Error { - InvalidEnumError(usize), IOError(io::Error), JSONEncoderError(json::EncoderError), JSONDecoderError(json::DecoderError), + PacketReadError(proto::PacketReadError), SendControlRequestError(mpsc::SendError), SendProtoResponseError(mpsc::SendError), Utf8Error(str::Utf8Error), @@ -26,16 +26,14 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::InvalidEnumError(n) => - write!( - fmt, "InvalidEnumError: {} is not a valid enum value", n - ), Error::IOError(ref err) => write!(fmt, "IOError: {}", err), Error::JSONEncoderError(ref err) => write!(fmt, "JSONEncoderError: {}", err), Error::JSONDecoderError(ref err) => write!(fmt, "JSONDecoderError: {}", err), + Error::PacketReadError(ref err) => + write!(fmt, "PacketReadError: {}", err), Error::SendControlRequestError(ref err) => write!(fmt, "SendControlRequestError: {}", err), Error::SendProtoResponseError(ref err) => @@ -51,10 +49,10 @@ impl fmt::Display for Error { impl error::Error for Error { fn description(&self) -> &str { match *self { - Error::InvalidEnumError(_) => "InvalidEnumError", Error::IOError(_) => "IOError", Error::JSONEncoderError(_) => "JSONEncoderError", Error::JSONDecoderError(_) => "JSONDecoderError", + Error::PacketReadError(_) => "PacketReadError", Error::SendControlRequestError(_) => "SendControlRequestError", Error::SendProtoResponseError(_) => "SendProtoResponseError", Error::Utf8Error(_) => "Utf8Error", @@ -64,10 +62,10 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match *self { - Error::InvalidEnumError(_) => None, Error::IOError(ref err) => Some(err), Error::JSONEncoderError(ref err) => Some(err), Error::JSONDecoderError(ref err) => Some(err), + Error::PacketReadError(ref err) => Some(err), Error::SendControlRequestError(ref err) => Some(err), Error::SendProtoResponseError(ref err) => Some(err), Error::Utf8Error(ref err) => Some(err), @@ -94,6 +92,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: proto::PacketReadError) -> Self { + Error::PacketReadError(err) + } +} + impl From> for Error { fn from(err: mpsc::SendError) -> Self { Error::SendControlRequestError(err) diff --git a/src/user.rs b/src/user.rs index 3c7d2ab..e3b736d 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,8 +1,9 @@ use std::collections; use std::error; use std::fmt; +use std::io; -use result; +use proto; const STATUS_OFFLINE: u32 = 1; const STATUS_AWAY: u32 = 2; @@ -19,22 +20,31 @@ pub enum Status { Online, } -impl Status { - pub fn from_u32(n: u32) -> result::Result { +impl proto::ReadFromPacket for Status { + fn read_from_packet(packet: &mut proto::Packet) + -> Result + { + let n: u32 = try!(packet.read_value()); match n { STATUS_OFFLINE => Ok(Status::Offline), STATUS_AWAY => Ok(Status::Away), STATUS_ONLINE => Ok(Status::Online), - _ => Err(result::Error::InvalidEnumError(n as usize)) + _ => { + Err(proto::PacketReadError::InvalidUserStatusError(n)) + } } } +} - pub fn to_u32(&self) -> u32 { - match *self { +impl<'a> proto::WriteToPacket for &'a Status { + fn write_to_packet(self, packet: &mut proto::Packet) -> io::Result<()> { + let n = match *self { Status::Offline => STATUS_OFFLINE, Status::Away => STATUS_AWAY, Status::Online => STATUS_ONLINE, - } + }; + try!(packet.write_value(n)); + Ok(()) } }