Use PresenceFull where necessary

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-12-26 15:02:45 +01:00
parent 65c7383745
commit 5239a19871
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
5 changed files with 162 additions and 90 deletions

View file

@ -84,7 +84,7 @@ async fn handle_presence_full_available<C: ComponentTrait>(
debug!("Presence received to existing room: {}", &roomjid);
if let ControlFlow::Break(_) = muc {
// <{muc}x/> was found
match room.add_session(component, *presence.clone()).await {
match room.add_session(component, presence.clone()).await {
Ok(_) => (),
Err(Error::NickAlreadyAssigned(nick)) => {
let error = Presence::new(PresenceType::Error)
@ -103,7 +103,7 @@ async fn handle_presence_full_available<C: ComponentTrait>(
}
} else if let ControlFlow::Continue(_) = muc {
// <{muc}x/> wasn't found
match room.update_presence(component, *presence.clone()).await {
match room.update_presence(component, presence.clone()).await {
Ok(()) => (),
Err(Error::ParticipantNotFound(_)) => {
let error = Presence::new(PresenceType::Unavailable)
@ -131,9 +131,7 @@ async fn handle_presence_full_available<C: ComponentTrait>(
} else {
debug!("Presence received to new room: {}", &roomjid);
let mut room = Room::new(roomjid.clone());
room.add_session(component, *presence.clone())
.await
.unwrap();
room.add_session(component, presence.clone()).await.unwrap();
let _ = rooms.insert(roomjid, room);
}
@ -165,7 +163,7 @@ async fn handle_presence_full_unavailable<C: ComponentTrait>(
)
.into()]);
if let Some(mut room) = rooms.remove(&roomjid) {
match room.remove_session(component, *presence.clone()).await {
match room.remove_session(component, presence.clone()).await {
Ok(()) => (),
Err(Error::NonexistantSession(_)) => {
component.send_stanza(error).await.unwrap();

View file

@ -14,11 +14,12 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use crate::presence::PresenceFull;
use crate::session::{Nick, Session};
use std::iter::IntoIterator;
use xmpp_parsers::{presence::Presence, BareJid, FullJid, Jid};
use xmpp_parsers::{BareJid, FullJid, Jid};
/// An occupant in a room. May contain multiple sessions (Multi-Session Nicks)
#[derive(Debug, Clone, PartialEq)]
@ -32,7 +33,7 @@ pub struct Occupant {
impl Occupant {
/// New occupant
pub fn new(presence: Presence) -> Result<Occupant, Error> {
pub fn new(presence: PresenceFull) -> Result<Occupant, Error> {
let participant = presence.to.clone().map(FullJid::try_from).unwrap().unwrap();
let session = Session::try_from(presence)?;
Ok(Occupant {
@ -50,7 +51,7 @@ impl Occupant {
}
/// Add a new session to the occupant
pub fn add_session(&mut self, presence: Presence) -> Result<(), Error> {
pub fn add_session(&mut self, presence: PresenceFull) -> Result<(), Error> {
let new_session = Session::try_from(presence)?;
if BareJid::from(new_session.real().clone()) != self.real {
return Err(Error::MismatchJids(
@ -70,7 +71,7 @@ impl Occupant {
}
/// Remove a session from the occupant
pub fn remove_session(&mut self, presence: Presence) -> Result<(), Error> {
pub fn remove_session(&mut self, presence: PresenceFull) -> Result<(), Error> {
let own_session = Session::try_from(presence)?;
let len = self.sessions.len();
@ -86,7 +87,7 @@ impl Occupant {
}
/// Update session presence
pub fn update_presence(&mut self, presence: Presence) -> Result<(), Error> {
pub fn update_presence(&mut self, presence: PresenceFull) -> Result<(), Error> {
let own_session = Session::try_from(presence)?;
for (i, session) in self.sessions.iter().enumerate() {
@ -142,38 +143,52 @@ mod tests {
#[tokio::test]
async fn test_occupant_update_presence() {
let presence_louise1 = Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(LOUISE_ROOM1_PART.clone());
let presence_louise2 = Presence::new(PresenceType::None)
.with_from(LOUISE_FULL2.clone())
.with_to(LOUISE_ROOM1_PART.clone());
let presence_louise1 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(LOUISE_ROOM1_PART.clone()),
)
.unwrap();
let presence_louise2 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(LOUISE_FULL2.clone())
.with_to(LOUISE_ROOM1_PART.clone()),
)
.unwrap();
let mut occupant = Occupant::new(presence_louise1).unwrap();
occupant.add_session(presence_louise2).unwrap();
let presence1 = Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(ROOM1_BARE.clone())
.with_show(PresenceShow::Away)
.with_payloads(vec![
Muc::new().into(),
MucUser {
status: Vec::new(),
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
}
.into(),
]);
let presence1 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(LOUISE_ROOM1_PART.clone())
.with_show(PresenceShow::Away)
.with_payloads(vec![
Muc::new().into(),
MucUser {
status: Vec::new(),
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
}
.into(),
]),
)
.unwrap();
match occupant.update_presence(presence1.clone()) {
Ok(()) => (),
err => panic!("Err: {:?}", err),
}
assert_eq!(occupant.sessions[0].presence, presence1);
let presence2 = Presence::new(PresenceType::None)
.with_from(LOUISE_FULL2.clone())
.with_to(ROOM1_BARE.clone())
.with_show(PresenceShow::Xa);
let presence2 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(LOUISE_FULL2.clone())
.with_to(LOUISE_ROOM1_PART.clone())
.with_show(PresenceShow::Xa),
)
.unwrap();
match occupant.update_presence(presence2.clone()) {
Err(Error::SecondarySession(session)) if session.real() == &*LOUISE_FULL2 => (),
@ -187,9 +202,12 @@ mod tests {
Session::try_from(presence2.clone()).unwrap()
);
let presence_leave_louise2 = Presence::new(PresenceType::Unavailable)
.with_from(LOUISE_FULL2.clone())
.with_to(LOUISE_ROOM1_PART.clone());
let presence_leave_louise2 = PresenceFull::try_from(
Presence::new(PresenceType::Unavailable)
.with_from(LOUISE_FULL2.clone())
.with_to(LOUISE_ROOM1_PART.clone()),
)
.unwrap();
occupant.remove_session(presence_leave_louise2).unwrap();
match occupant.update_presence(presence2) {

View file

@ -16,6 +16,7 @@
use crate::component::ComponentTrait;
use crate::error::Error;
use crate::occupant::Occupant;
use crate::presence::PresenceFull;
use crate::session::{Nick, Session};
use std::collections::BTreeMap;
@ -69,7 +70,7 @@ impl Room {
&self,
component: &mut C,
own_occupant: &Occupant,
presence: Presence,
presence: PresenceFull,
mode: BroadcastPresence,
) -> Result<(), Error> {
let leave = matches!(mode, BroadcastPresence::Leave);
@ -243,7 +244,7 @@ impl Room {
pub async fn add_session<C: ComponentTrait>(
&mut self,
component: &mut C,
presence: Presence,
presence: PresenceFull,
) -> Result<(), Error> {
let new_session = Session::try_from(presence)?;
let new_nick = new_session.participant().resource.clone();
@ -310,7 +311,7 @@ impl Room {
pub async fn update_presence<C: ComponentTrait>(
&mut self,
component: &mut C,
presence: Presence,
presence: PresenceFull,
) -> Result<(), Error> {
let session = Session::try_from(presence)?;
@ -334,7 +335,7 @@ impl Room {
pub async fn remove_session<C: ComponentTrait>(
&mut self,
component: &mut C,
presence: Presence,
presence: PresenceFull,
) -> Result<(), Error> {
let session = Session::try_from(presence)?;
// If occupant doesn't exist, ignore.
@ -425,17 +426,26 @@ mod tests {
let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap();
let participant3 = roomjid.clone().with_resource(String::from("nick3"));
let presence1 = Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone());
let presence1 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone()),
)
.unwrap();
let presence2 = Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone());
let presence2 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone()),
)
.unwrap();
let presence3 = Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone());
let presence3 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone()),
)
.unwrap();
let mut room = Room::new(roomjid.clone());
@ -514,17 +524,26 @@ mod tests {
let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap();
let participant3 = roomjid.clone().with_resource(String::from("nick3"));
let presence1 = Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone());
let presence1 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone()),
)
.unwrap();
let presence2 = Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone());
let presence2 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone()),
)
.unwrap();
let presence3 = Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone());
let presence3 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone()),
)
.unwrap();
let mut room = Room::new(roomjid.clone());
@ -586,17 +605,26 @@ mod tests {
let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap();
let participant3 = roomjid.clone().with_resource(String::from("nick3"));
let presence1 = Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone());
let presence1 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid1.clone())
.with_to(participant1.clone()),
)
.unwrap();
let presence2 = Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone());
let presence2 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid2.clone())
.with_to(participant2.clone()),
)
.unwrap();
let presence3 = Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone());
let presence3 = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(realjid3.clone())
.with_to(participant3.clone()),
)
.unwrap();
let mut room = Room::new(roomjid.clone());
@ -689,17 +717,26 @@ mod tests {
#[tokio::test]
async fn test_broadcast_presence_leave() {
let presence_louise = Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(LOUISE_ROOM1_PART.clone());
let presence_louise = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(LOUISE_FULL1.clone())
.with_to(LOUISE_ROOM1_PART.clone()),
)
.unwrap();
let presence_sugako = Presence::new(PresenceType::None)
.with_from(SUGAKO_FULL1.clone())
.with_to(SUGAKO_ROOM1_PART.clone());
let presence_sugako = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(SUGAKO_FULL1.clone())
.with_to(SUGAKO_ROOM1_PART.clone()),
)
.unwrap();
let presence_rosa = Presence::new(PresenceType::None)
.with_from(ROSA_FULL1.clone())
.with_to(ROSA_ROOM1_PART.clone());
let presence_rosa = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_from(ROSA_FULL1.clone())
.with_to(ROSA_ROOM1_PART.clone()),
)
.unwrap();
let mut room = Room::new(ROOM1_BARE.clone());
@ -756,9 +793,12 @@ mod tests {
.into()]),
);
let presence_leave = Presence::new(PresenceType::Unavailable)
.with_from(ROSA_FULL1.clone())
.with_to(ROSA_ROOM1_PART.clone());
let presence_leave = PresenceFull::try_from(
Presence::new(PresenceType::Unavailable)
.with_from(ROSA_FULL1.clone())
.with_to(ROSA_ROOM1_PART.clone()),
)
.unwrap();
room.broadcast_presence(
&mut component,

View file

@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::error::Error;
use crate::presence::PresenceFull;
use xmpp_parsers::{presence::Presence, FullJid, Jid};
@ -22,12 +23,12 @@ pub type Nick = String;
/// An occupant session
#[derive(Debug, Clone)]
pub struct Session {
pub presence: Presence,
pub presence: PresenceFull,
}
impl Session {
/// Ensure presence doesn't contain payloads that would impersonate us
fn filter_presence(presence: Presence) -> Presence {
fn filter_presence(presence: PresenceFull) -> PresenceFull {
presence
}
@ -48,7 +49,16 @@ impl Session {
impl PartialEq for Session {
fn eq(&self, other: &Session) -> bool {
self.real() == other.real() && self.participant() == other.participant()
self.real() == other.real() // && self.participant() == other.participant()
}
}
impl TryFrom<PresenceFull> for Session {
type Error = Error;
fn try_from(presence: PresenceFull) -> Result<Session, Error> {
let presence = Session::filter_presence(presence);
Ok(Session { presence })
}
}
@ -56,7 +66,9 @@ impl TryFrom<Presence> for Session {
type Error = Error;
fn try_from(presence: Presence) -> Result<Session, Error> {
let presence = Session::filter_presence(presence);
Ok(Session { presence })
let presence: PresenceFull = PresenceFull::try_from(presence)?;
Ok(Session {
presence: Session::filter_presence(presence),
})
}
}

View file

@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::occupant::Occupant;
use crate::presence::PresenceFull;
use crate::room::Room;
use crate::session::Nick;
use std::str::FromStr;
@ -79,7 +80,7 @@ pub fn one_participant_room(roomjid: BareJid) -> Room {
.with_to(LOUISE_ROOM1_PART.clone());
room.occupants.insert(
String::from(LOUISE_NICK),
Occupant::new(presence_louise).unwrap(),
Occupant::new(PresenceFull::try_from(presence_louise).unwrap()).unwrap(),
);
room
}
@ -94,11 +95,11 @@ pub fn two_participant_room(roomjid: BareJid) -> Room {
.with_to(SUGAKO_ROOM1_PART.clone());
room.occupants.insert(
String::from(LOUISE_NICK),
Occupant::new(presence_louise).unwrap(),
Occupant::new(PresenceFull::try_from(presence_louise).unwrap()).unwrap(),
);
room.occupants.insert(
String::from(SUGAKO_NICK),
Occupant::new(presence_sugako).unwrap(),
Occupant::new(PresenceFull::try_from(presence_sugako).unwrap()).unwrap(),
);
room
}
@ -111,9 +112,12 @@ pub async fn new_room<N: Into<Nick>>(roomjid: BareJid, sessions: Vec<(FullJid, N
let nick: Nick = nick.into();
let participant = roomjid.clone().with_resource(nick.clone());
let presence = Presence::new(PresenceType::None)
.with_to(participant)
.with_from(session);
let presence = PresenceFull::try_from(
Presence::new(PresenceType::None)
.with_to(participant)
.with_from(session),
)
.unwrap();
match room.occupants.get_mut(&nick) {
Some(occupant) => occupant.add_session(presence).unwrap(),