use std::io;
|
|
use std::net;
|
|
|
|
use proto::server::constants::*;
|
|
use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder};
|
|
use proto::packet::{Packet, PacketReadError, ReadFromPacket};
|
|
use user;
|
|
|
|
/*=================*
|
|
* SERVER RESPONSE *
|
|
*=================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum ServerResponse {
|
|
ConnectToPeerResponse(ConnectToPeerResponse),
|
|
FileSearchResponse(FileSearchResponse),
|
|
LoginResponse(LoginResponse),
|
|
PeerAddressResponse(PeerAddressResponse),
|
|
PrivilegedUsersResponse(PrivilegedUsersResponse),
|
|
RoomJoinResponse(RoomJoinResponse),
|
|
RoomLeaveResponse(RoomLeaveResponse),
|
|
RoomListResponse(RoomListResponse),
|
|
RoomMessageResponse(RoomMessageResponse),
|
|
RoomTickersResponse(RoomTickersResponse),
|
|
RoomUserJoinedResponse(RoomUserJoinedResponse),
|
|
RoomUserLeftResponse(RoomUserLeftResponse),
|
|
UserInfoResponse(UserInfoResponse),
|
|
UserStatusResponse(UserStatusResponse),
|
|
WishlistIntervalResponse(WishlistIntervalResponse),
|
|
|
|
// Unknown purpose
|
|
ParentMinSpeedResponse(ParentMinSpeedResponse),
|
|
ParentSpeedRatioResponse(ParentSpeedRatioResponse),
|
|
|
|
UnknownResponse(u32),
|
|
}
|
|
|
|
impl ReadFromPacket for ServerResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let code: u32 = try!(packet.read_value());
|
|
let resp = match code {
|
|
CODE_CONNECT_TO_PEER => ServerResponse::ConnectToPeerResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
CODE_FILE_SEARCH => ServerResponse::FileSearchResponse(try!(packet.read_value())),
|
|
|
|
CODE_LOGIN => ServerResponse::LoginResponse(try!(packet.read_value())),
|
|
|
|
CODE_PEER_ADDRESS => ServerResponse::PeerAddressResponse(try!(packet.read_value())),
|
|
|
|
CODE_PRIVILEGED_USERS => ServerResponse::PrivilegedUsersResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
CODE_ROOM_JOIN => ServerResponse::RoomJoinResponse(try!(packet.read_value())),
|
|
|
|
CODE_ROOM_LEAVE => ServerResponse::RoomLeaveResponse(try!(packet.read_value())),
|
|
|
|
CODE_ROOM_LIST => ServerResponse::RoomListResponse(try!(packet.read_value())),
|
|
|
|
CODE_ROOM_MESSAGE => ServerResponse::RoomMessageResponse(try!(packet.read_value())),
|
|
|
|
CODE_ROOM_TICKERS => ServerResponse::RoomTickersResponse(try!(packet.read_value())),
|
|
|
|
CODE_ROOM_USER_JOINED => ServerResponse::RoomUserJoinedResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
CODE_ROOM_USER_LEFT => ServerResponse::RoomUserLeftResponse(try!(packet.read_value())),
|
|
|
|
CODE_USER_INFO => ServerResponse::UserInfoResponse(try!(packet.read_value())),
|
|
|
|
CODE_USER_STATUS => ServerResponse::UserStatusResponse(try!(packet.read_value())),
|
|
|
|
CODE_WISHLIST_INTERVAL => ServerResponse::WishlistIntervalResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
CODE_PARENT_MIN_SPEED => ServerResponse::ParentMinSpeedResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
CODE_PARENT_SPEED_RATIO => ServerResponse::ParentSpeedRatioResponse(
|
|
try!(packet.read_value()),
|
|
),
|
|
|
|
code => ServerResponse::UnknownResponse(code),
|
|
};
|
|
let bytes_remaining = packet.bytes_remaining();
|
|
if bytes_remaining > 0 {
|
|
warn!(
|
|
"Packet with code {} contains {} extra bytes",
|
|
code,
|
|
bytes_remaining
|
|
)
|
|
}
|
|
Ok(resp)
|
|
}
|
|
}
|
|
|
|
impl ProtoEncode for ServerResponse {
|
|
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
|
|
match *self {
|
|
ServerResponse::ConnectToPeerResponse(ref response) => {
|
|
encoder.encode_u32(CODE_CONNECT_TO_PEER)?;
|
|
response.encode(encoder)?;
|
|
},
|
|
ServerResponse::FileSearchResponse(ref response) => {
|
|
encoder.encode_u32(CODE_FILE_SEARCH)?;
|
|
response.encode(encoder)?;
|
|
},
|
|
_ => {
|
|
unimplemented!();
|
|
},
|
|
};
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl ProtoDecode for ServerResponse {
|
|
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
|
|
let code = decoder.decode_u32()?;
|
|
let response = match code {
|
|
CODE_CONNECT_TO_PEER => {
|
|
let response = ConnectToPeerResponse::decode(decoder)?;
|
|
ServerResponse::ConnectToPeerResponse(response)
|
|
},
|
|
CODE_FILE_SEARCH => {
|
|
let response = FileSearchResponse::decode(decoder)?;
|
|
ServerResponse::FileSearchResponse(response)
|
|
},
|
|
_ => {
|
|
return Err(DecodeError::UnknownCodeError(code));
|
|
},
|
|
};
|
|
Ok(response)
|
|
}
|
|
}
|
|
|
|
/*=================*
|
|
* CONNECT TO PEER *
|
|
*=================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct ConnectToPeerResponse {
|
|
pub user_name: String,
|
|
pub connection_type: String,
|
|
pub ip: net::Ipv4Addr,
|
|
pub port: u16,
|
|
pub token: u32,
|
|
pub is_privileged: bool,
|
|
}
|
|
|
|
impl ReadFromPacket for ConnectToPeerResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let user_name = try!(packet.read_value());
|
|
let connection_type = try!(packet.read_value());
|
|
let ip = try!(packet.read_value());
|
|
let port = try!(packet.read_value());
|
|
let token = try!(packet.read_value());
|
|
let is_privileged = try!(packet.read_value());
|
|
|
|
Ok(ConnectToPeerResponse {
|
|
user_name: user_name,
|
|
connection_type: connection_type,
|
|
ip: ip,
|
|
port: port,
|
|
token: token,
|
|
is_privileged: is_privileged,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ProtoEncode for ConnectToPeerResponse {
|
|
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
|
|
encoder.encode_string(&self.user_name)?;
|
|
encoder.encode_string(&self.connection_type)?;
|
|
encoder.encode_ipv4_addr(self.ip)?;
|
|
encoder.encode_u16(self.port)?;
|
|
encoder.encode_u32(self.token)?;
|
|
encoder.encode_bool(self.is_privileged)
|
|
}
|
|
}
|
|
|
|
impl ProtoDecode for ConnectToPeerResponse {
|
|
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
|
|
let user_name = decoder.decode_string()?;
|
|
let connection_type = decoder.decode_string()?;
|
|
let ip = decoder.decode_ipv4_addr()?;
|
|
let port = decoder.decode_u16()?;
|
|
let token = decoder.decode_u32()?;
|
|
let is_privileged = decoder.decode_bool()?;
|
|
|
|
Ok(ConnectToPeerResponse {
|
|
user_name: user_name,
|
|
connection_type: connection_type,
|
|
ip: ip,
|
|
port: port,
|
|
token: token,
|
|
is_privileged: is_privileged,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*=============*
|
|
* FILE SEARCH *
|
|
*=============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct FileSearchResponse {
|
|
pub user_name: String,
|
|
pub ticket: u32,
|
|
pub query: String,
|
|
}
|
|
|
|
impl ReadFromPacket for FileSearchResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let user_name = try!(packet.read_value());
|
|
let ticket = try!(packet.read_value());
|
|
let query = try!(packet.read_value());
|
|
|
|
Ok(FileSearchResponse {
|
|
user_name: user_name,
|
|
ticket: ticket,
|
|
query: query,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ProtoEncode for FileSearchResponse {
|
|
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
|
|
encoder.encode_string(&self.user_name)?;
|
|
encoder.encode_u32(self.ticket)?;
|
|
encoder.encode_string(&self.query)
|
|
}
|
|
}
|
|
|
|
impl ProtoDecode for FileSearchResponse {
|
|
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
|
|
let user_name = decoder.decode_string()?;
|
|
let ticket = decoder.decode_u32()?;
|
|
let query = decoder.decode_string()?;
|
|
|
|
Ok(FileSearchResponse {
|
|
user_name: user_name,
|
|
ticket: ticket,
|
|
query: query,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*=======*
|
|
* LOGIN *
|
|
*=======*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub enum LoginResponse {
|
|
LoginOk {
|
|
motd: String,
|
|
ip: net::Ipv4Addr,
|
|
password_md5_opt: Option<String>,
|
|
},
|
|
LoginFail { reason: String },
|
|
}
|
|
|
|
impl ReadFromPacket for LoginResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let ok = try!(packet.read_value());
|
|
if ok {
|
|
let motd = try!(packet.read_value());
|
|
let ip = try!(packet.read_value());
|
|
|
|
match packet.read_value::<bool>() {
|
|
Ok(value) => debug!("LoginResponse last field: {}", value),
|
|
Err(e) => debug!("Error reading LoginResponse field: {:?}", e),
|
|
}
|
|
|
|
Ok(LoginResponse::LoginOk {
|
|
motd: motd,
|
|
ip: ip,
|
|
password_md5_opt: None,
|
|
})
|
|
} else {
|
|
Ok(LoginResponse::LoginFail {
|
|
reason: try!(packet.read_value()),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/*==================*
|
|
* PARENT MIN SPEED *
|
|
*==================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct ParentMinSpeedResponse {
|
|
pub value: u32,
|
|
}
|
|
|
|
impl ReadFromPacket for ParentMinSpeedResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let value = try!(packet.read_value());
|
|
Ok(ParentMinSpeedResponse { value: value })
|
|
}
|
|
}
|
|
|
|
/*====================*
|
|
* PARENT SPEED RATIO *
|
|
*====================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct ParentSpeedRatioResponse {
|
|
pub value: u32,
|
|
}
|
|
|
|
impl ReadFromPacket for ParentSpeedRatioResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let value = try!(packet.read_value());
|
|
Ok(ParentSpeedRatioResponse { value: value })
|
|
}
|
|
}
|
|
|
|
/*==============*
|
|
* PEER ADDRESS *
|
|
*==============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct PeerAddressResponse {
|
|
username: String,
|
|
ip: net::Ipv4Addr,
|
|
port: u16,
|
|
}
|
|
|
|
impl ReadFromPacket for PeerAddressResponse {
|
|
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_value());
|
|
|
|
Ok(PeerAddressResponse {
|
|
username: username,
|
|
ip: ip,
|
|
port: port,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*==================*
|
|
* PRIVILEGED USERS *
|
|
*==================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct PrivilegedUsersResponse {
|
|
pub users: Vec<String>,
|
|
}
|
|
|
|
impl ReadFromPacket for PrivilegedUsersResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let users = try!(packet.read_value());
|
|
Ok(PrivilegedUsersResponse { users: users })
|
|
}
|
|
}
|
|
|
|
/*===========*
|
|
* ROOM JOIN *
|
|
*===========*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomJoinResponse {
|
|
pub room_name: String,
|
|
pub users: Vec<(String, user::User)>,
|
|
pub owner: Option<String>,
|
|
pub operators: Vec<String>,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomJoinResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let mut response = RoomJoinResponse {
|
|
room_name: try!(packet.read_value()),
|
|
users: Vec::new(),
|
|
owner: None,
|
|
operators: Vec::new(),
|
|
};
|
|
|
|
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_value()));
|
|
|
|
let num_operators: usize = try!(packet.read_value());
|
|
for _ in 0..num_operators {
|
|
response.operators.push(try!(packet.read_value()));
|
|
}
|
|
}
|
|
|
|
Ok(response)
|
|
}
|
|
}
|
|
|
|
impl RoomJoinResponse {
|
|
fn read_user_infos(&mut self, packet: &mut Packet) -> Result<(), PacketReadError> {
|
|
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 || num_users != num_infos || num_users != num_free_slots ||
|
|
num_users != num_countries
|
|
{
|
|
warn!(
|
|
"RoomJoinResponse: mismatched vector sizes {}, {}, {}, {}, {}",
|
|
num_users,
|
|
num_statuses,
|
|
num_infos,
|
|
num_free_slots,
|
|
num_countries
|
|
);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
/*============*
|
|
* ROOM LEAVE *
|
|
*============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomLeaveResponse {
|
|
pub room_name: String,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomLeaveResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
Ok(RoomLeaveResponse { room_name: try!(packet.read_value()) })
|
|
}
|
|
}
|
|
|
|
/*===========*
|
|
* ROOM LIST *
|
|
*===========*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomListResponse {
|
|
pub rooms: Vec<(String, u32)>,
|
|
pub owned_private_rooms: Vec<(String, u32)>,
|
|
pub other_private_rooms: Vec<(String, u32)>,
|
|
pub operated_private_room_names: Vec<String>,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomListResponse {
|
|
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) -> Result<Vec<(String, u32)>, PacketReadError> {
|
|
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
|
|
);
|
|
}
|
|
|
|
Ok(rooms)
|
|
}
|
|
}
|
|
|
|
/*==============*
|
|
* ROOM MESSAGE *
|
|
*==============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomMessageResponse {
|
|
pub room_name: String,
|
|
pub user_name: String,
|
|
pub message: String,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomMessageResponse {
|
|
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,
|
|
message: message,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*==============*
|
|
* ROOM MESSAGE *
|
|
*==============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomTickersResponse {
|
|
pub room_name: String,
|
|
pub tickers: Vec<(String, String)>,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomTickersResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let room_name = try!(packet.read_value());
|
|
|
|
let num_tickers: usize = try!(packet.read_value());
|
|
let mut tickers = Vec::new();
|
|
for _ in 0..num_tickers {
|
|
let user_name = try!(packet.read_value());
|
|
let message = try!(packet.read_value());
|
|
tickers.push((user_name, message))
|
|
}
|
|
|
|
Ok(RoomTickersResponse {
|
|
room_name: room_name,
|
|
tickers: tickers,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*==================*
|
|
* ROOM USER JOINED *
|
|
*==================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomUserJoinedResponse {
|
|
pub room_name: String,
|
|
pub user_name: String,
|
|
pub user: user::User,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomUserJoinedResponse {
|
|
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 = try!(packet.read_value());
|
|
|
|
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_value());
|
|
|
|
Ok(RoomUserJoinedResponse {
|
|
room_name: room_name,
|
|
user_name: user_name,
|
|
user: user::User {
|
|
status: status,
|
|
average_speed: average_speed,
|
|
num_downloads: num_downloads,
|
|
unknown: unknown,
|
|
num_files: num_files,
|
|
num_folders: num_folders,
|
|
num_free_slots: num_free_slots,
|
|
country: country,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
/*================*
|
|
* ROOM USER LEFT *
|
|
*================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct RoomUserLeftResponse {
|
|
pub room_name: String,
|
|
pub user_name: String,
|
|
}
|
|
|
|
impl ReadFromPacket for RoomUserLeftResponse {
|
|
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,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*===========*
|
|
* USER INFO *
|
|
*===========*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct UserInfoResponse {
|
|
pub user_name: String,
|
|
pub average_speed: usize,
|
|
pub num_downloads: usize,
|
|
pub num_files: usize,
|
|
pub num_folders: usize,
|
|
}
|
|
|
|
impl ReadFromPacket for UserInfoResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let user_name = try!(packet.read_value());
|
|
let average_speed = try!(packet.read_value());
|
|
let num_downloads = try!(packet.read_value());
|
|
let num_files = try!(packet.read_value());
|
|
let num_folders = try!(packet.read_value());
|
|
Ok(UserInfoResponse {
|
|
user_name: user_name,
|
|
average_speed: average_speed,
|
|
num_downloads: num_downloads,
|
|
num_files: num_files,
|
|
num_folders: num_folders,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*=============*
|
|
* USER STATUS *
|
|
*=============*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct UserStatusResponse {
|
|
pub user_name: String,
|
|
pub status: user::Status,
|
|
pub is_privileged: bool,
|
|
}
|
|
|
|
impl ReadFromPacket for UserStatusResponse {
|
|
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,
|
|
is_privileged: is_privileged,
|
|
})
|
|
}
|
|
}
|
|
|
|
/*===================*
|
|
* WISHLIST INTERVAL *
|
|
*===================*/
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct WishlistIntervalResponse {
|
|
pub seconds: u32,
|
|
}
|
|
|
|
impl ReadFromPacket for WishlistIntervalResponse {
|
|
fn read_from_packet(packet: &mut Packet) -> Result<Self, PacketReadError> {
|
|
let seconds = try!(packet.read_value());
|
|
Ok(WishlistIntervalResponse { seconds: seconds })
|
|
}
|
|
}
|
|
|
|
/*=======*
|
|
* TESTS *
|
|
*=======*/
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::io;
|
|
use std::net;
|
|
|
|
use bytes::BytesMut;
|
|
|
|
use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder};
|
|
use proto::codec::tests::roundtrip;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn roundtrip_connect_to_peer() {
|
|
roundtrip(ServerResponse::ConnectToPeerResponse(ConnectToPeerResponse {
|
|
user_name: "alice".to_string(),
|
|
connection_type: "P".to_string(),
|
|
ip: net::Ipv4Addr::new(192, 168, 254, 1),
|
|
port: 1337,
|
|
token: 42,
|
|
is_privileged: true,
|
|
}))
|
|
}
|
|
|
|
#[test]
|
|
fn roundtrip_file_search() {
|
|
roundtrip(ServerResponse::FileSearchResponse(FileSearchResponse {
|
|
user_name: "alice".to_string(),
|
|
ticket: 1337,
|
|
query: "foo.txt".to_string(),
|
|
}))
|
|
}
|
|
}
|