From a65ea89ce11b49c1e01199664ef6d79fdcd75604 Mon Sep 17 00:00:00 2001 From: Nikita Vilunov Date: Mon, 20 Mar 2023 17:25:14 +0100 Subject: [PATCH] feat(xmpp): make presence polymorphic wrt any fields --- src/projections/xmpp/mod.rs | 2 +- src/projections/xmpp/proto.rs | 6 ++-- src/protos/xmpp/client.rs | 66 +++++++++++++++++++++++++---------- src/util/xml.rs | 3 ++ src/util/xml/ignore.rs | 62 ++++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 22 deletions(-) create mode 100644 src/util/xml/ignore.rs diff --git a/src/projections/xmpp/mod.rs b/src/projections/xmpp/mod.rs index d9fc50b..846d249 100644 --- a/src/projections/xmpp/mod.rs +++ b/src/projections/xmpp/mod.rs @@ -337,7 +337,7 @@ async fn socket_final( proto::ClientPacket::Message(_) => todo!(), proto::ClientPacket::Presence(p) => { let mut events = vec![]; - let response = Presence { + let response = Presence::<()> { to: Some("darova@localhost/kek".to_string()), from: Some("darova@localhost/kek".to_string()), ..Default::default() diff --git a/src/projections/xmpp/proto.rs b/src/projections/xmpp/proto.rs index 261d3f4..2337868 100644 --- a/src/projections/xmpp/proto.rs +++ b/src/projections/xmpp/proto.rs @@ -72,7 +72,7 @@ impl Parser for IqClientBodyParser { pub enum ClientPacket { Iq(Iq), Message(Message), - Presence(Presence), + Presence(Presence), } #[derive(From)] @@ -91,7 +91,7 @@ enum ClientPacketParserInner { Initial, IqV( as FromXml>::P), MessageV(::P), - PresenceV(::P), + PresenceV( as FromXml>::P), } impl Parser for ClientPacketParser { @@ -111,7 +111,7 @@ impl Parser for ClientPacketParser { let name = bytes.name(); match_parser!(ClientPacketParser, name, namespace, event; Iq::, - Presence, + Presence::, Message ) } diff --git a/src/protos/xmpp/client.rs b/src/protos/xmpp/client.rs index daf384b..868fc78 100644 --- a/src/protos/xmpp/client.rs +++ b/src/protos/xmpp/client.rs @@ -342,13 +342,27 @@ impl ToXml for Iq { } } -#[derive(PartialEq, Eq, Debug, Default)] -pub struct Presence { +#[derive(PartialEq, Eq, Debug)] +pub struct Presence { pub to: Option, pub from: Option, pub priority: Option, pub show: Option, pub status: Vec, + pub custom: Vec, +} + +impl Default for Presence { + fn default() -> Self { + Self { + to: Default::default(), + from: Default::default(), + priority: Default::default(), + show: Default::default(), + status: Default::default(), + custom: Default::default(), + } + } } #[derive(PartialEq, Eq, Debug)] @@ -389,20 +403,21 @@ impl PresenceShow { } #[derive(From)] -pub struct PresenceParser(PresenceParserInner); -enum PresenceParserInner { +pub struct PresenceParser(PresenceParserInner); +enum PresenceParserInner { Initial, - InPresence(Presence), - InPriority(Presence), - InPriorityEnd(Presence), - InShow(Presence), - InShowEnd(Presence), - InStatus(Presence), - InStatusEnd(Presence), + InPresence(Presence), + InPriority(Presence), + InPriorityEnd(Presence), + InShow(Presence), + InShowEnd(Presence), + InStatus(Presence), + InStatusEnd(Presence), + InCustom(Presence, T::P), } -impl Parser for PresenceParser { - type Output = Result; +impl Parser for PresenceParser { + type Output = Result>; fn consume<'a>( self: Self, @@ -425,8 +440,11 @@ impl Parser for PresenceParser { b"priority" => { Continuation::Continue(PresenceParserInner::InPriority(p).into()) } - _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), + _ => PresenceParser(PresenceParserInner::InCustom(p, T::parse())) + .consume(namespace, event), }, + Event::Empty(_) => PresenceParser(PresenceParserInner::InCustom(p, T::parse())) + .consume(namespace, event), Event::End(_) => Continuation::Final(Ok(p)), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), }, @@ -489,24 +507,36 @@ impl Parser for PresenceParser { Event::End(_) => Continuation::Continue(PresenceParserInner::InPresence(p).into()), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), }, + PresenceParserInner::InCustom(mut p, c) => match c.consume(namespace, event) { + Continuation::Final(Ok(res)) => { + p.custom.push(res); + Continuation::Continue(PresenceParserInner::InPresence(p).into()) + } + Continuation::Final(Err(err)) => Continuation::Final(Err(ffail!( + "Failed to parse custom presence element: {err}" + ))), + Continuation::Continue(c) => { + Continuation::Continue(PresenceParserInner::InCustom(p, c).into()) + } + }, } } } -impl FromXml for Presence { - type P = PresenceParser; +impl FromXml for Presence { + type P = PresenceParser; fn parse() -> Self::P { PresenceParserInner::Initial.into() } } -impl FromXmlTag for Presence { +impl FromXmlTag for Presence { const NAME: &'static str = "presence"; const NS: &'static str = XMLNS; } -impl ToXml for Presence { +impl ToXml for Presence { fn serialize(&self, events: &mut Vec>) { let mut start = BytesStart::new("presence"); if let Some(ref to) = self.to { diff --git a/src/util/xml.rs b/src/util/xml.rs index 91ba0f0..98f48a3 100644 --- a/src/util/xml.rs +++ b/src/util/xml.rs @@ -3,6 +3,9 @@ use quick_xml::name::ResolveResult; use crate::prelude::Result; +mod ignore; +pub use ignore::Ignore; + pub trait FromXml: Sized { type P: Parser>; diff --git a/src/util/xml/ignore.rs b/src/util/xml/ignore.rs new file mode 100644 index 0000000..342e51e --- /dev/null +++ b/src/util/xml/ignore.rs @@ -0,0 +1,62 @@ +use super::*; +use derive_more::From; + +#[derive(Default, Debug, PartialEq, Eq)] +pub struct Ignore; + +#[derive(From)] +pub struct IgnoreParser(IgnoreParserInner); + +enum IgnoreParserInner { + Initial, + InTag { name: Vec, depth: u8 }, +} + +impl Parser for IgnoreParser { + type Output = Result; + + fn consume<'a>( + self: Self, + namespace: ResolveResult, + event: &Event<'a>, + ) -> Continuation { + match self.0 { + IgnoreParserInner::Initial => match event { + Event::Start(bytes) => { + let name = bytes.name().0.to_owned(); + Continuation::Continue(IgnoreParserInner::InTag { name, depth: 0 }.into()) + } + Event::Empty(_) => Continuation::Final(Ok(Ignore)), + _ => Continuation::Final(Ok(Ignore)), + }, + IgnoreParserInner::InTag { name, depth } => match event { + Event::End(bytes) if name == bytes.name().0 => { + if depth == 0 { + Continuation::Final(Ok(Ignore)) + } else { + Continuation::Continue( + IgnoreParserInner::InTag { + name, + depth: depth - 1, + } + .into(), + ) + } + } + _ => Continuation::Final(Ok(Ignore)), + }, + } + } +} + +impl FromXml for Ignore { + type P = IgnoreParser; + + fn parse() -> Self::P { + IgnoreParserInner::Initial.into() + } +} + +impl ToXml for () { + fn serialize(&self, events: &mut Vec>) {} +}