|
|
|
@ -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<String>,
|
|
|
|
mut operators: Vec<String>,
|
|
|
|
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<RoomState> {
|
|
|
|
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<String>,
|
|
|
|
mut operators: Vec<String>,
|
|
|
|
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::<HashSet<String>>(),
|
|
|
|
user_count: 2,
|
|
|
|
members: users
|
|
|
|
.iter()
|
|
|
|
.map(|user| user.name.clone())
|
|
|
|
.collect::<HashSet<String>>(),
|
|
|
|
..RoomState::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_new_is_empty() {
|
|
|
|
assert_eq!(RoomMap::new().get_room_list(), vec![]);
|
|
|
|
|