Support Multi-Session Nicks joins
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
919f3cf754
commit
7a687df552
3 changed files with 171 additions and 37 deletions
|
@ -13,10 +13,9 @@ file.
|
|||
|
||||
### XMPP
|
||||
|
||||
- [ ] Join
|
||||
* [x] Single session
|
||||
* [ ] Multiple sessions non-MSN
|
||||
* [ ] MSN
|
||||
- [x] Join
|
||||
* [x] Normal sessions
|
||||
* [x] MSN
|
||||
- [ ] Presence
|
||||
* [x] Updates
|
||||
* [x] Resync
|
||||
|
|
92
src/room.rs
92
src/room.rs
|
@ -114,28 +114,14 @@ impl Room {
|
|||
_ => false,
|
||||
};
|
||||
|
||||
/*
|
||||
// MucItems to be sent to sessions of this occupant
|
||||
let self_items = own_occupant.iter().map(|session| {
|
||||
MucItem {
|
||||
affiliation: Affiliation::Owner,
|
||||
role: Role::Moderator,
|
||||
jid: Some(session.clone()),
|
||||
nick: None,
|
||||
actor: None,
|
||||
continue_: None,
|
||||
reason: None,
|
||||
}
|
||||
}).collect::<Vec<MucItem>>();
|
||||
*/
|
||||
|
||||
for (_, other) in self.occupants.iter() {
|
||||
if own_occupant.nick == other.nick {
|
||||
continue;
|
||||
}
|
||||
if sync { // Send presences from others to participant.
|
||||
if own_occupant.nick != &other.nick {
|
||||
let presence = presence_to_new.clone()
|
||||
.with_from(Jid::Full(other.participant.clone()));
|
||||
component.send_stanza(presence).await?;
|
||||
}
|
||||
let presence = presence_to_new.clone()
|
||||
.with_from(Jid::Full(other.participant.clone()));
|
||||
component.send_stanza(presence).await?;
|
||||
}
|
||||
if update || leave { // Send presence from participant to others.
|
||||
for session in other.iter() {
|
||||
|
@ -151,6 +137,39 @@ impl Room {
|
|||
}
|
||||
}
|
||||
|
||||
// MucItems to be sent to sessions of this occupant
|
||||
let self_items = own_occupant.iter().map(|session| {
|
||||
MucItem {
|
||||
affiliation: Affiliation::Owner,
|
||||
role: if leave { Role::None } else { Role::Moderator },
|
||||
jid: Some(session.clone()),
|
||||
nick: None,
|
||||
actor: None,
|
||||
continue_: None,
|
||||
reason: None,
|
||||
}
|
||||
}).collect::<Vec<MucItem>>();
|
||||
|
||||
// Multi-Session Nick: For this occupant, include all sessions all with item@jid discovered
|
||||
// so they can identify each other as being the same account under the same nick.
|
||||
let session_presence = Presence::new(
|
||||
if leave { PresenceType::Unavailable } else { PresenceType::None }
|
||||
)
|
||||
.with_from(Jid::Full(own_occupant.participant.clone()));
|
||||
|
||||
for session in own_occupant.iter() {
|
||||
if session == own_session {
|
||||
continue;
|
||||
}
|
||||
let presence = session_presence.clone()
|
||||
.with_to(Jid::Full(session.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![],
|
||||
items: self_items.clone(),
|
||||
}.into()]);
|
||||
component.send_stanza(presence).await?;
|
||||
}
|
||||
|
||||
// Send self-presence
|
||||
if sync || leave {
|
||||
// New participant to all other sessions
|
||||
|
@ -167,12 +186,11 @@ impl Room {
|
|||
MucStatus::SelfPresence,
|
||||
MucStatus::AssignedNick,
|
||||
] },
|
||||
items: vec![
|
||||
MucItem::new(
|
||||
Affiliation::Owner,
|
||||
if leave { Role::None } else { Role::Moderator },
|
||||
)
|
||||
],
|
||||
items: if leave {
|
||||
vec![MucItem::new(Affiliation::Owner, Role::None)]
|
||||
} else {
|
||||
self_items
|
||||
},
|
||||
}
|
||||
.into()]);
|
||||
component.send_stanza(self_presence).await?;
|
||||
|
@ -231,7 +249,9 @@ impl Room {
|
|||
let mode: Option<BroadcastPresence> = {
|
||||
if let Some(occupant) = self.occupants.get_mut(&new_nick) {
|
||||
match occupant.add_session(realjid.clone()) {
|
||||
Ok(_) => None,
|
||||
Ok(_) => {
|
||||
Some(BroadcastPresence::Join)
|
||||
},
|
||||
Err(Error::SessionAlreadyExists(_)) => {
|
||||
Some(BroadcastPresence::Resync)
|
||||
},
|
||||
|
@ -372,7 +392,7 @@ mod tests {
|
|||
use std::str::FromStr;
|
||||
use crate::component::TestComponent;
|
||||
use xmpp_parsers::{
|
||||
BareJid,
|
||||
BareJid, Element,
|
||||
presence::{Presence, Type as PresenceType},
|
||||
muc::{
|
||||
MucUser,
|
||||
|
@ -402,6 +422,12 @@ mod tests {
|
|||
let occupant3 = Occupant::new(&room, realjid3.clone(), String::from("nick3"));
|
||||
room.occupants.insert(participant3.resource.clone(), occupant3.clone());
|
||||
|
||||
let self_item = MucItem::try_from(
|
||||
r#"<item xmlns="http://jabber.org/protocol/muc#user" affiliation="owner" role="moderator" jid="bar@qxx/foo"/>"#
|
||||
.parse::<Element>()
|
||||
.unwrap()
|
||||
).unwrap();
|
||||
|
||||
// BroadcastPresence::Resync
|
||||
let mut component = TestComponent::new(vec![]);
|
||||
|
||||
|
@ -436,7 +462,7 @@ mod tests {
|
|||
.with_payloads(vec![
|
||||
MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
items: vec![self_item.clone()],
|
||||
}.into()
|
||||
])
|
||||
);
|
||||
|
@ -520,6 +546,12 @@ mod tests {
|
|||
let occupant3 = Occupant::new(&room, realjid3.clone(), String::from("nick3"));
|
||||
room.occupants.insert(participant3.resource.clone(), occupant3.clone());
|
||||
|
||||
let self_item = MucItem::try_from(
|
||||
r#"<item xmlns="http://jabber.org/protocol/muc#user" affiliation="owner" role="moderator" jid="bar@qxx/foo"/>"#
|
||||
.parse::<Element>()
|
||||
.unwrap()
|
||||
).unwrap();
|
||||
|
||||
// BroadcastPresence::Join
|
||||
let mut component = TestComponent::new(vec![]);
|
||||
|
||||
|
@ -578,7 +610,7 @@ mod tests {
|
|||
.with_payloads(vec![
|
||||
MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
items: vec![self_item],
|
||||
}.into()
|
||||
])
|
||||
);
|
||||
|
|
109
src/tests.rs
109
src/tests.rs
|
@ -101,7 +101,11 @@ async fn test_join_presence_empty_room() {
|
|||
.with_to(Jid::Full(from.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
items: vec![{
|
||||
let mut item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
item.jid = Some(from.clone());
|
||||
item
|
||||
}],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
@ -256,7 +260,11 @@ async fn test_join_presence_existing_room() {
|
|||
.with_to(Jid::Full(realjid2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
items: vec![{
|
||||
let mut item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
item.jid = Some(realjid2.clone());
|
||||
item
|
||||
}],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
@ -347,7 +355,11 @@ async fn test_presence_resync() {
|
|||
.with_to(Jid::Full(realjid1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
items: vec![{
|
||||
let mut item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
item.jid = Some(realjid1.clone());
|
||||
item
|
||||
}],
|
||||
}
|
||||
.into()]),
|
||||
);
|
||||
|
@ -488,3 +500,94 @@ async fn test_leave_room_not_last() {
|
|||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_join_msn() {
|
||||
let barejid = BareJid::from_str("foo@bar").unwrap();
|
||||
let realjid1 = barejid.clone().with_resource("qxx");
|
||||
let realjid2 = barejid.clone().with_resource("hah");
|
||||
let roomjid = COMPONENT_JID.clone().with_node("room");
|
||||
let participant1 = roomjid.clone().with_resource("nick1");
|
||||
|
||||
let join1: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(realjid1.clone()))
|
||||
.with_to(Jid::Full(participant1.clone()))
|
||||
.with_payloads(vec![Muc::new().into()])
|
||||
.into();
|
||||
|
||||
let join2: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(realjid2.clone()))
|
||||
.with_to(Jid::Full(participant1.clone()))
|
||||
.with_payloads(vec![Muc::new().into()])
|
||||
.into();
|
||||
|
||||
let mut component = TestComponent::new(vec![join1, join2]);
|
||||
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(participant1.clone()))
|
||||
.with_to(Jid::Full(realjid1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![{
|
||||
let mut item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
item.jid = Some(realjid1.clone());
|
||||
item
|
||||
}],
|
||||
}.into()])
|
||||
);
|
||||
|
||||
component.expect_message(|_| (), "Subject message for participant1");
|
||||
|
||||
// New session joins
|
||||
// Participant1 presence for participant2
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(participant1.clone()))
|
||||
.with_to(Jid::Full(realjid1.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: Vec::new(),
|
||||
items: {
|
||||
let item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
let mut item1 = item.clone();
|
||||
item1.jid = Some(realjid1.clone());
|
||||
let mut item2 = item.clone();
|
||||
item2.jid = Some(realjid2.clone());
|
||||
vec![item1, item2]
|
||||
},
|
||||
}.into()])
|
||||
);
|
||||
|
||||
// Self-presence for participant2
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(participant1.clone()))
|
||||
.with_to(Jid::Full(realjid2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: {
|
||||
let item = MucItem::new(Affiliation::Owner, Role::Moderator);
|
||||
let mut item1 = item.clone();
|
||||
item1.jid = Some(realjid1.clone());
|
||||
let mut item2 = item.clone();
|
||||
item2.jid = Some(realjid2.clone());
|
||||
vec![item1, item2]
|
||||
},
|
||||
}.into()])
|
||||
);
|
||||
|
||||
component.expect_message(|_| (), "Subject message for participant2");
|
||||
|
||||
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||
component.assert();
|
||||
|
||||
assert_eq!(rooms.len(), 1);
|
||||
match rooms.get(&roomjid) {
|
||||
Some(room) => {
|
||||
assert_eq!(room.occupants.len(), 1);
|
||||
assert_eq!(room.occupants.get(&participant1.resource).unwrap().sessions.len(), 2);
|
||||
},
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue