Browse Source

Use ReadFromPacket and WriteToPacket traits to simplify packet I/O.

wip
Titouan Rigoudy 9 years ago
parent
commit
d59ac09ca0
8 changed files with 422 additions and 341 deletions
  1. +6
    -1
      Cargo.lock
  2. +1
    -1
      Cargo.toml
  3. +7
    -1
      src/proto/mod.rs
  4. +208
    -104
      src/proto/packet.rs
  5. +28
    -44
      src/proto/server/request.rs
  6. +144
    -176
      src/proto/server/response.rs
  7. +11
    -7
      src/result.rs
  8. +17
    -7
      src/user.rs

+ 6
- 1
Cargo.lock View File

@ -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"


+ 1
- 1
Cargo.toml View File

@ -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"


+ 7
- 1
src/proto/mod.rs View File

@ -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};


+ 208
- 104
src/proto/packet.rs View File

@ -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<Self>;
}
/*=================*
* 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<u8>,
}
impl io::Read for Packet {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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<usize> {
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<usize> {
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<usize> {
match self.write_u32::<LittleEndian>(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<u16, PacketReadError> {
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<usize> {
self.write(&[b as u8])
/// Provides the main way to read data out of a binary packet.
pub fn read_value<T: ReadFromPacket>(&mut self)
-> Result<T, PacketReadError>
{
T::read_from_packet(self)
}
// Reading convenience
/// Provides the main way to write data into a binary packet.
pub fn write_value<T: WriteToPacket>(&mut self, val: T)
-> io::Result<()>
{
val.write_to_packet(self)
}
pub fn read_uint(&mut self) -> io::Result<u32> {
self.read_u32::<LittleEndian>().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<String> {
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::<LittleEndian>(bytes_len).unwrap();
}
&self.bytes
}
}
pub fn read_bool(&mut self) -> io::Result<bool> {
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<u8>),
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<T, E, F>(&mut self, vector: &mut Vec<T>, read_item: F)
-> Result<usize, E>
where F: Fn(&mut Self) -> Result<T, E>,
E: From<io::Error>
{
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<E, F>(&mut self, mut read_item: F)
-> Result<usize, E>
where F: FnMut(&mut Self, usize) -> Result<(), E>,
E: From<io::Error>
{
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<net::Ipv4Addr> {
let ip_u32 = try!(self.read_uint());
Ok(net::Ipv4Addr::from(ip_u32))
impl From<io::Error> 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<Self, PacketReadError>;
}
impl ReadFromPacket for u32 {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
packet.read_u32::<LittleEndian>().map_err(PacketReadError::from)
}
}
impl ReadFromPacket for usize {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
let n: u32 = try!(packet.read_value());
Ok(n as usize)
}
}
pub fn read_port(&mut self) -> io::Result<u16> {
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<Self, PacketReadError> {
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<Self, PacketReadError> {
let ip: u32 = try!(packet.read_value());
Ok(net::Ipv4Addr::from(ip))
}
}
impl ReadFromPacket for String {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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::<LittleEndian>(bytes_len).unwrap();
impl<T: ReadFromPacket> ReadFromPacket for Vec<T> {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<usize> {
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::<LittleEndian>(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<usize> {
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<T: Read + Write + Evented> {
stream: T,


+ 28
- 44
src/proto/server/request.rs View File

@ -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(())
}
}

+ 144
- 176
src/proto/server/response.rs View File

@ -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<Self> {
let code = try!(packet.read_uint());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let username = try!(packet.read_str());
let connection_type = try!(packet.read_str());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let ok = try!(packet.read_bool());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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::<bool>() {
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<Self> {
let value = try!(packet.read_uint());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let value = try!(packet.read_uint());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let username = try!(packet.read_str());
let ip = try!(packet.read_ipv4_addr());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
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<Self, PacketReadError> {
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<Self> {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<usize> =
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<usize> =
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<usize> =
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<usize> =
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<usize> =
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<Self> {
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
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<Self, PacketReadError> {
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<Vec<(String, u32)>, PacketReadError>
{
let original_rooms_len = rooms.len();
let num_rooms_res: result::Result<usize> =
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<usize> =
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<Self> {
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<Self, PacketReadError> {
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<Self> {
let room_name = try!(packet.read_str());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let room_name = try!(packet.read_str());
let user_name = try!(packet.read_str());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
let room_name = try!(packet.read_str());
let user_name = try!(packet.read_str());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
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<Self> {
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<Self, PacketReadError> {
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<Self> {
let seconds = try!(packet.read_uint());
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
let seconds = try!(packet.read_value());
Ok(WishlistIntervalResponse {
seconds: seconds,
})


+ 11
- 7
src/result.rs View File

@ -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<control::Request>),
SendProtoResponseError(mpsc::SendError<proto::Response>),
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<json::DecoderError> for Error {
}
}
impl From<proto::PacketReadError> for Error {
fn from(err: proto::PacketReadError) -> Self {
Error::PacketReadError(err)
}
}
impl From<mpsc::SendError<control::Request>> for Error {
fn from(err: mpsc::SendError<control::Request>) -> Self {
Error::SendControlRequestError(err)


+ 17
- 7
src/user.rs View File

@ -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<Status> {
impl proto::ReadFromPacket for Status {
fn read_from_packet(packet: &mut proto::Packet)
-> Result<Self, proto::PacketReadError>
{
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(())
}
}


Loading…
Cancel
Save