From f63b780089064841bc8133e2e2c09d2e4594be32 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Fri, 20 Dec 2024 19:05:07 +0100 Subject: [PATCH] xmpp-parsers: Simplify PubSub Item using xso Now that we can have a single arbitrary payload, we can derive FromXml and AsXml on the Item. --- parsers/ChangeLog | 1 + parsers/src/openpgp.rs | 8 ++--- parsers/src/pubsub/event.rs | 25 +++++++++---- parsers/src/pubsub/mod.rs | 29 --------------- parsers/src/pubsub/pubsub.rs | 36 ++++++++++++++++--- parsers/src/util/macros.rs | 70 ------------------------------------ xmpp/src/pubsub/mod.rs | 1 - 7 files changed, 55 insertions(+), 115 deletions(-) diff --git a/parsers/ChangeLog b/parsers/ChangeLog index 4c268913d7f748629e4c4167afe8eb64acda6254..2b558bffb605b6bcdb5e02457b1db9ba43e86c5d 100644 --- a/parsers/ChangeLog +++ b/parsers/ChangeLog @@ -36,6 +36,7 @@ XXXX-YY-ZZ RELEASER fast::Tls0Rtt, legacy_omemo::IsPreKey, mam::Complete, sm::ResumeAttr (!476) - bookmarks::Conference and bookmarks2::Conference use ResourcePart to store the optional nickname instead of a String (!485) + - pubsub Item and pubsub#event Item are now distinct structs (!503) - message::Message id field is now Option instead of Option (!504) - message_correction::Replace id field is now Id instead of String (!504) diff --git a/parsers/src/openpgp.rs b/parsers/src/openpgp.rs index 04693dd9fbbc78cfa6dfd499d8f92d38e9844c36..b34e935bfd3107ca4c2c146173080f44dd092cc8 100644 --- a/parsers/src/openpgp.rs +++ b/parsers/src/openpgp.rs @@ -64,8 +64,8 @@ mod tests { use super::*; use crate::ns; use crate::pubsub::{ - pubsub::{Item as PubSubItem, Publish}, - Item, NodeName, + pubsub::{Item, Publish}, + NodeName, }; use core::str::FromStr; use minidom::Element; @@ -82,7 +82,7 @@ mod tests { let pubsub = Publish { node: NodeName(format!("{}:{}", ns::OX_PUBKEYS, "some-fingerprint")), - items: vec![PubSubItem(Item::new(None, None, Some(pubkey)))], + items: vec![Item::new(None, None, Some(pubkey))], }; println!("Foo2: {:?}", pubsub); } @@ -99,7 +99,7 @@ mod tests { let pubsub = Publish { node: NodeName("foo".to_owned()), - items: vec![PubSubItem(Item::new(None, None, Some(pubkeymeta)))], + items: vec![Item::new(None, None, Some(pubkeymeta))], }; println!("Foo2: {:?}", pubsub); } diff --git a/parsers/src/pubsub/event.rs b/parsers/src/pubsub/event.rs index 1ab36794ea5793e4ec5fa0f4461524e5d53bb984..47fbc77457a1e8947e0e846a8c1a6480900287bc 100644 --- a/parsers/src/pubsub/event.rs +++ b/parsers/src/pubsub/event.rs @@ -4,20 +4,33 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use xso::{AsXml, FromXml}; + use crate::data_forms::DataForm; use crate::date::DateTime; use crate::message::MessagePayload; use crate::ns; -use crate::pubsub::{Item as PubSubItem, ItemId, NodeName, Subscription, SubscriptionId}; +use crate::pubsub::{ItemId, NodeName, Subscription, SubscriptionId}; use jid::Jid; use minidom::Element; use xso::error::{Error, FromElementError}; -/// Event wrapper for a PubSub ``. -#[derive(Debug, Clone, PartialEq)] -pub struct Item(pub PubSubItem); - -impl_pubsub_item!(Item, PUBSUB_EVENT); +/// An event item from a PubSub node. +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] +#[xml(namespace = ns::PUBSUB_EVENT, name = "item")] +pub struct Item { + /// The identifier for this item, unique per node. + #[xml(attribute(default))] + pub id: Option, + + /// The JID of the entity who published this item. + #[xml(attribute(default))] + pub publisher: Option, + + /// The payload of this item, in an arbitrary namespace. + #[xml(element(default))] + pub payload: Option, +} /// Represents an event happening to a PubSub node. #[derive(Debug, Clone, PartialEq)] diff --git a/parsers/src/pubsub/mod.rs b/parsers/src/pubsub/mod.rs index 46d7f355605424b80773b42aa70ce40e39e011e0..923dbc3f888e26b7b5f5befce49903f585fc3fc4 100644 --- a/parsers/src/pubsub/mod.rs +++ b/parsers/src/pubsub/mod.rs @@ -18,7 +18,6 @@ pub use self::event::PubSubEvent; pub use self::owner::PubSubOwner; pub use self::pubsub::PubSub; -use jid::Jid; use minidom::Element; generate_id!( @@ -77,33 +76,5 @@ generate_attribute!( } ); -/// An item from a PubSub node. -#[derive(Debug, Clone, PartialEq)] -pub struct Item { - /// The identifier for this item, unique per node. - pub id: Option, - - /// The JID of the entity who published this item. - pub publisher: Option, - - /// The payload of this item, in an arbitrary namespace. - pub payload: Option, -} - -impl Item { - /// Create a new item, accepting only payloads implementing `PubSubPayload`. - pub fn new( - id: Option, - publisher: Option, - payload: Option

