|
|
@ -1,10 +1,9 @@ |
|
|
use std::collections;
|
|
|
|
|
|
use std::error;
|
|
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
use std::collections::{HashMap, HashSet};
|
|
|
use std::mem;
|
|
|
use std::mem;
|
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use solstice_proto::{server, User};
|
|
|
use solstice_proto::{server, User};
|
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
/// This enumeration is the list of possible membership states for a chat room.
|
|
|
/// This enumeration is the list of possible membership states for a chat room.
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
@ -57,9 +56,9 @@ pub struct Room { |
|
|
/// The name of the room's owner, if any.
|
|
|
/// The name of the room's owner, if any.
|
|
|
pub owner: Option<String>,
|
|
|
pub owner: Option<String>,
|
|
|
/// The names of the room's operators.
|
|
|
/// The names of the room's operators.
|
|
|
pub operators: collections::HashSet<String>,
|
|
|
|
|
|
|
|
|
pub operators: HashSet<String>,
|
|
|
/// The names of the room's members.
|
|
|
/// The names of the room's members.
|
|
|
pub members: collections::HashSet<String>,
|
|
|
|
|
|
|
|
|
pub members: HashSet<String>,
|
|
|
/// The messages sent to this chat room, in chronological order.
|
|
|
/// The messages sent to this chat room, in chronological order.
|
|
|
pub messages: Vec<Message>,
|
|
|
pub messages: Vec<Message>,
|
|
|
/// The tickers displayed in this room.
|
|
|
/// The tickers displayed in this room.
|
|
|
@ -75,8 +74,8 @@ impl Room { |
|
|
operated: false,
|
|
|
operated: false,
|
|
|
user_count: user_count,
|
|
|
user_count: user_count,
|
|
|
owner: None,
|
|
|
owner: None,
|
|
|
operators: collections::HashSet::new(),
|
|
|
|
|
|
members: collections::HashSet::new(),
|
|
|
|
|
|
|
|
|
operators: HashSet::new(),
|
|
|
|
|
|
members: HashSet::new(),
|
|
|
messages: Vec::new(),
|
|
|
messages: Vec::new(),
|
|
|
tickers: Vec::new(),
|
|
|
tickers: Vec::new(),
|
|
|
}
|
|
|
}
|
|
|
@ -84,37 +83,13 @@ impl Room { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// The error returned by RoomMap functions.
|
|
|
/// The error returned by RoomMap functions.
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
pub enum Error {
|
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
|
|
pub enum RoomError {
|
|
|
|
|
|
#[error("room {0} not found")]
|
|
|
RoomNotFound(String),
|
|
|
RoomNotFound(String),
|
|
|
MembershipChangeInvalid(Membership, Membership),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Error {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
|
match *self {
|
|
|
|
|
|
Error::RoomNotFound(ref room_name) => {
|
|
|
|
|
|
write!(f, "room {:?} not found", room_name)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Error::MembershipChangeInvalid(old_membership, new_membership) => {
|
|
|
|
|
|
write!(
|
|
|
|
|
|
f,
|
|
|
|
|
|
"cannot change membership from {:?} to {:?}",
|
|
|
|
|
|
old_membership, new_membership
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl error::Error for Error {
|
|
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
|
|
match *self {
|
|
|
|
|
|
Error::RoomNotFound(_) => "room not found",
|
|
|
|
|
|
Error::MembershipChangeInvalid(_, _) => "cannot change membership",
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
#[error("cannot change membership from {0:?} to {1:?}")]
|
|
|
|
|
|
MembershipChangeInvalid(Membership, Membership),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// Contains the mapping from room names to room data and provides a clean
|
|
|
/// Contains the mapping from room names to room data and provides a clean
|
|
|
@ -122,7 +97,7 @@ impl error::Error for Error { |
|
|
#[derive(Debug, Default)]
|
|
|
#[derive(Debug, Default)]
|
|
|
pub struct RoomMap {
|
|
|
pub struct RoomMap {
|
|
|
/// The actual map from room names to room data.
|
|
|
/// The actual map from room names to room data.
|
|
|
map: collections::HashMap<String, Room>,
|
|
|
|
|
|
|
|
|
map: HashMap<String, Room>,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl RoomMap {
|
|
|
impl RoomMap {
|
|
|
@ -141,19 +116,22 @@ impl RoomMap { |
|
|
/// Looks up the given room name in the map, returning an immutable
|
|
|
/// Looks up the given room name in the map, returning an immutable
|
|
|
/// reference to the associated data if found, or an error if not found.
|
|
|
/// reference to the associated data if found, or an error if not found.
|
|
|
#[cfg(test)]
|
|
|
#[cfg(test)]
|
|
|
pub fn get_strict(&self, room_name: &str) -> Result<&Room, Error> {
|
|
|
|
|
|
|
|
|
pub fn get_strict(&self, room_name: &str) -> Result<&Room, RoomError> {
|
|
|
match self.map.get(room_name) {
|
|
|
match self.map.get(room_name) {
|
|
|
Some(room) => Ok(room),
|
|
|
Some(room) => Ok(room),
|
|
|
None => Err(Error::RoomNotFound(room_name.to_string())),
|
|
|
|
|
|
|
|
|
None => Err(RoomError::RoomNotFound(room_name.to_string())),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// Looks up the given room name in the map, returning a mutable
|
|
|
/// Looks up the given room name in the map, returning a mutable
|
|
|
/// reference to the associated data if found, or an error if not found.
|
|
|
/// reference to the associated data if found, or an error if not found.
|
|
|
fn get_mut_strict(&mut self, room_name: &str) -> Result<&mut Room, Error> {
|
|
|
|
|
|
|
|
|
fn get_mut_strict(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
room_name: &str,
|
|
|
|
|
|
) -> Result<&mut Room, RoomError> {
|
|
|
match self.map.get_mut(room_name) {
|
|
|
match self.map.get_mut(room_name) {
|
|
|
Some(room) => Ok(room),
|
|
|
Some(room) => Ok(room),
|
|
|
None => Err(Error::RoomNotFound(room_name.to_string())),
|
|
|
|
|
|
|
|
|
None => Err(RoomError::RoomNotFound(room_name.to_string())),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -164,7 +142,7 @@ impl RoomMap { |
|
|
name: String,
|
|
|
name: String,
|
|
|
visibility: Visibility,
|
|
|
visibility: Visibility,
|
|
|
user_count: u32,
|
|
|
user_count: u32,
|
|
|
old_map: &mut collections::HashMap<String, Room>,
|
|
|
|
|
|
|
|
|
old_map: &mut HashMap<String, Room>,
|
|
|
) {
|
|
|
) {
|
|
|
let room = match old_map.remove(&name) {
|
|
|
let room = match old_map.remove(&name) {
|
|
|
None => Room::new(Visibility::Public, user_count as usize),
|
|
|
None => Room::new(Visibility::Public, user_count as usize),
|
|
|
@ -183,7 +161,7 @@ impl RoomMap { |
|
|
/// server response.
|
|
|
/// server response.
|
|
|
pub fn set_room_list(&mut self, mut response: server::RoomListResponse) {
|
|
|
pub fn set_room_list(&mut self, mut response: server::RoomListResponse) {
|
|
|
// Replace the old mapping with an empty one.
|
|
|
// Replace the old mapping with an empty one.
|
|
|
let mut old_map = mem::replace(&mut self.map, collections::HashMap::new());
|
|
|
|
|
|
|
|
|
let mut old_map = mem::replace(&mut self.map, HashMap::new());
|
|
|
|
|
|
|
|
|
// Add all public rooms.
|
|
|
// Add all public rooms.
|
|
|
for (name, user_count) in response.rooms.drain(..) {
|
|
|
for (name, user_count) in response.rooms.drain(..) {
|
|
|
@ -221,7 +199,7 @@ impl RoomMap { |
|
|
/// Records that we are now trying to join the given room.
|
|
|
/// Records that we are now trying to join the given room.
|
|
|
/// If the room is not found, or if its membership is not `NonMember`,
|
|
|
/// If the room is not found, or if its membership is not `NonMember`,
|
|
|
/// returns an error.
|
|
|
/// returns an error.
|
|
|
pub fn start_joining(&mut self, room_name: &str) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
pub fn start_joining(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
match room.membership {
|
|
|
@ -230,7 +208,7 @@ impl RoomMap { |
|
|
Ok(())
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
membership => Err(Error::MembershipChangeInvalid(
|
|
|
|
|
|
|
|
|
membership => Err(RoomError::MembershipChangeInvalid(
|
|
|
membership,
|
|
|
membership,
|
|
|
Membership::Joining,
|
|
|
Membership::Joining,
|
|
|
)),
|
|
|
)),
|
|
|
@ -245,7 +223,7 @@ impl RoomMap { |
|
|
owner: Option<String>,
|
|
|
owner: Option<String>,
|
|
|
mut operators: Vec<String>,
|
|
|
mut operators: Vec<String>,
|
|
|
members: &[User],
|
|
|
members: &[User],
|
|
|
) -> Result<&Room, Error> {
|
|
|
|
|
|
|
|
|
) -> Result<&Room, RoomError> {
|
|
|
// First look up the room struct.
|
|
|
// First look up the room struct.
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
|
@ -280,7 +258,7 @@ impl RoomMap { |
|
|
/// Records that we are now trying to leave the given room.
|
|
|
/// 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`,
|
|
|
/// If the room is not found, or if its membership status is not `Member`,
|
|
|
/// returns an error.
|
|
|
/// returns an error.
|
|
|
pub fn start_leaving(&mut self, room_name: &str) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
pub fn start_leaving(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
match room.membership {
|
|
|
@ -289,7 +267,7 @@ impl RoomMap { |
|
|
Ok(())
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
membership => Err(Error::MembershipChangeInvalid(
|
|
|
|
|
|
|
|
|
membership => Err(RoomError::MembershipChangeInvalid(
|
|
|
membership,
|
|
|
membership,
|
|
|
Membership::Leaving,
|
|
|
Membership::Leaving,
|
|
|
)),
|
|
|
)),
|
|
|
@ -297,7 +275,7 @@ impl RoomMap { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// Records that we have now left the given room.
|
|
|
/// Records that we have now left the given room.
|
|
|
pub fn leave(&mut self, room_name: &str) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
pub fn leave(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
match room.membership {
|
|
|
@ -318,7 +296,7 @@ impl RoomMap { |
|
|
&mut self,
|
|
|
&mut self,
|
|
|
room_name: &str,
|
|
|
room_name: &str,
|
|
|
message: Message,
|
|
|
message: Message,
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
room.messages.push(message);
|
|
|
room.messages.push(message);
|
|
|
Ok(())
|
|
|
Ok(())
|
|
|
@ -330,7 +308,7 @@ impl RoomMap { |
|
|
&mut self,
|
|
|
&mut self,
|
|
|
room_name: &str,
|
|
|
room_name: &str,
|
|
|
user_name: String,
|
|
|
user_name: String,
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
room.members.insert(user_name);
|
|
|
room.members.insert(user_name);
|
|
|
Ok(())
|
|
|
Ok(())
|
|
|
@ -342,7 +320,7 @@ impl RoomMap { |
|
|
&mut self,
|
|
|
&mut self,
|
|
|
room_name: &str,
|
|
|
room_name: &str,
|
|
|
user_name: &str,
|
|
|
user_name: &str,
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
room.members.remove(user_name);
|
|
|
room.members.remove(user_name);
|
|
|
Ok(())
|
|
|
Ok(())
|
|
|
@ -356,7 +334,7 @@ impl RoomMap { |
|
|
&mut self,
|
|
|
&mut self,
|
|
|
room_name: &str,
|
|
|
room_name: &str,
|
|
|
tickers: Vec<(String, String)>,
|
|
|
tickers: Vec<(String, String)>,
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
room.tickers = tickers;
|
|
|
room.tickers = tickers;
|
|
|
Ok(())
|
|
|
Ok(())
|
|
|
|