diff --git a/crates/projection-xmpp/src/presence.rs b/crates/projection-xmpp/src/presence.rs index 3712baa..f39ce73 100644 --- a/crates/projection-xmpp/src/presence.rs +++ b/crates/projection-xmpp/src/presence.rs @@ -4,9 +4,9 @@ use anyhow::Result; use quick_xml::events::Event; use lavina_core::room::RoomId; -use proto_xmpp::bind::{Jid, Name, Server}; +use proto_xmpp::bind::{Jid, Name, Resource, Server}; use proto_xmpp::client::Presence; -use proto_xmpp::muc::XUser; +use proto_xmpp::muc::{Delay, HistoryMessage, XUser}; use proto_xmpp::xml::{Ignore, ToXml}; use crate::XmppConnection; @@ -23,8 +23,11 @@ impl<'a> XmppConnection<'a> { // 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); + let muc_join_response = self.muc_presence(&name).await?; + muc_join_response.serialize(output); + + let history_on_join_response = self.send_history_on_join().await?; + history_on_join_response.serialize(output) } _ => { // TODO other presence cases @@ -60,7 +63,6 @@ impl<'a> XmppConnection<'a> { } } - // 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 @@ -80,21 +82,44 @@ impl<'a> XmppConnection<'a> { }; Ok(response) } + async fn send_history_on_join(&self) -> Result<(HistoryMessage)> { + Ok(HistoryMessage { + id: "kek".to_string(), + to: Jid { + name: Some(Name("tester".into())), + server: Server("localhost".into()), + resource: Some(Resource("tester".into())), + }, + from: Jid { + name: Some(Name("tester".into())), + server: Server("localhost".into()), + resource: Some(Resource("tester".into())), + }, + delay: Delay::new( + Jid { + name: Some(Name("tester".into())), + server: Server("localhost".into()), + resource: Some(Resource("tester".into())), + }, + "2021-10-10T10:10:10Z".to_string(), + ), + body: "Vasya Pupkin says hello.".to_string(), + }) + } } -// 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 anyhow::Result; + use lavina_core::player::PlayerId; use proto_xmpp::bind::{Jid, Name, Resource, Server}; use proto_xmpp::client::Presence; use proto_xmpp::muc::XUser; + use crate::testkit::{expect_user_authenticated, TestServer}; + use crate::Authenticated; + #[tokio::test] async fn test_muc_joining() -> Result<()> { let server = TestServer::start().await.unwrap(); diff --git a/crates/proto-xmpp/src/muc/mod.rs b/crates/proto-xmpp/src/muc/mod.rs index 61cf933..b00460f 100644 --- a/crates/proto-xmpp/src/muc/mod.rs +++ b/crates/proto-xmpp/src/muc/mod.rs @@ -1,10 +1,12 @@ #![allow(unused_variables)] -use quick_xml::events::{BytesStart, Event}; -use quick_xml::name::ResolveResult; - -use crate::xml::*; use anyhow::{anyhow, Result}; +use quick_xml::events::attributes::Attribute; +use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; +use quick_xml::name::{QName, ResolveResult}; + +use crate::bind::Jid; +use crate::xml::*; pub const XMLNS: &'static str = "http://jabber.org/protocol/muc"; pub const XMLNS_USER: &'static str = "http://jabber.org/protocol/muc#user"; @@ -146,6 +148,7 @@ impl FromXml for X { #[derive(Debug, PartialEq, Eq)] pub struct XUser; + impl ToXml for XUser { fn serialize(&self, output: &mut Vec>) { let mut tag = BytesStart::new("x"); @@ -154,6 +157,79 @@ impl ToXml for XUser { } } +// +// +// dddddd +// + +#[derive(Debug, PartialEq, Eq)] +pub struct Delay { + xmlns: String, + from: Jid, + pub stamp: String, +} + +impl Delay { + pub fn new(from: Jid, stamp: String) -> Self { + Self { + xmlns: "urn:xmpp:delay".into(), + from, + stamp, + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct HistoryMessage { + pub id: String, + pub to: Jid, + pub from: Jid, + pub delay: Delay, + pub body: String, +} + +impl ToXml for HistoryMessage { + fn serialize(&self, events: &mut Vec>) { + let mut tag = BytesStart::new("message"); + tag.push_attribute(Attribute { + key: QName(b"id"), + value: self.id.as_str().as_bytes().into(), + }); + tag.push_attribute(Attribute { + key: QName(b"to"), + value: self.to.to_string().into_bytes().into(), + }); + tag.push_attribute(Attribute { + key: QName(b"from"), + value: self.from.to_string().into_bytes().into(), + }); + tag.push_attribute(Attribute { + key: QName(b"type"), + value: b"groupchat".into(), + }); + events.push(Event::Start(tag)); + let mut tag = BytesStart::new("delay"); + tag.push_attribute(Attribute { + key: QName(b"xmlns"), + value: self.delay.xmlns.as_bytes().into(), + }); + tag.push_attribute(Attribute { + key: QName(b"from"), + value: self.delay.from.to_string().into_bytes().into(), + }); + tag.push_attribute(Attribute { + key: QName(b"stamp"), + value: self.delay.stamp.as_bytes().into(), + }); + events.push(Event::Empty(tag)); + let mut tag = BytesStart::new("body"); + events.push(Event::Start(tag)); + events.push(Event::Text(BytesText::new(self.body.to_string().as_str()).into_owned())); + events.push(Event::End(BytesEnd::new("body"))); + events.push(Event::End(BytesEnd::new("message"))); + } +} + #[cfg(test)] mod test { use super::*;