, - ) -> Item { - Item { - id, - publisher, - payload: payload.map(Into::into), - } - } -} - /// This trait should be implemented on any element which can be included as a PubSub payload. pub trait PubSubPayload: TryFrom + Into {} diff --git a/parsers/src/pubsub/pubsub.rs b/parsers/src/pubsub/pubsub.rs index 749ea6e668ac26723ef1cbf98114f4f84df9411e..2a8a45641f58fb8181293557b31236f01618a9dd 100644 --- a/parsers/src/pubsub/pubsub.rs +++ b/parsers/src/pubsub/pubsub.rs @@ -14,7 +14,7 @@ use crate::data_forms::DataForm; use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload}; use crate::ns; use crate::pubsub::{ - AffiliationAttribute, Item as PubSubItem, NodeName, Subscription, SubscriptionId, + AffiliationAttribute, ItemId, NodeName, PubSubPayload, Subscription, SubscriptionId, }; use jid::Jid; use minidom::Element; @@ -111,11 +111,37 @@ impl Items { } } -/// Response wrapper for a PubSub ``. -#[derive(Debug, Clone, PartialEq)] -pub struct Item(pub PubSubItem); +/// A requested item from a PubSub node. +#[derive(FromXml, AsXml, Debug, Clone, PartialEq)] +#[xml(namespace = ns::PUBSUB, name = "item")] +pub struct Item { + /// The identifier for this item, unique per node. + #[xml(attribute(default))] + pub id: Option, -impl_pubsub_item!(Item, PUBSUB); + /// The JID of the entity who published this item. + #[xml(attribute(default))] + pub publisher: Option, + + /// The payload of this item, in an arbitrary namespace. + #[xml(element(default))] + pub payload: Option, +} + +impl Item { + /// Create a new item, accepting only payloads implementing `PubSubPayload`. + pub fn new( + id: Option, + publisher: Option, + payload: Option

, + ) -> Item { + Item { + id, + publisher, + payload: payload.map(Into::into), + } + } +} /// The options associated to a subscription request. #[derive(FromXml, AsXml, Debug, PartialEq, Clone)] diff --git a/parsers/src/util/macros.rs b/parsers/src/util/macros.rs index e26bba83cd06ffa843f7f365e8057750a8ae436d..7cfb784054289d18d8fd1d2dc32ef831ba5d8cc5 100644 --- a/parsers/src/util/macros.rs +++ b/parsers/src/util/macros.rs @@ -408,73 +408,3 @@ macro_rules! assert_size ( assert_eq!(::core::mem::size_of::<$t>(), $sz); ); ); - -// TODO: move that to src/pubsub/mod.rs, once we figure out how to use macros from there. -macro_rules! impl_pubsub_item { - ($item:ident, $ns:ident) => { - impl ::core::convert::TryFrom for $item { - type Error = FromElementError; - - fn try_from(mut elem: minidom::Element) -> Result<$item, FromElementError> { - check_self!(elem, "item", $ns); - check_no_unknown_attributes!(elem, "item", ["id", "publisher"]); - let mut payloads = elem.take_contents_as_children().collect::>(); - let payload = payloads.pop(); - if !payloads.is_empty() { - return Err(Error::Other("More than a single payload in item element.").into()); - } - Ok($item(crate::pubsub::Item { - id: get_attr!(elem, "id", Option), - publisher: get_attr!(elem, "publisher", Option), - payload, - })) - } - } - - impl ::xso::FromXml for $item { - type Builder = ::xso::minidom_compat::FromEventsViaElement<$item>; - - fn from_events( - qname: ::xso::exports::rxml::QName, - attrs: ::xso::exports::rxml::AttrMap, - ) -> Result { - if qname.0 != crate::ns::$ns || qname.1 != "item" { - return Err(::xso::error::FromEventsError::Mismatch { name: qname, attrs }); - } - Self::Builder::new(qname, attrs) - } - } - - impl From<$item> for minidom::Element { - fn from(item: $item) -> minidom::Element { - minidom::Element::builder("item", ns::$ns) - .attr("id", item.0.id) - .attr("publisher", item.0.publisher) - .append_all(item.0.payload) - .build() - } - } - - impl ::xso::AsXml for $item { - type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>; - - fn as_xml_iter(&self) -> Result, ::xso::error::Error> { - ::xso::minidom_compat::AsItemsViaElement::new(self.clone()) - } - } - - impl ::core::ops::Deref for $item { - type Target = crate::pubsub::Item; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl ::core::ops::DerefMut for $item { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - }; -} diff --git a/xmpp/src/pubsub/mod.rs b/xmpp/src/pubsub/mod.rs index a82de045fd047916008ccb1bd8b84495b8dadf4f..e7fcdbac1866e68897662b002a53fe9edf71b8db 100644 --- a/xmpp/src/pubsub/mod.rs +++ b/xmpp/src/pubsub/mod.rs @@ -123,7 +123,6 @@ pub(crate) async fn handle_iq_result( let mut new_room_list: Vec = Vec::new(); for item in items.items { - let item = item.0; let jid = BareJid::from_str(&item.id.clone().unwrap().0).unwrap(); let payload = item.payload.clone().unwrap(); match bookmarks2::Conference::try_from(payload) {