Merge MSN sessions on nick changes
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
3f90060c08
commit
18050c1185
2 changed files with 174 additions and 26 deletions
83
src/room.rs
83
src/room.rs
|
@ -347,13 +347,18 @@ impl Room {
|
|||
let newnick = &new_session.participant().resource;
|
||||
let bare = BareJid::from(new_session.real().clone());
|
||||
|
||||
let mut merge = false;
|
||||
for (nick, occupant) in self.occupants.iter_mut() {
|
||||
if nick == newnick && occupant.real != bare {
|
||||
return Err(Error::NickAlreadyAssigned(newnick.clone()));
|
||||
if nick == newnick {
|
||||
if occupant.real != bare {
|
||||
return Err(Error::NickAlreadyAssigned(newnick.clone()));
|
||||
} else {
|
||||
merge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send unavailable for current session to everyone
|
||||
|
||||
let presence_leave = Presence::new(PresenceType::Unavailable)
|
||||
|
@ -402,13 +407,29 @@ impl Room {
|
|||
}
|
||||
} else {
|
||||
// Other occupants' sessions
|
||||
component
|
||||
.send_stanza(
|
||||
presence_leave_to_others
|
||||
.clone()
|
||||
.with_to(Jid::Full(session.real().clone())),
|
||||
)
|
||||
.await?;
|
||||
if occupant.real == bare {
|
||||
// Same barejid
|
||||
let mucuser = MucUser {
|
||||
status: vec![MucStatus::NewNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::None)
|
||||
.with_nick(newnick.clone())
|
||||
.with_jid(joined_session.real().clone())],
|
||||
};
|
||||
|
||||
let presence = presence_leave
|
||||
.clone()
|
||||
.with_to(Jid::Full(session.real().clone()))
|
||||
.with_payloads(vec![mucuser.into()]);
|
||||
component.send_stanza(presence).await?;
|
||||
} else {
|
||||
component
|
||||
.send_stanza(
|
||||
presence_leave_to_others
|
||||
.clone()
|
||||
.with_to(Jid::Full(session.real().clone())),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,9 +445,17 @@ impl Room {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Nickname isn't present already in the room. Create new occupant.
|
||||
let occupant = Occupant::new(new_session.presence.clone())?;
|
||||
self.occupants.insert(newnick.to_string(), occupant.clone());
|
||||
if merge {
|
||||
// Merge the new session
|
||||
match self.get_mut_occupant(&new_session) {
|
||||
Ok(occupant) => occupant.add_session(new_session.presence.clone())?,
|
||||
_ => unreachable!(), // We've already established that the occupant existed.
|
||||
}
|
||||
} else {
|
||||
// Nickname isn't present already in the room. Create new occupant.
|
||||
let occupant = Occupant::new(new_session.presence.clone())?;
|
||||
self.occupants.insert(newnick.to_string(), occupant.clone());
|
||||
}
|
||||
|
||||
// Send available for new session to everyone
|
||||
|
||||
|
@ -439,23 +468,29 @@ impl Room {
|
|||
}
|
||||
.into()]);
|
||||
|
||||
let occupant = self.get_occupant(&new_session)?;
|
||||
let mucuser = MucUser {
|
||||
status: vec![],
|
||||
items: {
|
||||
occupant
|
||||
.iter()
|
||||
.map(|session| {
|
||||
MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(session.real().clone())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
},
|
||||
};
|
||||
|
||||
for (nick, occupant) in self.occupants.iter() {
|
||||
for session in occupant.iter() {
|
||||
// Self occupant
|
||||
if nick == newnick {
|
||||
let mucuser = MucUser {
|
||||
status: vec![],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(new_session.real().clone())],
|
||||
};
|
||||
|
||||
if session.real() == new_session.real() {
|
||||
// Self session
|
||||
let mucuser = MucUser {
|
||||
status: vec![MucStatus::SelfPresence],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(new_session.real().clone())],
|
||||
};
|
||||
let mut mucuser = mucuser.clone();
|
||||
mucuser.status = vec![MucStatus::SelfPresence];
|
||||
|
||||
component
|
||||
.send_stanza(
|
||||
presence_join
|
||||
|
|
|
@ -17,8 +17,8 @@ use crate::component::TestComponent;
|
|||
use crate::handlers::handle_stanza;
|
||||
use crate::room::Room;
|
||||
use crate::tests::templates::{
|
||||
new_room, LOUISE_FULL1, LOUISE_FULL2, LOUISE_NICK, LOUISE_ROOM1_PART, ROOM1_BARE, SUGAKO_FULL1,
|
||||
SUGAKO_NICK,
|
||||
new_room, LOUISE_FULL1, LOUISE_FULL2, LOUISE_NICK, LOUISE_NICK2, LOUISE_ROOM1_PART,
|
||||
LOUISE_ROOM1_PART2, ROOM1_BARE, SUGAKO_FULL1, SUGAKO_NICK,
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
@ -195,3 +195,116 @@ async fn leave() {
|
|||
assert!(louise.is_some());
|
||||
assert_eq!(louise.unwrap().sessions.len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn nickname_change_merge() {
|
||||
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||
rooms.insert(
|
||||
ROOM1_BARE.clone(),
|
||||
new_room(
|
||||
ROOM1_BARE.clone(),
|
||||
vec![
|
||||
(LOUISE_NICK, vec![LOUISE_FULL1.clone()]),
|
||||
(LOUISE_NICK2, vec![LOUISE_FULL2.clone()]),
|
||||
(SUGAKO_NICK, vec![SUGAKO_FULL1.clone()]),
|
||||
],
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
||||
// LOUISE_NICK2 merging with LOUISE_NICK
|
||||
let update: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(LOUISE_FULL2.clone()))
|
||||
.with_to(Jid::Full(LOUISE_ROOM1_PART.clone()))
|
||||
.into();
|
||||
|
||||
let mut component = TestComponent::new(vec![update]);
|
||||
|
||||
// Unavailable to self
|
||||
component.expect(
|
||||
Presence::new(PresenceType::Unavailable)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART2.clone()))
|
||||
.with_to(Jid::Full(LOUISE_FULL2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::NewNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::None)
|
||||
.with_nick(LOUISE_NICK)
|
||||
.with_jid(LOUISE_FULL2.clone())],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
// Available to self
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART.clone()))
|
||||
.with_to(Jid::Full(LOUISE_FULL2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence],
|
||||
items: vec![
|
||||
MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(LOUISE_FULL1.clone()),
|
||||
MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(LOUISE_FULL2.clone()),
|
||||
],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
// Unavailable to other MSN session
|
||||
component.expect(
|
||||
Presence::new(PresenceType::Unavailable)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART2.clone()))
|
||||
.with_to(Jid::Full(LOUISE_FULL1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::NewNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::None)
|
||||
.with_nick(LOUISE_NICK)
|
||||
.with_jid(LOUISE_FULL2.clone())],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
// Available to other MSN session
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART.clone()))
|
||||
.with_to(Jid::Full(LOUISE_FULL1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![],
|
||||
items: vec![
|
||||
MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(LOUISE_FULL1.clone()),
|
||||
MucItem::new(Affiliation::Owner, Role::Moderator)
|
||||
.with_jid(LOUISE_FULL2.clone()),
|
||||
],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
// Unavailable to Sugako
|
||||
component.expect(
|
||||
Presence::new(PresenceType::Unavailable)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART2.clone()))
|
||||
.with_to(Jid::Full(SUGAKO_FULL1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::NewNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::None).with_nick(LOUISE_NICK)],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
// Available to Sugako
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(LOUISE_ROOM1_PART.clone()))
|
||||
.with_to(Jid::Full(SUGAKO_FULL1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
||||
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue