Broadcast presence updates
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
222e5a1793
commit
d7c4bcd87b
5 changed files with 99 additions and 23 deletions
|
@ -25,6 +25,7 @@ pub enum Error {
|
|||
NickAlreadyAssigned(String),
|
||||
NonexistantSession(FullJid),
|
||||
SessionAlreadyExists(FullJid),
|
||||
ParticipantNotFound(String),
|
||||
Xmpp(Box<TokioXMPPError>),
|
||||
Parser(Box<ParserError>),
|
||||
}
|
||||
|
@ -38,6 +39,7 @@ impl fmt::Display for Error {
|
|||
Error::NickAlreadyAssigned(err) => write!(f, "Nickname already assigned: {}", err),
|
||||
Error::NonexistantSession(err) => write!(f, "Session doesn't exist: {}", err),
|
||||
Error::SessionAlreadyExists(err) => write!(f, "Session already exist: {}", err),
|
||||
Error::ParticipantNotFound(err) => write!(f, "Participant not found: {}", err),
|
||||
Error::Xmpp(err) => write!(f, "XMPP error: {}", err),
|
||||
Error::Parser(err) => write!(f, "Parser error: {}", err),
|
||||
}
|
||||
|
|
|
@ -195,11 +195,7 @@ async fn handle_presence<C: ComponentTrait>(
|
|||
_ => ControlFlow::Continue(()),
|
||||
});
|
||||
|
||||
// TODO: Handle presence probes, remove the return here.
|
||||
// TODO: check for features in the Muc element.
|
||||
if let ControlFlow::Continue(_) = muc {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Presences to MUC come from resources not accounts
|
||||
if let Jid::Full(realjid) = presence.from.clone().unwrap() &&
|
||||
|
@ -211,23 +207,31 @@ async fn handle_presence<C: ComponentTrait>(
|
|||
// Room already exists
|
||||
if let Some(room) = rooms.get_mut(&roomjid) {
|
||||
debug!("Presence received to existing room: {}", &roomjid);
|
||||
match room.add_session(component, realjid.clone(), nick).await {
|
||||
Ok(_) => (),
|
||||
Err(Error::NickAlreadyAssigned(nick)) => {
|
||||
let error = Presence::new(PresenceType::Error)
|
||||
.with_from(participant)
|
||||
.with_to(realjid)
|
||||
.with_payloads(vec![
|
||||
StanzaError::new(
|
||||
ErrorType::Cancel,
|
||||
DefinedCondition::Conflict,
|
||||
"en",
|
||||
format!("Nickname conflict: {}", nick),
|
||||
).into()
|
||||
]);
|
||||
component.send_stanza(error).await?;
|
||||
},
|
||||
err => err.unwrap(),
|
||||
if let ControlFlow::Break(_) = muc {
|
||||
match room.add_session(component, realjid.clone(), nick).await {
|
||||
Ok(_) => (),
|
||||
Err(Error::NickAlreadyAssigned(nick)) => {
|
||||
let error = Presence::new(PresenceType::Error)
|
||||
.with_from(participant)
|
||||
.with_to(realjid)
|
||||
.with_payloads(vec![
|
||||
StanzaError::new(
|
||||
ErrorType::Cancel,
|
||||
DefinedCondition::Conflict,
|
||||
"en",
|
||||
format!("Nickname conflict: {}", nick),
|
||||
).into()
|
||||
]);
|
||||
component.send_stanza(error).await?;
|
||||
},
|
||||
err => err.unwrap(),
|
||||
}
|
||||
} else if let ControlFlow::Continue(_) = muc {
|
||||
if room.is_joined(&realjid) {
|
||||
room.update_presence(component, realjid.clone(), nick).await?
|
||||
} else {
|
||||
// TODO: We don't want to support GC1. Error
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("Presence received to new room: {}", &roomjid);
|
||||
|
|
30
src/room.rs
30
src/room.rs
|
@ -286,6 +286,22 @@ impl Room {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_presence<C: ComponentTrait>(
|
||||
&mut self,
|
||||
component: &mut C,
|
||||
realjid: Session,
|
||||
nick: Nick,
|
||||
) -> Result<(), Error> {
|
||||
self.broadcast_presence(
|
||||
component,
|
||||
self.get_occupant(&realjid, &nick)?,
|
||||
&realjid,
|
||||
BroadcastPresence::Update,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove_session<C: ComponentTrait>(
|
||||
&mut self,
|
||||
component: &mut C,
|
||||
|
@ -305,6 +321,20 @@ impl Room {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Looks for the occupant associated with the provided nick and ensure the session is part of
|
||||
/// it.
|
||||
pub fn get_occupant(&self, realjid: &Session, nick: &Nick) -> Result<&Occupant, Error> {
|
||||
if let Some(occupant) = self.occupants.get(nick) {
|
||||
if occupant.sessions.contains(realjid) {
|
||||
Ok(occupant)
|
||||
} else {
|
||||
Err(Error::NonexistantSession(realjid.clone()))
|
||||
}
|
||||
} else {
|
||||
Err(Error::ParticipantNotFound(nick.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_joined<J: Into<Jid>>(&self, _jid: &J) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ use crate::component::TestComponent;
|
|||
use crate::handlers::handle_stanza;
|
||||
use crate::room::Room;
|
||||
use crate::tests::templates::{
|
||||
LOUISE_FULL1, LOUISE_FULL2, LOUISE_NICK, LOUISE_ROOM1_PART, ROOM1_BARE, SUGAKO_FULL1,
|
||||
SUGAKO_ROOM1_PART,
|
||||
two_participant_room, LOUISE_FULL1, LOUISE_FULL2, LOUISE_NICK, LOUISE_ROOM1_PART, ROOM1_BARE,
|
||||
SUGAKO_FULL1, SUGAKO_ROOM1_PART,
|
||||
};
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
@ -513,3 +513,30 @@ async fn test_join_msn() {
|
|||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_presence_update_joined() {
|
||||
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||
rooms.insert(ROOM1_BARE.clone(), two_participant_room(ROOM1_BARE.clone()));
|
||||
|
||||
let update1: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(SUGAKO_FULL1.clone()))
|
||||
.with_to(Jid::Full(SUGAKO_ROOM1_PART.clone()))
|
||||
.with_show(PresenceShow::Away)
|
||||
.into();
|
||||
|
||||
let mut component = TestComponent::new(vec![update1]);
|
||||
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(SUGAKO_ROOM1_PART.clone()))
|
||||
.with_to(Jid::Full(LOUISE_FULL1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: Vec::new(),
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||
}
|
||||
|
|
|
@ -75,3 +75,16 @@ pub fn one_participant_room(roomjid: BareJid) -> Room {
|
|||
);
|
||||
room
|
||||
}
|
||||
|
||||
pub fn two_participant_room(roomjid: BareJid) -> Room {
|
||||
let mut room = Room::new(roomjid.clone());
|
||||
room.occupants.insert(
|
||||
String::from(LOUISE_NICK),
|
||||
Occupant::new(&room, LOUISE_FULL1.clone(), String::from(LOUISE_NICK)),
|
||||
);
|
||||
room.occupants.insert(
|
||||
String::from(SUGAKO_NICK),
|
||||
Occupant::new(&room, SUGAKO_FULL1.clone(), String::from(SUGAKO_NICK)),
|
||||
);
|
||||
room
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue