presence: Stop parsing payloads automatically.

This commit is contained in:
Emmanuel Gil Peyrot 2017-05-18 23:32:44 +01:00
parent fe8dccd5df
commit 0ad6893d52

View file

@ -53,6 +53,34 @@ pub enum PresencePayload {
ECaps2(ECaps2), ECaps2(ECaps2),
} }
impl<'a> TryFrom<&'a Element> for PresencePayload {
type Error = Error;
fn try_from(elem: &'a Element) -> Result<PresencePayload, Error> {
Ok(match (elem.name().as_ref(), elem.ns().unwrap().as_ref()) {
("error", ns::JABBER_CLIENT) => PresencePayload::StanzaError(StanzaError::try_from(elem)?),
// XEP-0203
("delay", ns::DELAY) => PresencePayload::Delay(Delay::try_from(elem)?),
// XEP-0390
("c", ns::ECAPS2) => PresencePayload::ECaps2(ECaps2::try_from(elem)?),
_ => return Err(Error::ParseError("Unknown presence payload."))
})
}
}
impl<'a> Into<Element> for &'a PresencePayload {
fn into(self) -> Element {
match *self {
PresencePayload::StanzaError(ref stanza_error) => stanza_error.into(),
PresencePayload::Delay(ref delay) => delay.into(),
PresencePayload::ECaps2(ref ecaps2) => ecaps2.into(),
}
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum PresenceType { pub enum PresenceType {
/// This value is not an acceptable 'type' attribute, it is only used /// This value is not an acceptable 'type' attribute, it is only used
@ -107,12 +135,6 @@ impl IntoAttributeValue for PresenceType {
} }
} }
#[derive(Debug, Clone)]
pub enum PresencePayloadType {
XML(Element),
Parsed(PresencePayload),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Presence { pub struct Presence {
pub from: Option<Jid>, pub from: Option<Jid>,
@ -122,7 +144,7 @@ pub struct Presence {
pub show: Option<Show>, pub show: Option<Show>,
pub statuses: BTreeMap<Lang, Status>, pub statuses: BTreeMap<Lang, Status>,
pub priority: Priority, pub priority: Priority,
pub payloads: Vec<PresencePayloadType>, pub payloads: Vec<Element>,
} }
impl<'a> TryFrom<&'a Element> for Presence { impl<'a> TryFrom<&'a Element> for Presence {
@ -179,19 +201,7 @@ impl<'a> TryFrom<&'a Element> for Presence {
} }
priority = Some(Priority::from_str(elem.text().as_ref())?); priority = Some(Priority::from_str(elem.text().as_ref())?);
} else { } else {
let payload = if let Ok(stanza_error) = StanzaError::try_from(elem) { payloads.push(elem.clone());
Some(PresencePayload::StanzaError(stanza_error))
} else if let Ok(delay) = Delay::try_from(elem) {
Some(PresencePayload::Delay(delay))
} else if let Ok(ecaps2) = ECaps2::try_from(elem) {
Some(PresencePayload::ECaps2(ecaps2))
} else {
None
};
payloads.push(match payload {
Some(payload) => PresencePayloadType::Parsed(payload),
None => PresencePayloadType::XML(elem.clone()),
});
} }
} }
Ok(Presence { Ok(Presence {
@ -207,16 +217,6 @@ impl<'a> TryFrom<&'a Element> for Presence {
} }
} }
impl<'a> Into<Element> for &'a PresencePayload {
fn into(self) -> Element {
match *self {
PresencePayload::StanzaError(ref stanza_error) => stanza_error.into(),
PresencePayload::Delay(ref delay) => delay.into(),
PresencePayload::ECaps2(ref ecaps2) => ecaps2.into(),
}
}
}
impl<'a> Into<Element> for &'a Presence { impl<'a> Into<Element> for &'a Presence {
fn into(self) -> Element { fn into(self) -> Element {
let mut stanza = Element::builder("presence") let mut stanza = Element::builder("presence")
@ -225,13 +225,20 @@ impl<'a> Into<Element> for &'a Presence {
.attr("to", self.to.clone().and_then(|value| Some(String::from(value)))) .attr("to", self.to.clone().and_then(|value| Some(String::from(value))))
.attr("id", self.id.clone()) .attr("id", self.id.clone())
.attr("type", self.type_.clone()) .attr("type", self.type_.clone())
.append(self.show.clone())
.append(self.statuses.iter().map(|(lang, status)| {
Element::builder("status")
.attr("xml:lang", match lang.as_ref() {
"" => None,
lang => Some(lang),
})
.append(status.clone())
.build()
}).collect::<Vec<_>>())
.append(if self.priority == 0 { None } else { Some(format!("{}", self.priority)) })
.build(); .build();
for child in self.payloads.clone() { for child in self.payloads.clone() {
let elem = match child { stanza.append_child(child);
PresencePayloadType::XML(elem) => elem,
PresencePayloadType::Parsed(payload) => (&payload).into(),
};
stanza.append_child(elem);
} }
stanza stanza
} }
@ -241,7 +248,6 @@ impl<'a> Into<Element> for &'a Presence {
mod tests { mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use super::*; use super::*;
use ns;
#[test] #[test]
fn test_simple() { fn test_simple() {
@ -364,11 +370,8 @@ mod tests {
fn test_unknown_child() { fn test_unknown_child() {
let elem: Element = "<presence xmlns='jabber:client'><test xmlns='invalid'/></presence>".parse().unwrap(); let elem: Element = "<presence xmlns='jabber:client'><test xmlns='invalid'/></presence>".parse().unwrap();
let presence = Presence::try_from(&elem).unwrap(); let presence = Presence::try_from(&elem).unwrap();
if let PresencePayloadType::XML(ref payload) = presence.payloads[0] { let payload = &presence.payloads[0];
assert!(payload.is("test", "invalid")); assert!(payload.is("test", "invalid"));
} else {
panic!("Did successfully parse an invalid element.");
}
} }
#[test] #[test]
@ -398,16 +401,17 @@ mod tests {
#[test] #[test]
fn test_serialise_status() { fn test_serialise_status() {
let status = Status::from("Hello world!"); let status = Status::from("Hello world!");
let payloads = vec!(PresencePayloadType::Parsed(PresencePayload::Status(status))); let mut statuses = BTreeMap::new();
statuses.insert(String::from(""), status);
let presence = Presence { let presence = Presence {
from: None, from: None,
to: None, to: None,
id: None, id: None,
type_: PresenceType::Unavailable, type_: PresenceType::Unavailable,
show: None, show: None,
statuses: BTreeMap::new(), statuses: statuses,
priority: 0i8, priority: 0i8,
payloads: payloads, payloads: vec!(),
}; };
let elem: Element = (&presence).into(); let elem: Element = (&presence).into();
assert!(elem.is("presence", ns::JABBER_CLIENT)); assert!(elem.is("presence", ns::JABBER_CLIENT));