From 33dbfba1164ee9c95fcd68427e218d89b11207d0 Mon Sep 17 00:00:00 2001 From: Nikita Vilunov Date: Sun, 12 Mar 2023 14:15:13 +0100 Subject: [PATCH] feat(xmpp): implement session iq --- src/projections/xmpp/mod.rs | 16 +++++++++ src/projections/xmpp/proto.rs | 34 ++++++++++++------- src/protos/xmpp/bind.rs | 8 ++--- src/protos/xmpp/client.rs | 12 +++---- src/protos/xmpp/mod.rs | 1 + src/protos/xmpp/session.rs | 62 +++++++++++++++++++++++++++++++++++ src/util/xml.rs | 5 +++ 7 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 src/protos/xmpp/session.rs diff --git a/src/projections/xmpp/mod.rs b/src/projections/xmpp/mod.rs index 286b29d..dbf9965 100644 --- a/src/projections/xmpp/mod.rs +++ b/src/projections/xmpp/mod.rs @@ -25,6 +25,7 @@ use crate::prelude::*; use crate::protos::xmpp; use crate::protos::xmpp::bind::{BindResponse, Jid, Name, Server}; use crate::protos::xmpp::client::Iq; +use crate::protos::xmpp::session::Session; use crate::protos::xmpp::stream::*; use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; use crate::util::Terminator; @@ -301,6 +302,21 @@ async fn socket_final( } xml_writer.get_mut().flush().await?; } + proto::IqClientBody::Session(_) => { + let mut events = vec![]; + let req = Iq { + from: None, + id: iq.id, + to: None, + r#type: xmpp::client::IqType::Result, + body: Session, + }; + req.serialize(&mut events); + for i in events { + xml_writer.write_event_async(i).await?; + } + xml_writer.get_mut().flush().await?; + } }, proto::ClientPacket::Message(_) => todo!(), } diff --git a/src/projections/xmpp/proto.rs b/src/projections/xmpp/proto.rs index 17a0327..909774c 100644 --- a/src/projections/xmpp/proto.rs +++ b/src/projections/xmpp/proto.rs @@ -4,13 +4,15 @@ use quick_xml::name::{Namespace, ResolveResult}; use crate::protos::xmpp::bind::BindRequest; use crate::protos::xmpp::client::{Iq, Message}; -use crate::util::xml::{Continuation, FromXml, Parser}; +use crate::protos::xmpp::session::Session; +use crate::util::xml::{Continuation, FromXml, FromXmlTag, Parser}; use crate::prelude::*; #[derive(PartialEq, Eq, Debug, From)] pub enum IqClientBody { Bind(BindRequest), + Session(Session), } #[derive(From)] @@ -20,6 +22,7 @@ pub struct IqClientBodyParser(IqClientBodyParserInner); enum IqClientBodyParserInner { Initial, Bind(::P), + SessionV(::P), } impl FromXml for IqClientBody { @@ -41,20 +44,21 @@ impl Parser for IqClientBodyParser { use IqClientBodyParserInner::*; match self.0 { Initial => { - let Event::Start(bytes) = event else { - return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}. Expected start of {}", BindRequest::NAME))); + let bytes = match event { + Event::Start(bytes) => bytes, + Event::Empty(bytes) => bytes, + _ => { + return Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))) + } }; if bytes.name().0 == BindRequest::NAME.as_bytes() && namespace == ResolveResult::Bound(Namespace(BindRequest::NS.as_bytes())) { - match BindRequest::parse().consume(namespace, event) { - Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())), - Continuation::Final(Err(e)) => Continuation::Final(Err(e)), - Continuation::Continue(s) => { - let inner: IqClientBodyParserInner = s.into(); - Continuation::Continue(inner.into()) - } - } + IqClientBodyParser(BindRequest::parse().into()).consume(namespace, event) + } else if bytes.name().0 == Session::NAME.as_bytes() + && namespace == ResolveResult::Bound(Namespace(Session::NS.as_bytes())) + { + IqClientBodyParser(Session::parse().into()).consume(namespace, event) } else { Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))) } @@ -67,6 +71,14 @@ impl Parser for IqClientBodyParser { Continuation::Continue(inner.into()) } }, + SessionV(p) => match p.consume(namespace, event) { + Continuation::Final(Ok(r)) => Continuation::Final(Ok(r.into())), + Continuation::Final(Err(e)) => Continuation::Final(Err(e)), + Continuation::Continue(s) => { + let inner: IqClientBodyParserInner = s.into(); + Continuation::Continue(inner.into()) + } + }, } } } diff --git a/src/protos/xmpp/bind.rs b/src/protos/xmpp/bind.rs index 08102ad..e0fc08b 100644 --- a/src/protos/xmpp/bind.rs +++ b/src/protos/xmpp/bind.rs @@ -3,7 +3,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::name::{Namespace, ResolveResult}; use crate::prelude::*; -use crate::util::xml::{Continuation, FromXml, Parser, ToXml}; +use crate::util::xml::*; pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-bind"; @@ -55,9 +55,9 @@ enum BindRequestParserInner { InBindResourceEnd(String), } -impl BindRequest { - pub const NS: &'static str = XMLNS; - pub const NAME: &'static str = "bind"; +impl FromXmlTag for BindRequest { + const NS: &'static str = XMLNS; + const NAME: &'static str = "bind"; } impl FromXml for BindRequest { diff --git a/src/protos/xmpp/client.rs b/src/protos/xmpp/client.rs index 028b64d..6764dc2 100644 --- a/src/protos/xmpp/client.rs +++ b/src/protos/xmpp/client.rs @@ -21,9 +21,9 @@ pub struct Message { pub body: String, } -impl Message { - pub const NS: &'static str = XMLNS; - pub const NAME: &'static str = "message"; +impl FromXmlTag for Message { + const NS: &'static str = XMLNS; + const NAME: &'static str = "message"; } impl FromXml for Message { @@ -180,9 +180,9 @@ pub struct Iq { pub body: T, } -impl Iq { - pub const NS: &'static str = XMLNS; - pub const NAME: &'static str = "iq"; +impl FromXmlTag for Iq { + const NAME: &'static str = "iq"; + const NS: &'static str = XMLNS; } impl FromXml for Iq { diff --git a/src/protos/xmpp/mod.rs b/src/protos/xmpp/mod.rs index 92ba9be..43bd8e1 100644 --- a/src/protos/xmpp/mod.rs +++ b/src/protos/xmpp/mod.rs @@ -1,6 +1,7 @@ pub mod bind; pub mod client; pub mod sasl; +pub mod session; pub mod stanzaerror; pub mod stream; pub mod tls; diff --git a/src/protos/xmpp/session.rs b/src/protos/xmpp/session.rs new file mode 100644 index 0000000..9f0104b --- /dev/null +++ b/src/protos/xmpp/session.rs @@ -0,0 +1,62 @@ +use quick_xml::events::{BytesStart, Event}; + +use crate::prelude::*; +use crate::util::xml::*; + +pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-session"; + +#[derive(PartialEq, Eq, Debug)] +pub struct Session; + +pub struct SessionParser(SessionParserInner); + +enum SessionParserInner { + Initial, + InSession, +} + +impl Parser for SessionParser { + type Output = Result; + + fn consume<'a>( + self: Self, + namespace: quick_xml::name::ResolveResult, + event: &quick_xml::events::Event<'a>, + ) -> Continuation { + match self.0 { + SessionParserInner::Initial => match event { + Event::Start(_) => { + Continuation::Continue(SessionParser(SessionParserInner::InSession)) + } + Event::Empty(_) => Continuation::Final(Ok(Session)), + _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), + }, + SessionParserInner::InSession => match event { + Event::End(_) => Continuation::Final(Ok(Session)), + _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), + }, + } + } +} + +impl FromXml for Session { + type P = SessionParser; + + fn parse() -> Self::P { + SessionParser(SessionParserInner::Initial) + } +} + +impl FromXmlTag for Session { + const NAME: &'static str = "session"; + const NS: &'static str = XMLNS; +} + +impl ToXml for Session { + fn serialize(&self, events: &mut Vec>) { + events.push(Event::Empty(BytesStart::new(format!( + r#"session xmlns="{}""#, + XMLNS + )))); + } +} diff --git a/src/util/xml.rs b/src/util/xml.rs index 3e7d0de..a132534 100644 --- a/src/util/xml.rs +++ b/src/util/xml.rs @@ -13,6 +13,11 @@ pub trait ToXml: Sized { fn serialize(&self, events: &mut Vec>); } +pub trait FromXmlTag: FromXml { + const NAME: &'static str; + const NS: &'static str; +} + pub trait Parser: Sized { type Output;