diff --git a/src/client.rs b/src/client.rs index e7e0bf0..3671d41 100644 --- a/src/client.rs +++ b/src/client.rs @@ -32,7 +32,7 @@ pub struct Client { login_status: LoginStatus, - rooms: collections::HashMap, + rooms: room::RoomMap, privileged_users: collections::HashSet, } @@ -54,7 +54,7 @@ impl Client { login_status: LoginStatus::Pending, - rooms: collections::HashMap::new(), + rooms: room::RoomMap::new(), privileged_users: collections::HashSet::new(), } } @@ -67,7 +67,7 @@ impl Client { config::VER_MAJOR, config::VER_MINOR, ).unwrap()); - self.proto_tx.send(Request::ServerRequest(server_request)).unwrap(); + self.server_send(server_request); loop { match self.recv() { @@ -97,6 +97,19 @@ impl Client { } } + /// Send a request to the server. + fn server_send(&self, request: ServerRequest) { + self.proto_tx.send(Request::ServerRequest(request)).unwrap(); + } + + /// Send a response to the controller client. + fn control_send(&self, response: control::Response) { + if !self.controller_connected { + return; // Silently drop control packets when no-one is listening. + } + self.control_tx.send(response).unwrap(); + } + /*==========================* * CONTROL REQUEST HANDLING * *==========================*/ @@ -132,8 +145,7 @@ impl Client { fn handle_join_room_request(&mut self, room_name: String) { let request = JoinRoomRequest { room_name: room_name }; - self.proto_tx.send(Request::ServerRequest( - ServerRequest::JoinRoomRequest(request))); + self.server_send(ServerRequest::JoinRoomRequest(request)); } fn handle_login_status_request(&mut self) { @@ -155,15 +167,16 @@ impl Client { reason: reason.clone(), }, }; - self.control_tx.send(control::Response::LoginStatusResponse(response)); + self.control_send(control::Response::LoginStatusResponse(response)); } fn handle_room_list_request(&mut self) { - let mut response = control::RoomListResponse{ rooms: Vec::new() }; - for (room_name, room) in self.rooms.iter() { - response.rooms.push((room_name.clone(), room.clone())); - } - self.control_tx.send(control::Response::RoomListResponse(response)); + // First send the controller client what we have in memory. + let response = self.rooms.get_room_list_response(); + self.control_send(control::Response::RoomListResponse(response)); + // Then ask the server for an updated version, which will be forwarded + // to the controller client once received. + self.server_send(ServerRequest::RoomListRequest); } /*==========================* @@ -220,43 +233,8 @@ impl Client { } } - fn handle_room_list_response( - &mut self, mut response: RoomListResponse) - { - self.rooms.clear(); - for (name, user_count) in response.rooms.drain(..) { - self.rooms.insert(name, room::Room { - visibility: room::Visibility::Public, - operated: false, - user_count: user_count as usize, - }); - } - for (name, user_count) in response.owned_private_rooms.drain(..) { - let room = room::Room { - visibility: room::Visibility::PrivateOwned, - operated: false, - user_count: user_count as usize, - }; - if let Some(_) = self.rooms.insert(name, room) { - error!("Room is both public and owned_private"); - } - } - for (name, user_count) in response.other_private_rooms.drain(..) { - let room = room::Room { - visibility: room::Visibility::PrivateOther, - operated: false, - user_count: user_count as usize, - }; - if let Some(_) = self.rooms.insert(name, room) { - error!("Room is both public and other_private"); - } - } - for name in response.operated_private_room_names.drain(..) { - match self.rooms.get_mut(&name) { - None => error!("Room {} is operated but does not exist", name), - Some(room) => room.operated = true, - } - } + fn handle_room_list_response(&mut self, response: RoomListResponse) { + self.rooms.update(response); } fn handle_privileged_users_response( diff --git a/src/control/controller.rs b/src/control/controller.rs index aa7783c..7c124e2 100644 --- a/src/control/controller.rs +++ b/src/control/controller.rs @@ -8,7 +8,6 @@ use rustc_serialize::json; use websocket; use websocket::{Receiver, Sender}; -use client; use config; use super::request::*; diff --git a/src/proto/server/request.rs b/src/proto/server/request.rs index 1cf25be..60d68f5 100644 --- a/src/proto/server/request.rs +++ b/src/proto/server/request.rs @@ -19,7 +19,7 @@ pub enum ServerRequest { JoinRoomRequest(JoinRoomRequest), LoginRequest(LoginRequest), PeerAddressRequest(PeerAddressRequest), - RoomListRequest(RoomListRequest), + RoomListRequest, SetListenPortRequest(SetListenPortRequest), } @@ -35,8 +35,8 @@ impl ServerRequest { ServerRequest::PeerAddressRequest(ref request) => (Packet::new(CODE_PEER_ADDRESS), request), - ServerRequest::RoomListRequest(ref request) => - (Packet::new(CODE_ROOM_LIST), request), + ServerRequest::RoomListRequest => + return Ok(Packet::new(CODE_ROOM_LIST)), ServerRequest::SetListenPortRequest(ref request) => (Packet::new(CODE_SET_LISTEN_PORT), request), @@ -135,25 +135,6 @@ impl WriteToPacket for PeerAddressRequest { } } -/*===========* - * ROOM LIST * - *===========*/ - -#[derive(Debug)] -pub struct RoomListRequest; - -impl RoomListRequest { - pub fn new() -> Self { - RoomListRequest - } -} - -impl WriteToPacket for RoomListRequest { - fn write_to_packet(&self, _: &mut Packet) -> io::Result<()> { - Ok(()) - } -} - /*=================* * SET LISTEN PORT * *=================*/ diff --git a/src/room.rs b/src/room.rs index 4e69d12..b9531fb 100644 --- a/src/room.rs +++ b/src/room.rs @@ -1,3 +1,8 @@ +use std::collections; + +use control; +use proto::server; + /// This enumeration is the list of visibility types for rooms that the user is /// a member of. #[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)] @@ -23,3 +28,76 @@ pub struct Room { /// The number of users that are members of the room. pub user_count: usize, } + +#[derive(Debug)] +pub struct RoomMap { + map: collections::HashMap, +} + +impl RoomMap { + pub fn new() -> Self { + RoomMap { + map: collections::HashMap::new() + } + } + + pub fn get(&self, name: &str) -> Option<&Room> { + self.map.get(name) + } + + pub fn update(&mut self, mut response: server::RoomListResponse) { + // First, clear the current map, keeping backing memory. + self.map.clear(); + + // Add all public rooms. + for (name, user_count) in response.rooms.drain(..) { + self.map.insert(name, Room { + visibility: Visibility::Public, + operated: false, + user_count: user_count as usize, + }); + } + + // Add all private, owned, rooms. + for (name, user_count) in response.owned_private_rooms.drain(..) { + let room = Room { + visibility: Visibility::PrivateOwned, + operated: false, + user_count: user_count as usize, + }; + if let Some(_) = self.map.insert(name, room) { + error!("Room is both public and owned_private"); + } + } + + // Add all private, unowned, rooms. + for (name, user_count) in response.other_private_rooms.drain(..) { + let room = Room { + visibility: Visibility::PrivateOther, + operated: false, + user_count: user_count as usize, + }; + if let Some(_) = self.map.insert(name, room) { + error!("Room is both public and other_private"); + } + } + + // Mark all operated rooms as necessary. + for name in response.operated_private_room_names.drain(..) { + match self.map.get_mut(&name) { + None => error!("Room {} is operated but does not exist", name), + Some(room) => room.operated = true, + } + } + } + + pub fn get_room_list_response(&self) + -> control::RoomListResponse + { + let mut response = control::RoomListResponse{ rooms: Vec::new() }; + for (room_name, room) in self.map.iter() { + response.rooms.push((room_name.clone(), room.clone())); + } + response + } +}