diff --git a/src/client.rs b/src/client.rs index 0c650ed..62e15c3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -288,6 +288,9 @@ impl Client { ServerResponse::UserJoinedRoomResponse(response) => self.handle_user_joined_room_response(response), + ServerResponse::UserStatusResponse(response) => + self.handle_user_status_response(response), + ServerResponse::UnknownResponse(code) => warn!("Unknown response: code {}", code), @@ -423,4 +426,15 @@ impl Client { ); } } + + fn handle_user_status_response(&mut self, response: UserStatusResponse) { + self.users.set_status(&response.user_name, response.status) + .unwrap_or_else(|err| error!("UserStatusResponse: {}", err)); + + if response.is_privileged { + self.users.insert_privileged(response.user_name); + } else { + self.users.remove_privileged(&response.user_name); + } + } } diff --git a/src/proto/server/constants.rs b/src/proto/server/constants.rs index a64534c..9239fd5 100644 --- a/src/proto/server/constants.rs +++ b/src/proto/server/constants.rs @@ -1,6 +1,7 @@ pub const CODE_LOGIN: u32 = 1; pub const CODE_SET_LISTEN_PORT: u32 = 2; pub const CODE_PEER_ADDRESS: u32 = 3; +pub const CODE_USER_STATUS: u32 = 7; pub const CODE_ROOM_MESSAGE: u32 = 13; pub const CODE_ROOM_JOIN: u32 = 14; pub const CODE_ROOM_LEAVE: u32 = 15; diff --git a/src/proto/server/request.rs b/src/proto/server/request.rs index af07394..a65c34f 100644 --- a/src/proto/server/request.rs +++ b/src/proto/server/request.rs @@ -23,6 +23,7 @@ pub enum ServerRequest { RoomListRequest, RoomMessageRequest(RoomMessageRequest), SetListenPortRequest(SetListenPortRequest), + UserStatusRequest(UserStatusRequest), } impl ServerRequest { @@ -48,6 +49,9 @@ impl ServerRequest { ServerRequest::SetListenPortRequest(ref request) => (Packet::new(CODE_SET_LISTEN_PORT), request), + + ServerRequest::UserStatusRequest(ref request) => + (Packet::new(CODE_USER_STATUS), request), }; try!(request.write_to_packet(&mut packet)); Ok(packet) @@ -201,3 +205,18 @@ impl WriteToPacket for SetListenPortRequest { } } +/*=============* + * USER STATUS * + *=============*/ + +#[derive(Debug)] +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)); + Ok(()) + } +} diff --git a/src/proto/server/response.rs b/src/proto/server/response.rs index ed34d01..9103eca 100644 --- a/src/proto/server/response.rs +++ b/src/proto/server/response.rs @@ -29,6 +29,7 @@ pub enum ServerResponse { RoomListResponse(RoomListResponse), RoomMessageResponse(RoomMessageResponse), UserJoinedRoomResponse(UserJoinedRoomResponse), + UserStatusResponse(UserStatusResponse), WishlistIntervalResponse(WishlistIntervalResponse), // Unknown purpose @@ -87,6 +88,11 @@ impl FromPacket for ServerResponse { try!(UserJoinedRoomResponse::from_packet(packet)) ), + CODE_USER_STATUS => + ServerResponse::UserStatusResponse( + try!(UserStatusResponse::from_packet(packet)) + ), + CODE_WISHLIST_INTERVAL => ServerResponse::WishlistIntervalResponse( try!(WishlistIntervalResponse::from_packet(packet)) @@ -545,6 +551,31 @@ impl FromPacket for UserJoinedRoomResponse { } } +/*=============* + * USER STATUS * + *=============*/ + +#[derive(Debug)] +pub struct UserStatusResponse { + pub user_name: String, + pub status: user::Status, + pub is_privileged: bool, +} + +impl FromPacket for UserStatusResponse { + fn from_packet(packet: &mut Packet) -> result::Result { + let user_name = try!(packet.read_str()); + let status_u32 = try!(packet.read_uint()); + let status = try!(user::Status::from_u32(status_u32)); + let is_privileged = try!(packet.read_bool()); + Ok(UserStatusResponse { + user_name: user_name, + status: status, + is_privileged: is_privileged, + }) + } +} + /*===================* * WISHLIST INTERVAL * *===================*/ diff --git a/src/user.rs b/src/user.rs index d6bc398..3c7d2ab 100644 --- a/src/user.rs +++ b/src/user.rs @@ -1,4 +1,6 @@ use std::collections; +use std::error; +use std::fmt; use result; @@ -59,6 +61,25 @@ pub struct User { pub country: String, } +/// The error returned when a user name was not found in the user map. +#[derive(Debug)] +pub struct UserNotFoundError { + /// The name of the user that wasn't found. + user_name: String, +} + +impl fmt::Display for UserNotFoundError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "user \"{}\" not found", self.user_name) + } +} + +impl error::Error for UserNotFoundError { + fn description(&self) -> &str { + "user not found" + } +} + /// Contains the mapping from user names to user data and provides a clean /// interface to interact with it. #[derive(Debug)] @@ -80,32 +101,51 @@ impl UserMap { /// Looks up the given user name in the map, returning an immutable /// reference to the associated data if found. - pub fn get(&self, name: &str) -> Option<&User> { - self.map.get(name) + pub fn get(&self, user_name: &str) -> Option<&User> { + self.map.get(user_name) } /// Inserts the given user info for the given user name in the mapping. /// If there is already data under that name, it is replaced. - pub fn insert(&mut self, name: String, user: User) { - self.map.insert(name, user); + pub fn insert(&mut self, user_name: String, user: User) { + self.map.insert(user_name, user); + } + + /// Sets the given user's status to the given value, if such a user exists. + pub fn set_status(&mut self, user_name: &str, status: Status) + -> Result<(), UserNotFoundError> + { + if let Some(user) = self.map.get_mut(user_name) { + user.status = status; + Ok(()) + } else { + Err(UserNotFoundError { + user_name: user_name.to_string(), + }) + } } /// Sets the set of privileged users to the given list. pub fn set_all_privileged(&mut self, mut users: Vec) { self.privileged.clear(); - for name in users.drain(..) { - self.privileged.insert(name); + for user_name in users.drain(..) { + self.privileged.insert(user_name); } } /// Marks the given user as privileged. - pub fn add_privileged(&mut self, name: String) { - self.privileged.insert(name); + pub fn insert_privileged(&mut self, user_name: String) { + self.privileged.insert(user_name); + } + + /// Marks the given user as not privileged. + pub fn remove_privileged(&mut self, user_name: &str) { + self.privileged.remove(user_name); } /// Checks if the given user is privileged. - pub fn is_privileged(&self, name: &str) -> bool { - self.privileged.contains(name) + pub fn is_privileged(&self, user_name: &str) -> bool { + self.privileged.contains(user_name) } }