Solstice client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

1363 lines
34 KiB

use std::net;
use log::{debug, warn};
use crate::core::{
ValueDecode, ValueDecodeError, ValueDecoder, ValueEncode, ValueEncodeError,
ValueEncoder,
};
use crate::peer::PeerConnectionType;
use crate::server::constants::*;
use crate::{User, UserStatus};
/*=================*
* SERVER RESPONSE *
*=================*/
#[derive(Clone, 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 ValueEncode for ServerResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
match *self {
ServerResponse::ConnectToPeerResponse(ref response) => {
encoder.encode_u32(CODE_CONNECT_TO_PEER)?;
response.encode_to(encoder)?;
}
ServerResponse::FileSearchResponse(ref response) => {
encoder.encode_u32(CODE_FILE_SEARCH)?;
response.encode_to(encoder)?;
}
ServerResponse::LoginResponse(ref response) => {
encoder.encode_u32(CODE_LOGIN)?;
response.encode_to(encoder)?;
}
ServerResponse::ParentMinSpeedResponse(ref response) => {
encoder.encode_u32(CODE_PARENT_MIN_SPEED)?;
response.encode_to(encoder)?;
}
ServerResponse::ParentSpeedRatioResponse(ref response) => {
encoder.encode_u32(CODE_PARENT_SPEED_RATIO)?;
response.encode_to(encoder)?;
}
ServerResponse::PeerAddressResponse(ref response) => {
encoder.encode_u32(CODE_PEER_ADDRESS)?;
response.encode_to(encoder)?;
}
ServerResponse::PrivilegedUsersResponse(ref response) => {
encoder.encode_u32(CODE_PRIVILEGED_USERS)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomJoinResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_JOIN)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomLeaveResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_LEAVE)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomListResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_LIST)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomMessageResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_MESSAGE)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomTickersResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_TICKERS)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomUserJoinedResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_USER_JOINED)?;
response.encode_to(encoder)?;
}
ServerResponse::RoomUserLeftResponse(ref response) => {
encoder.encode_u32(CODE_ROOM_USER_LEFT)?;
response.encode_to(encoder)?;
}
ServerResponse::UserInfoResponse(ref response) => {
encoder.encode_u32(CODE_USER_INFO)?;
response.encode_to(encoder)?;
}
ServerResponse::UserStatusResponse(ref response) => {
encoder.encode_u32(CODE_USER_STATUS)?;
response.encode_to(encoder)?;
}
ServerResponse::WishlistIntervalResponse(ref response) => {
encoder.encode_u32(CODE_WISHLIST_INTERVAL)?;
response.encode_to(encoder)?;
}
_ => {
unimplemented!();
}
};
Ok(())
}
}
impl ValueDecode for ServerResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let position = decoder.position();
let code: u32 = decoder.decode()?;
let response = match code {
CODE_CONNECT_TO_PEER => {
let response = decoder.decode()?;
ServerResponse::ConnectToPeerResponse(response)
}
CODE_FILE_SEARCH => {
let response = decoder.decode()?;
ServerResponse::FileSearchResponse(response)
}
CODE_LOGIN => {
let response = decoder.decode()?;
ServerResponse::LoginResponse(response)
}
CODE_PARENT_MIN_SPEED => {
let response = decoder.decode()?;
ServerResponse::ParentMinSpeedResponse(response)
}
CODE_PARENT_SPEED_RATIO => {
let response = decoder.decode()?;
ServerResponse::ParentSpeedRatioResponse(response)
}
CODE_PEER_ADDRESS => {
let response = decoder.decode()?;
ServerResponse::PeerAddressResponse(response)
}
CODE_PRIVILEGED_USERS => {
let response = decoder.decode()?;
ServerResponse::PrivilegedUsersResponse(response)
}
CODE_ROOM_JOIN => {
let response = decoder.decode()?;
ServerResponse::RoomJoinResponse(response)
}
CODE_ROOM_LEAVE => {
let response = decoder.decode()?;
ServerResponse::RoomLeaveResponse(response)
}
CODE_ROOM_LIST => {
let response = decoder.decode()?;
ServerResponse::RoomListResponse(response)
}
CODE_ROOM_MESSAGE => {
let response = decoder.decode()?;
ServerResponse::RoomMessageResponse(response)
}
CODE_ROOM_TICKERS => {
let response = decoder.decode()?;
ServerResponse::RoomTickersResponse(response)
}
CODE_ROOM_USER_JOINED => {
let response = decoder.decode()?;
ServerResponse::RoomUserJoinedResponse(response)
}
CODE_ROOM_USER_LEFT => {
let response = decoder.decode()?;
ServerResponse::RoomUserLeftResponse(response)
}
CODE_USER_INFO => {
let response = decoder.decode()?;
ServerResponse::UserInfoResponse(response)
}
CODE_USER_STATUS => {
let response = decoder.decode()?;
ServerResponse::UserStatusResponse(response)
}
CODE_WISHLIST_INTERVAL => {
let response = decoder.decode()?;
ServerResponse::WishlistIntervalResponse(response)
}
_ => {
return Err(ValueDecodeError::InvalidData {
value_name: "server response code".to_string(),
cause: format!("unknown value {}", code),
position: position,
});
}
};
Ok(response)
}
}
/*=================*
* CONNECT TO PEER *
*=================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConnectToPeerResponse {
pub user_name: String,
pub connection_type: PeerConnectionType,
pub ip: net::Ipv4Addr,
pub port: u16,
pub token: u32,
pub is_privileged: bool,
}
impl From<ConnectToPeerResponse> for ServerResponse {
fn from(response: ConnectToPeerResponse) -> Self {
Self::ConnectToPeerResponse(response)
}
}
impl ValueEncode for ConnectToPeerResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode(&self.user_name)?;
encoder.encode(&self.connection_type)?;
encoder.encode(&self.ip)?;
encoder.encode_u16(self.port)?;
encoder.encode_u32(self.token)?;
encoder.encode_bool(self.is_privileged)
}
}
impl ValueDecode for ConnectToPeerResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let connection_type = decoder.decode()?;
let ip = decoder.decode()?;
let port = decoder.decode()?;
let token = decoder.decode()?;
let is_privileged = decoder.decode()?;
Ok(ConnectToPeerResponse {
user_name,
connection_type,
ip,
port,
token,
is_privileged,
})
}
}
/*=============*
* FILE SEARCH *
*=============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FileSearchResponse {
pub user_name: String,
pub ticket: u32,
pub query: String,
}
impl From<FileSearchResponse> for ServerResponse {
fn from(response: FileSearchResponse) -> Self {
Self::FileSearchResponse(response)
}
}
impl ValueEncode for FileSearchResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.user_name)?;
encoder.encode_u32(self.ticket)?;
encoder.encode_string(&self.query)
}
}
impl ValueDecode for FileSearchResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let ticket = decoder.decode()?;
let query = decoder.decode()?;
Ok(FileSearchResponse {
user_name,
ticket,
query,
})
}
}
/*=======*
* LOGIN *
*=======*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoginResponse {
LoginOk {
motd: String,
ip: net::Ipv4Addr,
password_md5_opt: Option<String>,
},
LoginFail {
reason: String,
},
}
impl From<LoginResponse> for ServerResponse {
fn from(response: LoginResponse) -> Self {
Self::LoginResponse(response)
}
}
impl ValueEncode for LoginResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
match *self {
LoginResponse::LoginOk {
ref motd,
ip,
password_md5_opt: _,
} => {
encoder.encode_bool(true)?;
encoder.encode(motd)?;
encoder.encode(&ip)?;
}
LoginResponse::LoginFail { ref reason } => {
encoder.encode_bool(false)?;
encoder.encode(reason)?;
}
};
Ok(())
}
}
impl ValueDecode for LoginResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let ok: bool = decoder.decode()?;
if !ok {
let reason = decoder.decode()?;
return Ok(LoginResponse::LoginFail { reason });
}
let motd = decoder.decode()?;
let ip = decoder.decode()?;
let result = decoder.decode::<bool>();
match result {
Ok(value) => debug!("LoginResponse last field: {}", value),
Err(e) => debug!("Error reading LoginResponse field: {:?}", e),
}
Ok(LoginResponse::LoginOk {
motd,
ip,
password_md5_opt: None,
})
}
}
/*==================*
* PARENT MIN SPEED *
*==================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParentMinSpeedResponse {
pub value: u32,
}
impl From<ParentMinSpeedResponse> for ServerResponse {
fn from(response: ParentMinSpeedResponse) -> Self {
Self::ParentMinSpeedResponse(response)
}
}
impl ValueEncode for ParentMinSpeedResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_u32(self.value)
}
}
impl ValueDecode for ParentMinSpeedResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let value = decoder.decode()?;
Ok(ParentMinSpeedResponse { value })
}
}
/*====================*
* PARENT SPEED RATIO *
*====================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParentSpeedRatioResponse {
pub value: u32,
}
impl From<ParentSpeedRatioResponse> for ServerResponse {
fn from(response: ParentSpeedRatioResponse) -> Self {
Self::ParentSpeedRatioResponse(response)
}
}
impl ValueEncode for ParentSpeedRatioResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_u32(self.value)
}
}
impl ValueDecode for ParentSpeedRatioResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let value = decoder.decode()?;
Ok(ParentSpeedRatioResponse { value })
}
}
/*==============*
* PEER ADDRESS *
*==============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PeerAddressResponse {
user_name: String,
ip: net::Ipv4Addr,
port: u16,
}
impl From<PeerAddressResponse> for ServerResponse {
fn from(response: PeerAddressResponse) -> Self {
Self::PeerAddressResponse(response)
}
}
impl ValueEncode for PeerAddressResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode(&self.user_name)?;
encoder.encode(&self.ip)?;
encoder.encode_u16(self.port)
}
}
impl ValueDecode for PeerAddressResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let ip = decoder.decode()?;
let port = decoder.decode()?;
Ok(PeerAddressResponse {
user_name,
ip,
port,
})
}
}
/*==================*
* PRIVILEGED USERS *
*==================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PrivilegedUsersResponse {
pub users: Vec<String>,
}
impl From<PrivilegedUsersResponse> for ServerResponse {
fn from(response: PrivilegedUsersResponse) -> Self {
Self::PrivilegedUsersResponse(response)
}
}
impl ValueEncode for PrivilegedUsersResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode(&self.users)
}
}
impl ValueDecode for PrivilegedUsersResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let users = decoder.decode()?;
Ok(PrivilegedUsersResponse { users })
}
}
/*===========*
* ROOM JOIN *
*===========*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomJoinResponse {
pub room_name: String,
pub users: Vec<User>,
pub owner: Option<String>,
pub operators: Vec<String>,
}
impl From<RoomJoinResponse> for ServerResponse {
fn from(response: RoomJoinResponse) -> Self {
Self::RoomJoinResponse(response)
}
}
// This struct is defined to enable decoding a vector of such values for
// `RoomJoinResponse`, but its data is inlined in the `User` struct.
// For details about individual fields, see said `User` struct.
#[derive(Clone, Debug, Eq, PartialEq)]
struct UserInfo {
average_speed: u32,
num_downloads: u32,
unknown: u32,
num_files: u32,
num_folders: u32,
}
impl UserInfo {
fn from_user(user: &User) -> Self {
Self {
average_speed: user.average_speed as u32,
num_downloads: user.num_downloads as u32,
unknown: user.unknown as u32,
num_files: user.num_files as u32,
num_folders: user.num_folders as u32,
}
}
}
fn build_user(
name: String,
status: UserStatus,
info: UserInfo,
num_free_slots: u32,
country: String,
) -> User {
User {
name,
status,
average_speed: info.average_speed as usize,
num_downloads: info.num_downloads as usize,
unknown: info.unknown as usize,
num_files: info.num_files as usize,
num_folders: info.num_folders as usize,
num_free_slots: num_free_slots as usize,
country,
}
}
impl ValueEncode for UserInfo {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_u32(self.average_speed)?;
encoder.encode_u32(self.num_downloads)?;
encoder.encode_u32(self.unknown)?;
encoder.encode_u32(self.num_files)?;
encoder.encode_u32(self.num_folders)
}
}
impl ValueDecode for UserInfo {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let average_speed = decoder.decode()?;
let num_downloads = decoder.decode()?;
let unknown = decoder.decode()?;
let num_files = decoder.decode()?;
let num_folders = decoder.decode()?;
Ok(UserInfo {
average_speed,
num_downloads,
unknown,
num_files,
num_folders,
})
}
}
impl ValueEncode for RoomJoinResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
let mut user_names = vec![];
let mut user_statuses = vec![];
let mut user_infos = vec![];
let mut user_free_slots = vec![];
let mut user_countries = vec![];
for user in &self.users {
user_names.push(&user.name);
user_statuses.push(user.status);
user_infos.push(UserInfo::from_user(user));
user_free_slots.push(user.num_free_slots as u32);
user_countries.push(&user.country);
}
encoder.encode_string(&self.room_name)?;
encoder.encode(&user_names)?;
encoder.encode(&user_statuses)?;
encoder.encode(&user_infos)?;
encoder.encode(&user_free_slots)?;
encoder.encode(&user_countries)?;
if let Some(ref owner) = self.owner {
encoder.encode_string(owner)?;
encoder.encode(&self.operators)?;
}
Ok(())
}
}
fn build_users(
mut names: Vec<String>,
mut statuses: Vec<UserStatus>,
mut infos: Vec<UserInfo>,
mut free_slots: Vec<u32>,
mut countries: Vec<String>,
) -> Vec<User> {
let mut users = vec![];
loop {
let name_opt = names.pop();
let status_opt = statuses.pop();
let info_opt = infos.pop();
let slots_opt = free_slots.pop();
let country_opt = countries.pop();
match (name_opt, status_opt, info_opt, slots_opt, country_opt) {
(Some(name), Some(status), Some(info), Some(slots), Some(country)) => {
users.push(build_user(name, status, info, slots, country))
}
_ => break,
}
}
users.reverse();
users
}
impl ValueDecode for RoomJoinResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
let user_names = decoder.decode()?;
let user_statuses = decoder.decode()?;
let user_infos = decoder.decode()?;
let user_free_slots = decoder.decode()?;
let user_countries = decoder.decode()?;
let mut owner = None;
let mut operators = vec![];
if decoder.has_remaining() {
owner = Some(decoder.decode()?);
operators = decoder.decode()?;
}
let users = build_users(
user_names,
user_statuses,
user_infos,
user_free_slots,
user_countries,
);
Ok(RoomJoinResponse {
room_name,
users,
owner,
operators,
})
}
}
/*============*
* ROOM LEAVE *
*============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomLeaveResponse {
pub room_name: String,
}
impl From<RoomLeaveResponse> for ServerResponse {
fn from(response: RoomLeaveResponse) -> Self {
Self::RoomLeaveResponse(response)
}
}
impl ValueEncode for RoomLeaveResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.room_name)
}
}
impl ValueDecode for RoomLeaveResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
Ok(RoomLeaveResponse { room_name })
}
}
/*===========*
* ROOM LIST *
*===========*/
#[derive(Clone, 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 From<RoomListResponse> for ServerResponse {
fn from(response: RoomListResponse) -> Self {
Self::RoomListResponse(response)
}
}
impl RoomListResponse {
fn build_rooms(
mut room_names: Vec<String>,
mut user_counts: Vec<u32>,
) -> Vec<(String, u32)> {
let mut rooms = vec![];
loop {
let room_name_opt = room_names.pop();
let user_count_opt = user_counts.pop();
match (room_name_opt, user_count_opt) {
(Some(room_name), Some(user_count)) => {
rooms.push((room_name, user_count))
}
_ => break,
}
}
if !room_names.is_empty() {
warn!(
"Unmatched room names in room list response: {:?}",
room_names
)
}
if !user_counts.is_empty() {
warn!(
"Unmatched user counts in room list response: {:?}",
user_counts
)
}
rooms.reverse();
rooms
}
fn decode_rooms(
decoder: &mut ValueDecoder,
) -> Result<Vec<(String, u32)>, ValueDecodeError> {
let room_names = decoder.decode()?;
let user_counts = decoder.decode()?;
Ok(Self::build_rooms(room_names, user_counts))
}
fn encode_rooms(
rooms: &[(String, u32)],
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
let mut room_names = vec![];
let mut user_counts = vec![];
for &(ref room_name, user_count) in rooms {
room_names.push(room_name);
user_counts.push(user_count);
}
encoder.encode(&room_names)?;
encoder.encode(&user_counts)
}
}
impl ValueEncode for RoomListResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
Self::encode_rooms(&self.rooms, encoder)?;
Self::encode_rooms(&self.owned_private_rooms, encoder)?;
Self::encode_rooms(&self.other_private_rooms, encoder)?;
encoder.encode(&self.operated_private_room_names)
}
}
impl ValueDecode for RoomListResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let rooms = RoomListResponse::decode_rooms(decoder)?;
let owned_private_rooms = RoomListResponse::decode_rooms(decoder)?;
let other_private_rooms = RoomListResponse::decode_rooms(decoder)?;
let operated_private_room_names = decoder.decode()?;
Ok(RoomListResponse {
rooms,
owned_private_rooms,
other_private_rooms,
operated_private_room_names,
})
}
}
/*==============*
* ROOM MESSAGE *
*==============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomMessageResponse {
pub room_name: String,
pub user_name: String,
pub message: String,
}
impl From<RoomMessageResponse> for ServerResponse {
fn from(response: RoomMessageResponse) -> Self {
Self::RoomMessageResponse(response)
}
}
impl ValueEncode for RoomMessageResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.room_name)?;
encoder.encode_string(&self.user_name)?;
encoder.encode_string(&self.message)
}
}
impl ValueDecode for RoomMessageResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
let user_name = decoder.decode()?;
let message = decoder.decode()?;
Ok(RoomMessageResponse {
room_name,
user_name,
message,
})
}
}
/*==============*
* ROOM TICKERS *
*==============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomTickersResponse {
pub room_name: String,
pub tickers: Vec<(String, String)>,
}
impl From<RoomTickersResponse> for ServerResponse {
fn from(response: RoomTickersResponse) -> Self {
Self::RoomTickersResponse(response)
}
}
impl ValueEncode for RoomTickersResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.room_name)?;
encoder.encode(&self.tickers)
}
}
impl ValueDecode for RoomTickersResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
let tickers = decoder.decode()?;
Ok(RoomTickersResponse { room_name, tickers })
}
}
/*==================*
* ROOM USER JOINED *
*==================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomUserJoinedResponse {
pub room_name: String,
pub user: User,
}
impl From<RoomUserJoinedResponse> for ServerResponse {
fn from(response: RoomUserJoinedResponse) -> Self {
Self::RoomUserJoinedResponse(response)
}
}
impl ValueEncode for RoomUserJoinedResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.room_name)?;
encoder.encode_string(&self.user.name)?;
self.user.status.encode_to(encoder)?;
UserInfo::from_user(&self.user).encode_to(encoder)?;
encoder.encode_u32(self.user.num_free_slots as u32)?;
encoder.encode_string(&self.user.country)
}
}
impl ValueDecode for RoomUserJoinedResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
let user_name = decoder.decode()?;
let status = decoder.decode()?;
let info = decoder.decode()?;
let num_free_slots = decoder.decode()?;
let country = decoder.decode()?;
Ok(RoomUserJoinedResponse {
room_name,
user: build_user(user_name, status, info, num_free_slots, country),
})
}
}
/*================*
* ROOM USER LEFT *
*================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RoomUserLeftResponse {
pub room_name: String,
pub user_name: String,
}
impl From<RoomUserLeftResponse> for ServerResponse {
fn from(response: RoomUserLeftResponse) -> Self {
Self::RoomUserLeftResponse(response)
}
}
impl ValueEncode for RoomUserLeftResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.room_name)?;
encoder.encode_string(&self.user_name)
}
}
impl ValueDecode for RoomUserLeftResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let room_name = decoder.decode()?;
let user_name = decoder.decode()?;
Ok(RoomUserLeftResponse {
room_name,
user_name,
})
}
}
/*===========*
* USER INFO *
*===========*/
#[derive(Clone, 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 From<UserInfoResponse> for ServerResponse {
fn from(response: UserInfoResponse) -> Self {
Self::UserInfoResponse(response)
}
}
impl ValueEncode for UserInfoResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.user_name)?;
encoder.encode_u32(self.average_speed as u32)?;
encoder.encode_u32(self.num_downloads as u32)?;
encoder.encode_u32(self.num_files as u32)?;
encoder.encode_u32(self.num_folders as u32)
}
}
impl ValueDecode for UserInfoResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let average_speed: u32 = decoder.decode()?;
let num_downloads: u32 = decoder.decode()?;
let num_files: u32 = decoder.decode()?;
let num_folders: u32 = decoder.decode()?;
Ok(UserInfoResponse {
user_name,
average_speed: average_speed as usize,
num_downloads: num_downloads as usize,
num_files: num_files as usize,
num_folders: num_folders as usize,
})
}
}
/*=============*
* USER STATUS *
*=============*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UserStatusResponse {
pub user_name: String,
pub status: UserStatus,
pub is_privileged: bool,
}
impl From<UserStatusResponse> for ServerResponse {
fn from(response: UserStatusResponse) -> Self {
Self::UserStatusResponse(response)
}
}
impl ValueEncode for UserStatusResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_string(&self.user_name)?;
self.status.encode_to(encoder)?;
encoder.encode_bool(self.is_privileged)
}
}
impl ValueDecode for UserStatusResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let user_name = decoder.decode()?;
let status = decoder.decode()?;
let is_privileged = decoder.decode()?;
Ok(UserStatusResponse {
user_name,
status,
is_privileged,
})
}
}
/*===================*
* WISHLIST INTERVAL *
*===================*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WishlistIntervalResponse {
pub seconds: u32,
}
impl From<WishlistIntervalResponse> for ServerResponse {
fn from(response: WishlistIntervalResponse) -> Self {
Self::WishlistIntervalResponse(response)
}
}
impl ValueEncode for WishlistIntervalResponse {
fn encode_to(
&self,
encoder: &mut ValueEncoder,
) -> Result<(), ValueEncodeError> {
encoder.encode_u32(self.seconds)
}
}
impl ValueDecode for WishlistIntervalResponse {
fn decode_from(decoder: &mut ValueDecoder) -> Result<Self, ValueDecodeError> {
let seconds = decoder.decode()?;
Ok(WishlistIntervalResponse { seconds })
}
}
/*=======*
* TESTS *
*=======*/
#[cfg(test)]
mod tests {
use std::net;
use bytes::BytesMut;
use crate::core::testing::roundtrip;
use crate::core::{ValueDecodeError, ValueDecoder};
use super::*;
#[test]
fn invalid_code() {
let mut bytes = BytesMut::new();
bytes.extend_from_slice(&[57, 5, 0, 0]);
let result = ValueDecoder::new(&bytes).decode::<ServerResponse>();
assert_eq!(
result,
Err(ValueDecodeError::InvalidData {
value_name: "server response code".to_string(),
cause: "unknown value 1337".to_string(),
position: 0,
})
);
}
#[test]
fn roundtrip_connect_to_peer() {
roundtrip(ServerResponse::ConnectToPeerResponse(
ConnectToPeerResponse {
user_name: "alice".to_string(),
connection_type: PeerConnectionType::Peer,
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(),
}))
}
#[test]
fn roundtrip_login_ok() {
roundtrip(ServerResponse::LoginResponse(LoginResponse::LoginOk {
motd: "welcome one welcome all!".to_string(),
ip: net::Ipv4Addr::new(127, 0, 0, 1),
password_md5_opt: None,
}))
}
#[test]
fn roundtrip_login_fail() {
roundtrip(ServerResponse::LoginResponse(LoginResponse::LoginFail {
reason: "I just don't like you".to_string(),
}))
}
#[test]
fn roundtrip_parent_min_speed() {
roundtrip(ServerResponse::ParentMinSpeedResponse(
ParentMinSpeedResponse { value: 1337 },
))
}
#[test]
fn roundtrip_parent_speed_ratio() {
roundtrip(ServerResponse::ParentSpeedRatioResponse(
ParentSpeedRatioResponse { value: 1337 },
))
}
#[test]
fn roundtrip_peer_address() {
roundtrip(ServerResponse::PeerAddressResponse(PeerAddressResponse {
user_name: "alice".to_string(),
ip: net::Ipv4Addr::new(127, 0, 0, 1),
port: 1337,
}))
}
#[test]
fn roundtrip_privileged_users() {
roundtrip(ServerResponse::PrivilegedUsersResponse(
PrivilegedUsersResponse {
users: vec![
"alice".to_string(),
"bob".to_string(),
"chris".to_string(),
"dory".to_string(),
],
},
))
}
#[test]
fn roundtrip_room_join() {
roundtrip(ServerResponse::RoomJoinResponse(RoomJoinResponse {
room_name: "red".to_string(),
users: vec![
User {
name: "alice".to_string(),
status: UserStatus::Online,
average_speed: 1000,
num_downloads: 1001,
unknown: 1002,
num_files: 1003,
num_folders: 1004,
num_free_slots: 1005,
country: "US".to_string(),
},
User {
name: "barbara".to_string(),
status: UserStatus::Away,
average_speed: 2000,
num_downloads: 2001,
unknown: 2002,
num_files: 2003,
num_folders: 2004,
num_free_slots: 2005,
country: "DE".to_string(),
},
],
owner: Some("carol".to_string()),
operators: vec!["deirdre".to_string(), "erica".to_string()],
}))
}
#[test]
fn roundtrip_room_join_no_owner() {
roundtrip(ServerResponse::RoomJoinResponse(RoomJoinResponse {
room_name: "red".to_string(),
users: vec![],
owner: None,
operators: vec![],
}))
}
#[test]
fn roundtrip_room_leave() {
roundtrip(ServerResponse::RoomLeaveResponse(RoomLeaveResponse {
room_name: "red".to_string(),
}))
}
#[test]
fn roundtrip_room_list() {
roundtrip(ServerResponse::RoomListResponse(RoomListResponse {
rooms: vec![("red".to_string(), 12), ("blue".to_string(), 13)],
owned_private_rooms: vec![
("green".to_string(), 14),
("purple".to_string(), 15),
],
other_private_rooms: vec![
("yellow".to_string(), 16),
("orange".to_string(), 17),
],
operated_private_room_names: vec![
"brown".to_string(),
"pink".to_string(),
],
}))
}
#[test]
fn roundtrip_room_message() {
roundtrip(ServerResponse::RoomMessageResponse(RoomMessageResponse {
room_name: "red".to_string(),
user_name: "alice".to_string(),
message: "hello world!".to_string(),
}))
}
#[test]
fn roundtrip_room_tickers() {
roundtrip(ServerResponse::RoomTickersResponse(RoomTickersResponse {
room_name: "red".to_string(),
tickers: vec![
("alice".to_string(), "hello world!".to_string()),
("bob".to_string(), "hi alice :)".to_string()),
],
}))
}
#[test]
fn roundtrip_room_user_joined() {
roundtrip(ServerResponse::RoomUserJoinedResponse(
RoomUserJoinedResponse {
room_name: "red".to_string(),
user: User {
name: "alice".to_string(),
status: UserStatus::Online,
average_speed: 1000,
num_downloads: 1001,
unknown: 1002,
num_files: 1003,
num_folders: 1004,
num_free_slots: 1005,
country: "AR".to_string(),
},
},
))
}
#[test]
fn roundtrip_room_user_left() {
roundtrip(ServerResponse::RoomUserLeftResponse(RoomUserLeftResponse {
room_name: "red".to_string(),
user_name: "alice".to_string(),
}))
}
#[test]
fn roundtrip_user_info() {
roundtrip(ServerResponse::UserInfoResponse(UserInfoResponse {
user_name: "alice".to_string(),
average_speed: 1000,
num_downloads: 1001,
num_files: 1002,
num_folders: 1003,
}))
}
#[test]
fn roundtrip_user_status() {
roundtrip(ServerResponse::UserStatusResponse(UserStatusResponse {
user_name: "alice".to_string(),
status: UserStatus::Offline,
is_privileged: true,
}))
}
#[test]
fn roundtrip_wishlist_interval() {
roundtrip(ServerResponse::WishlistIntervalResponse(
WishlistIntervalResponse { seconds: 1337 },
))
}
}