stanza: new Stanza trait with .payloads method

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-09-29 23:52:03 +02:00
parent 70cba2279e
commit 2de10b53ae
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
5 changed files with 155 additions and 0 deletions

View file

@ -6,6 +6,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use crate::ns;
use crate::stanza::Stanza;
use crate::stanza_error::StanzaError;
use crate::util::error::Error;
use crate::Element;
@ -224,6 +225,21 @@ impl From<Iq> for Element {
}
}
impl Stanza for Iq {
fn payloads(&self) -> Box<dyn Iterator<Item = Element>> {
Box::new(
match &self.payload {
IqType::Get(elem) | IqType::Set(elem) | IqType::Result(Some(elem)) => {
Some(elem.clone())
}
IqType::Error(error) => Some(Into::into(error.clone())),
IqType::Result(None) => None,
}
.into_iter(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -33,6 +33,9 @@ pub mod ns;
#[macro_use]
mod util;
/// Generic Stanza trait
pub mod stanza;
/// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core
pub mod bind;
/// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core

View file

@ -5,6 +5,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use crate::ns;
use crate::stanza::Stanza;
use crate::util::error::Error;
use crate::Element;
use jid::Jid;
@ -238,6 +239,42 @@ impl From<Message> for Element {
}
}
impl Stanza for Message {
fn payloads(&self) -> Box<dyn Iterator<Item = Element>> {
Box::new(
self.bodies
.clone()
.into_iter()
.map(|(lang, body)| {
Element::builder("body", ns::DEFAULT_NS)
.attr(
"xml:lang",
match lang.as_ref() {
"" => None,
lang => Some(lang),
},
)
.append(body)
.build()
})
.chain(self.subjects.clone().into_iter().map(|(lang, subject)| {
Element::builder("subject", ns::DEFAULT_NS)
.attr(
"xml:lang",
match lang.as_ref() {
"" => None,
lang => Some(lang),
},
)
.append(subject)
.build()
}))
.chain(self.thread.clone().map(Into::into).into_iter())
.chain(self.payloads.clone().into_iter()),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -404,4 +441,31 @@ mod tests {
let elem2 = message.into();
assert_eq!(elem1, elem2);
}
#[test]
fn message_stanza_payloads() {
let mut message = Message::new(None);
message.thread = Some(Thread::from_str("thread-id").unwrap());
message.bodies = BTreeMap::new();
message
.bodies
.insert(String::from(""), Body::from_str("Body").unwrap());
message.payloads = vec![Element::builder("x", "urn:xmpp:example").build()];
let mut sorted: Vec<Element> = message.payloads().collect::<Vec<Element>>();
sorted.sort_by(|e1, e2| Ord::cmp(e1.name(), e2.name()));
let res: Vec<Element> = vec![
Element::builder("body", ns::DEFAULT_NS)
.attr("xml:lang", None::<String>)
.append(Body::from_str("Body").unwrap())
.build(),
Element::builder("thread", ns::DEFAULT_NS)
.append(String::from("thread-id"))
.build(),
Element::builder("x", "urn:xmpp:example").build(),
];
assert_eq!(sorted, res);
}
}

View file

@ -6,6 +6,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use crate::ns;
use crate::stanza::Stanza;
use crate::util::error::Error;
use jid::Jid;
use minidom::{Element, IntoAttributeValue};
@ -333,6 +334,42 @@ impl From<Presence> for Element {
}
}
impl Stanza for Presence {
fn payloads(&self) -> Box<dyn Iterator<Item = Element> + '_> {
Box::new(
self.statuses
.clone()
.into_iter()
.map(|(lang, status)| {
Element::builder("status", ns::DEFAULT_NS)
.attr(
"xml:lang",
match lang.as_ref() {
"" => None,
lang => Some(lang),
},
)
.append(status)
.build()
})
.chain(
if self.priority == 0 {
None
} else {
Some({
Element::builder("priority", ns::DEFAULT_NS)
.append(format!("{}", &self.priority))
.build()
})
}
.into_iter(),
)
.chain(self.show.as_ref().into_iter().cloned().map(Into::into))
.chain(self.payloads.clone().into_iter()),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -651,4 +688,25 @@ mod tests {
let elem: Element = presence.into();
assert_eq!(elem.attr("to"), Some("test@localhost/coucou"));
}
#[test]
fn presence_stanza_payloads() {
let presence = Presence::new(Type::None)
.with_priority(42)
.with_show(Show::Away)
.with_payloads(vec![Element::builder("x", "urn:xmpp:example").build()]);
let mut sorted: Vec<Element> = presence.payloads().collect::<Vec<Element>>();
sorted.sort_by(|e1, e2| Ord::cmp(e1.name(), e2.name()));
let res: Vec<Element> = vec![
Element::builder("priority", ns::DEFAULT_NS)
.append(String::from("42"))
.build(),
Show::Away.into(),
Element::builder("x", "urn:xmpp:example").build(),
];
assert_eq!(sorted, res);
}
}

14
parsers/src/stanza.rs Normal file
View file

@ -0,0 +1,14 @@
// Copyright (c) 2022 Maxime “pep” Buquet <pep@bouah.net>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// 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 minidom::Element;
use std::convert::TryFrom;
/// Generic trait for user libraries to use
pub trait Stanza: TryFrom<Element> + Into<Element> {
/// Returns an iterator over all children elements of the stanza
fn payloads(&self) -> Box<dyn Iterator<Item = Element> + '_>;
}