Browse Source

Refactor Error into result module, use it.

wip
Titouan Rigoudy 9 years ago
parent
commit
56c170c119
7 changed files with 241 additions and 110 deletions
  1. +6
    -72
      src/control/controller.rs
  2. +5
    -8
      src/handler.rs
  3. +1
    -0
      src/main.rs
  4. +8
    -5
      src/proto/packet.rs
  5. +69
    -21
      src/proto/server/response.rs
  6. +121
    -0
      src/result.rs
  7. +31
    -4
      src/user.rs

+ 6
- 72
src/control/controller.rs View File

@ -9,6 +9,7 @@ use websocket;
use websocket::{Receiver, Sender}; use websocket::{Receiver, Sender};
use config; use config;
use result;
use super::request::*; use super::request::*;
use super::response::*; use super::response::*;
@ -22,71 +23,6 @@ type WebSocketSender =
type WebSocketClient = type WebSocketClient =
websocket::Client<websocket::DataFrame, WebSocketSender, WebSocketReceiver>; websocket::Client<websocket::DataFrame, WebSocketSender, WebSocketReceiver>;
#[derive(Debug)]
enum Error {
IOError(io::Error),
JSONEncoderError(json::EncoderError),
JSONDecoderError(json::DecoderError),
SendError(mpsc::SendError<Request>),
Utf8Error(str::Utf8Error),
WebSocketError(websocket::result::WebSocketError),
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
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::SendError(ref err) =>
write!(fmt, "SendError({})", err),
Error::Utf8Error(ref err) =>
write!(fmt, "Utf8Error({})", err),
Error::WebSocketError(ref err) =>
write!(fmt, "WebSocketError({})", err),
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::IOError(err)
}
}
impl From<json::EncoderError> for Error {
fn from(err: json::EncoderError) -> Self {
Error::JSONEncoderError(err)
}
}
impl From<json::DecoderError> for Error {
fn from(err: json::DecoderError) -> Self {
Error::JSONDecoderError(err)
}
}
impl From<mpsc::SendError<Request>> for Error {
fn from(err: mpsc::SendError<Request>) -> Self {
Error::SendError(err)
}
}
impl From<str::Utf8Error> for Error {
fn from(err: str::Utf8Error) -> Self {
Error::Utf8Error(err)
}
}
impl From<websocket::result::WebSocketError> for Error {
fn from(err: websocket::result::WebSocketError) -> Self {
Error::WebSocketError(err)
}
}
pub struct Controller { pub struct Controller {
client_tx: mpsc::Sender<Request>, client_tx: mpsc::Sender<Request>,
client_rx: mpsc::Receiver<Response>, client_rx: mpsc::Receiver<Response>,
@ -148,14 +84,12 @@ impl Controller {
} }
fn try_get_client(server: &mut websocket::Server) fn try_get_client(server: &mut websocket::Server)
-> io::Result<WebSocketClient>
-> result::Result<WebSocketClient>
{ {
let connection = try!(server.accept()); let connection = try!(server.accept());
let request = try!(connection.read_request()); let request = try!(connection.read_request());
match request.accept().send() {
Ok(client) => Ok(client),
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
}
let client = try!(request.accept().send());
Ok(client)
} }
fn receiver_loop( fn receiver_loop(
@ -201,7 +135,7 @@ impl Controller {
fn handle_text_message( fn handle_text_message(
payload_bytes: &[u8], payload_bytes: &[u8],
client_tx: &mpsc::Sender<Request>) client_tx: &mpsc::Sender<Request>)
-> Result<(), Error>
-> result::Result<()>
{ {
let payload = try!(str::from_utf8(payload_bytes)); let payload = try!(str::from_utf8(payload_bytes));
let control_request = try!(json::decode(payload)); let control_request = try!(json::decode(payload));
@ -240,7 +174,7 @@ impl Controller {
} }
fn send_response(sender: &mut WebSocketSender, response: Response) fn send_response(sender: &mut WebSocketSender, response: Response)
-> Result<(), Error>
-> result::Result<()>
{ {
debug!("Sending control response: {:?}", response); debug!("Sending control response: {:?}", response);
let encoded = try!(json::encode(&response)); let encoded = try!(json::encode(&response));


+ 5
- 8
src/handler.rs View File

@ -8,6 +8,7 @@ use mio::tcp::TcpStream;
use proto::{Packet, PacketStream, Request, Response}; use proto::{Packet, PacketStream, Request, Response};
use proto::server::*; use proto::server::*;
use result;
struct TokenCounter { struct TokenCounter {
counter: usize, counter: usize,
@ -104,22 +105,18 @@ impl ConnectionHandler {
} }
} }
fn read_server_once(&mut self) -> io::Result<bool> {
fn read_server_once(&mut self) -> result::Result<bool> {
let mut packet = match try!(self.server_stream.try_read()) { let mut packet = match try!(self.server_stream.try_read()) {
Some(packet) => packet, Some(packet) => packet,
None => return Ok(false), None => return Ok(false),
}; };
debug!("Read packet with size {}", packet.bytes_remaining());
let server_response = try!(ServerResponse::from_packet(&mut packet)); let server_response = try!(ServerResponse::from_packet(&mut packet));
debug!("Received server response: {:?}", server_response); debug!("Received server response: {:?}", server_response);
match self.client_tx.send(Response::ServerResponse(server_response)) {
Ok(()) => Ok(true),
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("Send failed on client_tx channel: {}", e))),
}
try!(self.client_tx.send(Response::ServerResponse(server_response)));
Ok(true)
} }
fn write_server_once(&mut self) -> io::Result<bool> { fn write_server_once(&mut self) -> io::Result<bool> {


+ 1
- 0
src/main.rs View File

@ -3,6 +3,7 @@
mod client; mod client;
mod config; mod config;
mod control; mod control;
mod result;
mod handler; mod handler;
mod proto; mod proto;
mod room; mod room;


+ 8
- 5
src/proto/packet.rs View File

@ -87,9 +87,10 @@ impl Packet {
} }
} }
pub fn read_array<T, F>(&mut self, vector: &mut Vec<T>, read_item: F)
-> io::Result<usize>
where F: Fn(&mut Self) -> io::Result<T>
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, _| { self.read_array_with(|packet, _| {
let item = try!(read_item(packet)); let item = try!(read_item(packet));
@ -98,8 +99,10 @@ impl Packet {
}) })
} }
pub fn read_array_with<F>(&mut self, mut read_item: F) -> io::Result<usize>
where F: FnMut(&mut Self, usize) -> io::Result<()>
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; let num_items = try!(self.read_uint()) as usize;
for i in 0..num_items { for i in 0..num_items {


+ 69
- 21
src/proto/server/response.rs View File

@ -4,6 +4,7 @@ use std::net;
use super::constants::*; use super::constants::*;
use super::super::packet::Packet; use super::super::packet::Packet;
use result;
use user; use user;
/*=============* /*=============*
@ -11,7 +12,7 @@ use user;
*=============*/ *=============*/
pub trait FromPacket: Sized { pub trait FromPacket: Sized {
fn from_packet(&mut Packet) -> io::Result<Self>;
fn from_packet(&mut Packet) -> result::Result<Self>;
} }
/*=================* /*=================*
@ -36,7 +37,7 @@ pub enum ServerResponse {
} }
impl FromPacket for ServerResponse { impl FromPacket for ServerResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let code = try!(packet.read_uint()); let code = try!(packet.read_uint());
let resp = match code { let resp = match code {
CODE_CONNECT_TO_PEER => CODE_CONNECT_TO_PEER =>
@ -110,7 +111,7 @@ pub struct ConnectToPeerResponse {
} }
impl FromPacket for ConnectToPeerResponse { impl FromPacket for ConnectToPeerResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let username = try!(packet.read_str()); let username = try!(packet.read_str());
let connection_type = try!(packet.read_str()); let connection_type = try!(packet.read_str());
@ -145,7 +146,7 @@ pub struct JoinRoomResponse {
} }
impl FromPacket for JoinRoomResponse { impl FromPacket for JoinRoomResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let mut response = JoinRoomResponse { let mut response = JoinRoomResponse {
room_name: try!(packet.read_str()), room_name: try!(packet.read_str()),
user_names: Vec::new(), user_names: Vec::new(),
@ -165,8 +166,51 @@ impl FromPacket for JoinRoomResponse {
} }
impl JoinRoomResponse { impl JoinRoomResponse {
fn read_user_infos(&mut self, packet: &mut Packet) -> io::Result<()>
fn read_user_infos(&mut self, packet: &mut Packet)
-> result::Result<()>
{ {
let num_statuses_res: result::Result<usize> =
packet.read_array(&mut self.user_infos, |packet| {
let status_u32 = try!(packet.read_uint());
let status = try!(user::Status::from_u32(status_u32));
Ok(user::User {
status: status,
average_speed: 0,
num_downloads: 0,
unknown: 0,
num_files: 0,
num_folders: 0,
num_free_slots: 0,
})
});
let num_statuses = try!(num_statuses_res);
let num_infos_res: result::Result<usize> =
packet.read_array_with(|packet, i| {
if let Some(user) = self.user_infos.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(user) = self.user_infos.get_mut(i) {
user.num_free_slots = try!(packet.read_uint()) as usize;
}
Ok(())
});
let num_free_slots = try!(num_free_slots_res);
if num_statuses != num_infos || num_statuses != num_free_slots {
warn!("JoinRoomResponse: mismatched vector sizes");
}
Ok(()) Ok(())
} }
} }
@ -188,7 +232,7 @@ pub enum LoginResponse {
} }
impl FromPacket for LoginResponse { impl FromPacket for LoginResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let ok = try!(packet.read_bool()); let ok = try!(packet.read_bool());
if ok { if ok {
let motd = try!(packet.read_str()); let motd = try!(packet.read_str());
@ -222,7 +266,7 @@ pub struct ParentMinSpeedResponse {
} }
impl FromPacket for ParentMinSpeedResponse { impl FromPacket for ParentMinSpeedResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let value = try!(packet.read_uint()); let value = try!(packet.read_uint());
Ok(ParentMinSpeedResponse { Ok(ParentMinSpeedResponse {
value: value, value: value,
@ -240,7 +284,7 @@ pub struct ParentSpeedRatioResponse {
} }
impl FromPacket for ParentSpeedRatioResponse { impl FromPacket for ParentSpeedRatioResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let value = try!(packet.read_uint()); let value = try!(packet.read_uint());
Ok(ParentSpeedRatioResponse { Ok(ParentSpeedRatioResponse {
value: value, value: value,
@ -260,7 +304,7 @@ pub struct PeerAddressResponse {
} }
impl FromPacket for PeerAddressResponse { impl FromPacket for PeerAddressResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let username = try!(packet.read_str()); let username = try!(packet.read_str());
let ip = try!(packet.read_ipv4_addr()); let ip = try!(packet.read_ipv4_addr());
let port = try!(packet.read_port()); let port = try!(packet.read_port());
@ -283,7 +327,7 @@ pub struct PrivilegedUsersResponse {
} }
impl FromPacket for PrivilegedUsersResponse { impl FromPacket for PrivilegedUsersResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let mut response = PrivilegedUsersResponse { let mut response = PrivilegedUsersResponse {
users: Vec::new(), users: Vec::new(),
}; };
@ -305,7 +349,7 @@ pub struct RoomListResponse {
} }
impl FromPacket for RoomListResponse { impl FromPacket for RoomListResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let mut response = RoomListResponse { let mut response = RoomListResponse {
rooms: Vec::new(), rooms: Vec::new(),
owned_private_rooms: Vec::new(), owned_private_rooms: Vec::new(),
@ -341,19 +385,23 @@ impl FromPacket for RoomListResponse {
impl RoomListResponse { impl RoomListResponse {
fn read_rooms(packet: &mut Packet, rooms: &mut Vec<(String, u32)>) fn read_rooms(packet: &mut Packet, rooms: &mut Vec<(String, u32)>)
-> io::Result<()>
-> result::Result<()>
{ {
let original_rooms_len = rooms.len(); let original_rooms_len = rooms.len();
let num_rooms = try!(packet.read_array(rooms, |packet| {
Ok((try!(packet.read_str()), 0))
}));
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 = try!(packet.read_array_with(|packet, i| {
let user_count = try!(packet.read_uint());
rooms[original_rooms_len+i].1 = user_count;
Ok(())
}));
let num_user_counts_res: result::Result<usize> =
packet.read_array_with(|packet, i| {
let user_count = try!(packet.read_uint());
rooms[original_rooms_len+i].1 = user_count;
Ok(())
});
let num_user_counts = try!(num_user_counts_res);
if num_rooms != num_user_counts { if num_rooms != num_user_counts {
warn!("Numbers of rooms and user counts do not match: {} != {}", warn!("Numbers of rooms and user counts do not match: {} != {}",
@ -374,7 +422,7 @@ pub struct WishlistIntervalResponse {
} }
impl FromPacket for WishlistIntervalResponse { impl FromPacket for WishlistIntervalResponse {
fn from_packet(packet: &mut Packet) -> io::Result<Self> {
fn from_packet(packet: &mut Packet) -> result::Result<Self> {
let seconds = try!(packet.read_uint()); let seconds = try!(packet.read_uint());
Ok(WishlistIntervalResponse { Ok(WishlistIntervalResponse {
seconds: seconds, seconds: seconds,


+ 121
- 0
src/result.rs View File

@ -0,0 +1,121 @@
use std::fmt;
use std::io;
use std::result;
use std::error;
use std::str;
use std::sync::mpsc;
use rustc_serialize::json;
use websocket;
use control;
use proto;
#[derive(Debug)]
pub enum Error {
InvalidEnumError(usize),
IOError(io::Error),
JSONEncoderError(json::EncoderError),
JSONDecoderError(json::DecoderError),
SendControlRequestError(mpsc::SendError<control::Request>),
SendProtoResponseError(mpsc::SendError<proto::Response>),
Utf8Error(str::Utf8Error),
WebSocketError(websocket::result::WebSocketError),
}
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::SendControlRequestError(ref err) =>
write!(fmt, "SendControlRequestError: {}", err),
Error::SendProtoResponseError(ref err) =>
write!(fmt, "SendProtoResponseError: {}", err),
Error::Utf8Error(ref err) =>
write!(fmt, "Utf8Error: {}", err),
Error::WebSocketError(ref err) =>
write!(fmt, "WebSocketError: {}", err),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::InvalidEnumError(_) => "InvalidEnumError",
Error::IOError(_) => "IOError",
Error::JSONEncoderError(_) => "JSONEncoderError",
Error::JSONDecoderError(_) => "JSONDecoderError",
Error::SendControlRequestError(_) => "SendControlRequestError",
Error::SendProtoResponseError(_) => "SendProtoResponseError",
Error::Utf8Error(_) => "Utf8Error",
Error::WebSocketError(_) => "WebSocketError",
}
}
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::SendControlRequestError(ref err) => Some(err),
Error::SendProtoResponseError(ref err) => Some(err),
Error::Utf8Error(ref err) => Some(err),
Error::WebSocketError(ref err) => Some(err),
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::IOError(err)
}
}
impl From<json::EncoderError> for Error {
fn from(err: json::EncoderError) -> Self {
Error::JSONEncoderError(err)
}
}
impl From<json::DecoderError> for Error {
fn from(err: json::DecoderError) -> Self {
Error::JSONDecoderError(err)
}
}
impl From<mpsc::SendError<control::Request>> for Error {
fn from(err: mpsc::SendError<control::Request>) -> Self {
Error::SendControlRequestError(err)
}
}
impl From<mpsc::SendError<proto::Response>> for Error {
fn from(err: mpsc::SendError<proto::Response>) -> Self {
Error::SendProtoResponseError(err)
}
}
impl From<str::Utf8Error> for Error {
fn from(err: str::Utf8Error) -> Self {
Error::Utf8Error(err)
}
}
impl From<websocket::result::WebSocketError> for Error {
fn from(err: websocket::result::WebSocketError) -> Self {
Error::WebSocketError(err)
}
}
pub type Result<T> = result::Result<T, Error>;

+ 31
- 4
src/user.rs View File

@ -1,15 +1,40 @@
use std::collections; use std::collections;
use proto::server; use proto::server;
use result;
const STATUS_OFFLINE: u32 = 1;
const STATUS_AWAY: u32 = 2;
const STATUS_ONLINE: u32 = 3;
/// This enumeration is the list of possible user statuses. /// This enumeration is the list of possible user statuses.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum Status { pub enum Status {
/// The user if offline. /// The user if offline.
Offline = 1,
Offline,
/// The user is connected, but AFK. /// The user is connected, but AFK.
Away = 2,
Away,
/// The user is present. /// The user is present.
Online = 3,
Online,
}
impl Status {
pub fn from_u32(n: u32) -> result::Result<Status> {
match n {
STATUS_OFFLINE => Ok(Status::Offline),
STATUS_AWAY => Ok(Status::Away),
STATUS_ONLINE => Ok(Status::Online),
_ => Err(result::Error::InvalidEnumError(n as usize))
}
}
pub fn to_u32(&self) -> u32 {
match *self {
Status::Offline => STATUS_OFFLINE,
Status::Away => STATUS_AWAY,
Status::Online => STATUS_ONLINE,
}
}
} }
/// This structure contains the last known information about a fellow user. /// This structure contains the last known information about a fellow user.
@ -21,8 +46,10 @@ pub struct User {
pub status: Status, pub status: Status,
/// The average upload speed of the user. /// The average upload speed of the user.
pub average_speed: usize, pub average_speed: usize,
/// ???
/// ??? Nicotine calls it downloadnum.
pub num_downloads: usize, pub num_downloads: usize,
/// ??? Unknown field.
pub unknown: usize,
/// The number of files this user shares. /// The number of files this user shares.
pub num_files: usize, pub num_files: usize,
/// The number of folders this user shares. /// The number of folders this user shares.


Loading…
Cancel
Save