//! 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>, p: Presence) -> 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>, 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(); } }