use crate::{
jid::BareJid,
muc::{private_message::RoomPrivateMessageSettings, room::RoomMessageSettings},
parsers::{disco::DiscoInfoResult, occupant_id::OccupantId},
RoomNick,
};
use alloc::collections::BTreeMap;
#[derive(Clone, Debug, Default)]
pub struct RoomManager {
pub rooms: BTreeMap<BareJid, Room>,
}
impl RoomManager {
pub fn get(&self, room: &BareJid) -> Option<Room> {
self.rooms.get(room).cloned()
}
pub fn get_nick(&self, room: &BareJid) -> Option<RoomNick> {
if let Some(room) = self.get(room) {
match room.status {
RoomStatus::Joined | RoomStatus::Joining => Some(room.nick.clone()),
_ => None,
}
} else {
None
}
}
pub fn get_nick_unchecked(&self, room: &BareJid) -> RoomNick {
self.get(room).unwrap().nick.clone()
}
pub fn set_room_joining(&mut self, room: &BareJid, requested_nick: &RoomNick) {
if let Some(entry) = self.rooms.get_mut(room) {
match entry.status {
RoomStatus::Joining | RoomStatus::Joined => {
warn!("Trying to set room joining which is already joining/joined: {room}");
}
_ => entry.status = RoomStatus::Joining,
}
} else {
self.rooms.insert(
room.to_owned(),
Room {
status: RoomStatus::Joining,
jid: room.to_owned(),
nick: requested_nick.to_owned(),
info: None,
members: BTreeMap::new(),
},
);
}
}
pub fn set_room_joined(&mut self, room: &BareJid, nick: &RoomNick) {
if let Some(entry) = self.rooms.get_mut(room) {
match entry.status {
RoomStatus::Joining => {
entry.status = RoomStatus::Joined;
entry.nick = nick.to_owned();
return;
}
RoomStatus::Joined => {
warn!("Trying to set room joined which is already joined: {room}");
return;
}
_ => {
error!("Trying to set room joined which is leaving/left: {room}");
}
}
} else {
error!("Trying to set room joined which is unknown: {room}");
}
unreachable!("Your client tried to set a room joined which was not joining. This is probably a logic bug!");
}
pub fn set_room_leaving(&mut self, room: &BareJid) {
if let Some(entry) = self.rooms.get_mut(room) {
match entry.status {
RoomStatus::Joining | RoomStatus::Joined => {
entry.status = RoomStatus::Leaving;
return;
}
RoomStatus::Leaving => {
warn!("Trying to set room leaving which is already leaving: {room}");
return;
}
_ => {
error!("Trying to set room joined which is leaving/left: {room}");
}
}
} else {
error!("Trying to set room joined which is unknown: {room}");
}
unreachable!("Your client tried to set a room leaving which was not joining/joined/leaving. This is probably a logic bug!");
}
pub fn set_room_left(&mut self, room: &BareJid) {
if let Some(entry) = self.rooms.get_mut(room) {
match entry.status {
RoomStatus::Leaving => {
entry.status = RoomStatus::None;
return;
}
RoomStatus::None => {
warn!("Trying to set room left which is already left: {room}");
return;
}
_ => {
error!("Trying to set room left which is joined/joining: {room}");
}
}
} else {
error!("Trying to set room left which is unknown: {room}");
}
unreachable!("Your client tried to set a room left which was not leaving/left. This is probably a logic bug!");
}
pub fn is_joined(&self, room: &BareJid) -> bool {
self.get(room)
.map(|r| r.status == RoomStatus::Joined)
.unwrap_or(false)
}
pub fn is_joining(&self, room: &BareJid) -> bool {
self.get(room)
.map(|r| r.status == RoomStatus::Joining)
.unwrap_or(false)
}
pub fn is_leaving(&self, room: &BareJid) -> bool {
self.get(room)
.map(|r| r.status == RoomStatus::Leaving)
.unwrap_or(false)
}
pub fn rooms_joined<'a>(&'a self) -> Vec<&'a Room> {
self.rooms
.iter()
.filter_map(|(_barejid, room)| {
if room.status == RoomStatus::Joined {
Some(room)
} else {
None
}
})
.collect()
}
}
#[derive(Clone, Debug)]
pub struct Room {
pub status: RoomStatus,
pub jid: BareJid,
pub nick: RoomNick,
pub info: Option<DiscoInfoResult>,
pub members: BTreeMap<OccupantId, RoomMember>,
}
impl Room {
pub fn message<'a>(&self, message: &'a str) -> RoomMessageSettings<'a> {
RoomMessageSettings::new(self.jid.clone(), message)
}
pub fn member<'a>(&'a self, id: &OccupantId) -> Option<&'a RoomMember> {
self.members.get(id)
}
}
#[derive(Clone, Debug)]
pub struct RoomMember {
pub room: BareJid,
pub nick: RoomNick,
pub occupant_id: OccupantId,
}
impl RoomMember {
pub fn nick(&self) -> &RoomNick {
&self.nick
}
pub fn nick_str(&self) -> &str {
self.nick.as_str()
}
pub fn message<'a>(&self, message: &'a str) -> RoomPrivateMessageSettings<'a> {
RoomPrivateMessageSettings::new(self.room.clone(), self.nick.clone(), message)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum RoomStatus {
Joining,
Joined,
Leaving,
None,
}