pubsub: Make Item common to both pubsub and pubsub#event namespaces.

This commit is contained in:
Emmanuel Gil Peyrot 2019-01-27 18:57:25 +01:00
parent d60feffc22
commit d811c10ed3
4 changed files with 85 additions and 92 deletions

View file

@ -8,66 +8,16 @@ use crate::data_forms::DataForm;
use crate::date::DateTime;
use crate::util::error::Error;
use crate::ns;
use crate::pubsub::{ItemId, NodeName, Subscription, SubscriptionId, PubSubPayload};
use crate::pubsub::{ItemId, NodeName, Subscription, SubscriptionId, Item as PubSubItem};
use jid::Jid;
use minidom::Element;
use try_from::TryFrom;
/// One PubSub item from a node.
/// Event wrapper for a PubSub `<item/>`.
#[derive(Debug, Clone)]
pub struct Item {
/// The identifier for this item, unique per node.
pub id: Option<ItemId>,
pub struct Item(pub PubSubItem);
/// The JID of the entity who published this item.
pub publisher: Option<Jid>,
/// The actual content of this item.
pub payload: Option<Element>,
}
impl TryFrom<Element> for Item {
type Err = Error;
fn try_from(elem: Element) -> Result<Item, Error> {
check_self!(elem, "item", PUBSUB_EVENT);
check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
let mut payloads = elem.children().cloned().collect::<Vec<_>>();
let payload = payloads.pop();
if !payloads.is_empty() {
return Err(Error::ParseError(
"More than a single payload in item element.",
));
}
Ok(Item {
payload,
id: get_attr!(elem, "id", optional),
publisher: get_attr!(elem, "publisher", optional),
})
}
}
impl From<Item> for Element {
fn from(item: Item) -> Element {
Element::builder("item")
.ns(ns::PUBSUB_EVENT)
.attr("id", item.id)
.attr("publisher", item.publisher)
.append(item.payload)
.build()
}
}
impl Item {
/// Create a new item event, accepting only payloads implementing `PubSubPayload`.
pub fn new<P: PubSubPayload>(id: Option<ItemId>, publisher: Option<Jid>, payload: Option<P>) -> Item {
Item {
id,
publisher,
payload: payload.map(|payload| payload.into()),
}
}
}
impl_pubsub_item!(Item, PUBSUB_EVENT);
/// Represents an event happening to a PubSub node.
#[derive(Debug, Clone)]

View file

@ -13,6 +13,8 @@ pub mod pubsub;
pub use self::event::PubSubEvent;
pub use self::pubsub::PubSub;
use crate::{Jid, Element};
generate_id!(
/// The name of a PubSub node, used to identify it on a JID.
NodeName
@ -46,5 +48,29 @@ generate_attribute!(
}, Default = None
);
/// An item from a PubSub node.
#[derive(Debug, Clone)]
pub struct Item {
/// The identifier for this item, unique per node.
pub id: Option<ItemId>,
/// The JID of the entity who published this item.
pub publisher: Option<Jid>,
/// The payload of this item, in an arbitrary namespace.
pub payload: Option<Element>,
}
impl Item {
/// Create a new item, accepting only payloads implementing `PubSubPayload`.
pub fn new<P: PubSubPayload>(id: Option<ItemId>, publisher: Option<Jid>, payload: Option<P>) -> Item {
Item {
id,
publisher,
payload: payload.map(|payload| payload.into()),
}
}
}
/// This trait should be implemented on any element which can be included as a PubSub payload.
pub trait PubSubPayload: crate::TryFrom<crate::Element> + Into<crate::Element> {}

View file

@ -8,7 +8,7 @@ use crate::data_forms::DataForm;
use crate::util::error::Error;
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::ns;
use crate::pubsub::{ItemId, NodeName, Subscription, SubscriptionId};
use crate::pubsub::{NodeName, Subscription, SubscriptionId, Item as PubSubItem};
use jid::Jid;
use minidom::Element;
use try_from::TryFrom;
@ -113,45 +113,11 @@ generate_element!(
]
);
/// An item from a PubSub node.
/// Response wrapper for a PubSub `<item/>`.
#[derive(Debug, Clone)]
pub struct Item {
/// The payload of this item, in an arbitrary namespace.
pub payload: Option<Element>,
pub struct Item(pub PubSubItem);
/// The 'id' attribute of this item.
pub id: Option<ItemId>,
}
impl TryFrom<Element> for Item {
type Err = Error;
fn try_from(elem: Element) -> Result<Item, Error> {
check_self!(elem, "item", PUBSUB);
check_no_unknown_attributes!(elem, "item", ["id"]);
let mut payloads = elem.children().cloned().collect::<Vec<_>>();
let payload = payloads.pop();
if !payloads.is_empty() {
return Err(Error::ParseError(
"More than a single payload in item element.",
));
}
Ok(Item {
payload,
id: get_attr!(elem, "id", optional),
})
}
}
impl From<Item> for Element {
fn from(item: Item) -> Element {
Element::builder("item")
.ns(ns::PUBSUB)
.attr("id", item.id)
.append(item.payload)
.build()
}
}
impl_pubsub_item!(Item, PUBSUB);
generate_element!(
/// The options associated to a subscription request.

View file

@ -596,3 +596,54 @@ macro_rules! assert_size (
assert_eq!(::std::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 crate::TryFrom<crate::Element> for $item {
type Err = Error;
fn try_from(elem: crate::Element) -> Result<$item, Error> {
check_self!(elem, "item", $ns);
check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
let mut payloads = elem.children().cloned().collect::<Vec<_>>();
let payload = payloads.pop();
if !payloads.is_empty() {
return Err(Error::ParseError(
"More than a single payload in item element.",
));
}
Ok($item(crate::pubsub::Item {
id: get_attr!(elem, "id", optional),
publisher: get_attr!(elem, "publisher", optional),
payload,
}))
}
}
impl From<$item> for crate::Element {
fn from(item: $item) -> crate::Element {
crate::Element::builder("item")
.ns(ns::$ns)
.attr("id", item.0.id)
.attr("publisher", item.0.publisher)
.append(item.0.payload)
.build()
}
}
impl ::std::ops::Deref for $item {
type Target = crate::pubsub::Item;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ::std::ops::DerefMut for $item {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
}