From 30044af1c6c78a2eb16e8786fabd9c7744492478 Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Wed, 30 Nov 2022 22:07:34 +0000 Subject: [PATCH] Move join() from RoomMap to RoomEntry. --- client/src/client.rs | 11 +- .../handlers/room_join_response_handler.rs | 17 +-- client/src/room/map.rs | 139 +++++++++++------- proto/src/core/user.rs | 8 +- 4 files changed, 101 insertions(+), 74 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 705f48c..020e09e 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -547,14 +547,7 @@ impl Client { mut response: server::RoomJoinResponse, ) { // Join the room and store the received information. - let result = self.rooms.join( - &response.room_name, - response.owner, - response.operators, - &response.users, - ); - - let room = match result { + let room = match self.rooms.get_mut_strict(&response.room_name) { Ok(room) => room, Err(err) => { error!("RoomJoinResponse: {}", err); @@ -562,6 +555,8 @@ impl Client { } }; + room.join(response.owner, response.operators, &response.users); + // Then update the user structs based on the info we just got. for user in response.users.drain(..) { self.users.insert(user); diff --git a/client/src/handlers/room_join_response_handler.rs b/client/src/handlers/room_join_response_handler.rs index 3e23dfa..15756c6 100644 --- a/client/src/handlers/room_join_response_handler.rs +++ b/client/src/handlers/room_join_response_handler.rs @@ -17,16 +17,13 @@ impl MessageHandler for RoomJoinResponseHandler { response: &RoomJoinResponse, ) -> anyhow::Result<()> { { - let room = context - .state - .rooms - .join( - &response.room_name, - response.owner.clone(), - response.operators.clone(), - &response.users, - ) - .context("joining room")?; + let room = context.state.rooms.get_mut_strict(&response.room_name)?; + + room.join( + response.owner.clone(), + response.operators.clone(), + &response.users, + ); // Send under lock to avoid out-of-order sends. let control_response = diff --git a/client/src/room/map.rs b/client/src/room/map.rs index 45536fd..d4fd755 100644 --- a/client/src/room/map.rs +++ b/client/src/room/map.rs @@ -28,13 +28,14 @@ pub struct RoomNotFoundError(String); /// An entry in the chat room map. #[derive(Debug)] pub struct RoomEntry { + name: String, state: RoomState, } impl RoomEntry { /// Creates a new entry with the given state. - pub fn new(state: RoomState) -> Self { - Self { state } + pub fn new(name: String, state: RoomState) -> Self { + Self { name, state } } /// Returns a copy of the room state contained in this entry. @@ -42,14 +43,17 @@ impl RoomEntry { self.state.clone() } + pub fn into_state(self) -> RoomState { + self.state + } + /// Inserts the given message in this chat room's history. pub fn insert_message(&mut self, message: RoomMessage) { self.state.messages.insert(message) } - /// Records that we are now trying to join the given room. - /// If the room is not found, or if its membership is not `NonMember`, - /// returns an error. + /// Records that we are now trying to join this room. + /// Returns an error if its membership is not `NonMember`, pub fn start_joining(&mut self) -> Result<(), RoomMembershipChangeError> { match self.state.membership { RoomMembership::NonMember => { @@ -63,6 +67,31 @@ impl RoomEntry { )), } } + + /// Records that we are now a member of this room and updates its state. + pub fn join( + &mut self, + owner: Option, + mut operators: Vec, + members: &[User], + ) { + // Log what's happening. + if let RoomMembership::Joining = self.state.membership { + info!("Joined room {:?}", self.name); + } else { + warn!( + "Joined room {:?} but membership was already {:?}", + self.name, self.state.membership + ); + } + + // Update the room state. + self.state.membership = RoomMembership::Member; + self.state.user_count = members.len(); + self.state.owner = owner; + self.state.operators = operators.drain(..).collect(); + self.state.members = members.iter().map(|user| user.name.clone()).collect(); + } } /// Contains the mapping from room names to room data and provides a clean @@ -84,7 +113,7 @@ impl RoomMap { pub fn insert(&mut self, name: String, room: RoomState) -> Option { self .map - .insert(name, RoomEntry::new(room)) + .insert(name.clone(), RoomEntry::new(name, room)) .map(|entry| entry.state) } @@ -123,10 +152,10 @@ impl RoomMap { ) { let room = match old_map.remove(&name) { None => RoomState::new(RoomVisibility::Public, user_count as usize), - Some(RoomEntry { mut state }) => { - state.visibility = visibility; - state.user_count = user_count as usize; - state + Some(mut entry) => { + entry.state.visibility = visibility; + entry.state.user_count = user_count as usize; + entry.state } }; if let Some(_) = self.insert(name, room) { @@ -183,46 +212,6 @@ impl RoomMap { rooms } - /// Records that we are now a member of the given room and updates the room - /// information. - pub fn join( - &mut self, - room_name: &str, - owner: Option, - mut operators: Vec, - members: &[User], - ) -> Result<&RoomEntry, RoomError> { - // First look up the room struct. - let room = self.get_mut_strict(room_name)?; - - // Log what's happening. - if let RoomMembership::Joining = room.state.membership { - info!("Joined room {:?}", room_name); - } else { - warn!( - "Joined room {:?} but membership was already {:?}", - room_name, room.state.membership - ); - } - - // Update the room state. - room.state.membership = RoomMembership::Member; - room.state.user_count = members.len(); - room.state.owner = owner; - - room.state.operators.clear(); - for user_name in operators.drain(..) { - room.state.operators.insert(user_name); - } - - room.state.members.clear(); - for user in members { - room.state.members.insert(user.name.clone()); - } - - Ok(room) - } - #[allow(dead_code)] /// Records that we are now trying to leave the given room. /// If the room is not found, or if its membership status is not `Member`, @@ -300,6 +289,8 @@ impl RoomMap { #[cfg(test)] mod tests { + use std::collections::HashSet; + use solstice_proto::server::RoomListResponse; use crate::room::{RoomMembership, RoomState, RoomVisibility}; @@ -308,10 +299,13 @@ mod tests { #[test] fn entry_start_joining_error() { - let mut room = RoomEntry::new(RoomState { - membership: RoomMembership::Member, - ..RoomState::default() - }); + let mut room = RoomEntry::new( + "bleep".to_string(), + RoomState { + membership: RoomMembership::Member, + ..RoomState::default() + }, + ); room.start_joining().unwrap_err(); @@ -320,13 +314,48 @@ mod tests { #[test] fn entry_start_joining_success() { - let mut room = RoomEntry::new(RoomState::default()); + let mut room = RoomEntry::new("bleep".to_string(), RoomState::default()); room.start_joining().unwrap(); assert_eq!(room.clone_state().membership, RoomMembership::Joining); } + #[test] + fn entry_join() { + let mut room = RoomEntry::new("bleep".to_string(), RoomState::default()); + + let owner = Some("owner".to_string()); + let mut operators = vec!["operator1".to_string(), "operator2".to_string()]; + let users = [ + User { + name: "shruti".to_string(), + ..User::default() + }, + User { + name: "kim".to_string(), + ..User::default() + }, + ]; + + room.join(owner.clone(), operators.clone(), &users); + + assert_eq!( + room.into_state(), + RoomState { + membership: RoomMembership::Member, + owner: owner, + operators: operators.drain(..).collect::>(), + user_count: 2, + members: users + .iter() + .map(|user| user.name.clone()) + .collect::>(), + ..RoomState::default() + } + ); + } + #[test] fn map_new_is_empty() { assert_eq!(RoomMap::new().get_room_list(), vec![]); diff --git a/proto/src/core/user.rs b/proto/src/core/user.rs index 498ee2b..74ec3c0 100644 --- a/proto/src/core/user.rs +++ b/proto/src/core/user.rs @@ -22,6 +22,12 @@ pub enum UserStatus { Online, } +impl Default for UserStatus { + fn default() -> Self { + Self::Offline + } +} + impl ValueEncode for UserStatus { fn encode_to( &self, @@ -55,7 +61,7 @@ impl ValueDecode for UserStatus { /// This structure contains the last known information about a fellow user. #[derive( - Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, + Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, )] pub struct User { /// The name of the user.