lavina/crates/projection-xmpp/src/presence.rs

177 lines
6.4 KiB
Rust
Raw Normal View History

//! Handling of all client2server presence stanzas
use quick_xml::events::Event;
use lavina_core::prelude::*;
use lavina_core::room::RoomId;
use proto_xmpp::bind::{Jid, Name, Server};
use proto_xmpp::client::Presence;
use proto_xmpp::xml::{Ignore, ToXml};
use crate::XmppConnection;
impl<'a> XmppConnection<'a> {
pub async fn handle_presence(&mut self, output: &mut Vec<Event<'static>>, p: Presence<Ignore>) -> Result<()> {
match p.to {
None => {
self.self_presence(output, p.r#type.as_deref()).await;
}
Some(Jid {
name: Some(name),
server,
// resources in MUCs are members' personas not implemented (yet?)
resource: Some(_),
}) if server.0 == self.hostname_rooms => {
let response = self.muc_presence(&name).await?;
response.serialize(output);
}
_ => {
// TODO other presence cases
let response = Presence::<()>::default();
response.serialize(output);
}
}
Ok(())
}
async fn self_presence(&mut self, output: &mut Vec<Event<'static>>, r#type: Option<&str>) {
match r#type {
Some("unavailable") => {
// do not print anything
}
None => {
let response = Presence::<()> {
to: Some(Jid {
name: Some(self.user.xmpp_name.clone()),
server: Server(self.hostname.clone()),
resource: Some(self.user.xmpp_resource.clone()),
}),
from: Some(Jid {
name: Some(self.user.xmpp_name.clone()),
server: Server(self.hostname.clone()),
resource: Some(self.user.xmpp_resource.clone()),
}),
..Default::default()
};
response.serialize(output);
}
_ => todo!(),
}
}
// todo: return Presence and serialize on the outside.
async fn muc_presence(&mut self, name: &Name) -> Result<(Presence<()>)> {
let a = self.user_handle.join_room(RoomId::from(name.0.clone())?).await?;
// TODO handle bans
let response = Presence::<()> {
to: Some(Jid {
name: Some(self.user.xmpp_name.clone()),
server: Server(self.hostname.clone()),
resource: Some(self.user.xmpp_resource.clone()),
}),
from: Some(Jid {
name: Some(name.clone()),
server: Server(self.hostname_rooms.clone()),
resource: Some(self.user.xmpp_muc_name.clone()),
}),
..Default::default()
};
Ok(response)
}
}
// todo: set up so that the user has been previously joined.
// todo: first call to muc_presence is OK, next one is OK too.
#[cfg(test)]
mod tests {
use crate::testkit::{expect_user_authenticated, TestServer};
use crate::Authenticated;
use lavina_core::player::PlayerId;
use proto_xmpp::bind::{Jid, Name, Resource, Server};
use proto_xmpp::client::Presence;
#[tokio::test]
async fn test_muc_joining() {
let server = TestServer::start().await.unwrap();
server.storage.create_user("tester").await.unwrap();
let player_id = PlayerId::from("tester").unwrap();
let user = Authenticated {
player_id,
xmpp_name: Name("tester".into()),
xmpp_resource: Resource("tester".into()),
xmpp_muc_name: Resource("tester".into()),
};
let mut player_conn = server.core.players.connect_to_player(&user.player_id).await;
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
let expected = Presence::<()> {
to: Some(Jid {
name: Some(conn.user.xmpp_name.clone()),
server: Server(conn.hostname.clone()),
resource: Some(conn.user.xmpp_resource.clone()),
}),
from: Some(Jid {
name: Some(user.xmpp_name.clone()),
server: Server(conn.hostname_rooms.clone()),
resource: Some(conn.user.xmpp_muc_name.clone()),
}),
..Default::default()
};
assert_eq!(expected, response);
server.shutdown().await.unwrap();
}
// Test that joining a room second time after a server restart,
// i.e. in-memory cache of memberships is cleaned, does not cause any issues.
#[tokio::test]
async fn test_muc_joining_twice() {
let server = TestServer::start().await.unwrap();
server.storage.create_user("tester").await.unwrap();
let player_id = PlayerId::from("tester").unwrap();
let user = Authenticated {
player_id,
xmpp_name: Name("tester".into()),
xmpp_resource: Resource("tester".into()),
xmpp_muc_name: Resource("tester".into()),
};
let mut player_conn = server.core.players.connect_to_player(&user.player_id).await;
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
let expected = Presence::<()> {
to: Some(Jid {
name: Some(conn.user.xmpp_name.clone()),
server: Server(conn.hostname.clone()),
resource: Some(conn.user.xmpp_resource.clone()),
}),
from: Some(Jid {
name: Some(user.xmpp_name.clone()),
server: Server(conn.hostname_rooms.clone()),
resource: Some(conn.user.xmpp_muc_name.clone()),
}),
..Default::default()
};
assert_eq!(expected, response);
drop(conn);
let server = server.reboot().await.unwrap();
let mut player_conn = server.core.players.connect_to_player(&user.player_id).await;
let mut conn = expect_user_authenticated(&server, &user, &mut player_conn).await.unwrap();
let response = conn.muc_presence(&user.xmpp_name).await.unwrap();
assert_eq!(expected, response);
server.shutdown().await.unwrap();
}
}