diff options
| author | 2025-04-03 23:17:06 +0100 | |
|---|---|---|
| committer | 2025-04-03 23:17:06 +0100 | |
| commit | 1af59efbb312b680b742bb84198c6ba18a79ec31 (patch) | |
| tree | d024166e5520f3b83d25c1e0d48445bebe31534d | |
| parent | 20969bd8b9789c08303265ec263e02b5225348e6 (diff) | |
| download | luz-1af59efbb312b680b742bb84198c6ba18a79ec31.tar.gz luz-1af59efbb312b680b742bb84198c6ba18a79ec31.tar.bz2 luz-1af59efbb312b680b742bb84198c6ba18a79ec31.zip | |
feat(stanza): xep-0084: user avatar
Diffstat (limited to '')
| -rw-r--r-- | stanza/Cargo.toml | 1 | ||||
| -rw-r--r-- | stanza/src/lib.rs | 2 | ||||
| -rw-r--r-- | stanza/src/xep_0060/event.rs | 18 | ||||
| -rw-r--r-- | stanza/src/xep_0060/pubsub.rs | 18 | ||||
| -rw-r--r-- | stanza/src/xep_0084/data.rs | 30 | ||||
| -rw-r--r-- | stanza/src/xep_0084/metadata.rs | 106 | ||||
| -rw-r--r-- | stanza/src/xep_0084/mod.rs | 8 | 
7 files changed, 183 insertions, 0 deletions
| diff --git a/stanza/Cargo.toml b/stanza/Cargo.toml index d63703f..69fabc2 100644 --- a/stanza/Cargo.toml +++ b/stanza/Cargo.toml @@ -15,6 +15,7 @@ xep_0004 = []  xep_0030 = []  xep_0059 = []  xep_0060 = ["xep_0004", "dep:chrono"] +xep_0084 = []  xep_0115 = []  xep_0128 = ["xep_0004"]  xep_0131 = [] diff --git a/stanza/src/lib.rs b/stanza/src/lib.rs index 3ecace0..569b891 100644 --- a/stanza/src/lib.rs +++ b/stanza/src/lib.rs @@ -17,6 +17,8 @@ pub mod xep_0030;  pub mod xep_0059;  #[cfg(feature = "xep_0060")]  pub mod xep_0060; +#[cfg(feature = "xep_0084")] +pub mod xep_0084;  #[cfg(feature = "xep_0115")]  pub mod xep_0115;  #[cfg(feature = "xep_0131")] diff --git a/stanza/src/xep_0060/event.rs b/stanza/src/xep_0060/event.rs index 4ef5a6c..1be011d 100644 --- a/stanza/src/xep_0060/event.rs +++ b/stanza/src/xep_0060/event.rs @@ -8,6 +8,8 @@ use peanuts::{  };  use crate::xep_0004::X; +#[cfg(feature = "xep_0084")] +use crate::xep_0084;  #[cfg(feature = "xep_0172")]  use crate::xep_0172::{self, Nick}; @@ -296,6 +298,10 @@ impl IntoElement for Item {  pub enum Content {      #[cfg(feature = "xep_0172")]      Nick(Nick), +    #[cfg(feature = "xep_0084")] +    AvatarData(xep_0084::Data), +    #[cfg(feature = "xep_0084")] +    AvatarMetadata(xep_0084::Metadata),      Unknown(Element),  } @@ -304,6 +310,14 @@ impl FromElement for Content {          match element.identify() {              #[cfg(feature = "xep_0172")]              (Some(xep_0172::XMLNS), "nick") => Ok(Content::Nick(Nick::from_element(element)?)), +            #[cfg(feature = "xep_0084")] +            (Some(xep_0084::data::XMLNS), "data") => { +                Ok(Content::AvatarData(xep_0084::Data::from_element(element)?)) +            } +            #[cfg(feature = "xep_0084")] +            (Some(xep_0084::metadata::XMLNS), "metadata") => Ok(Content::AvatarMetadata( +                xep_0084::Metadata::from_element(element)?, +            )),              _ => Ok(Self::Unknown(element)),          }      } @@ -314,6 +328,10 @@ impl IntoElement for Content {          match self {              #[cfg(feature = "xep_0172")]              Content::Nick(nick) => nick.builder(), +            #[cfg(feature = "xep_0084")] +            Content::AvatarData(data) => data.builder(), +            #[cfg(feature = "xep_0084")] +            Content::AvatarMetadata(metadata) => metadata.builder(),              Content::Unknown(_e) => panic!("unknown content cannot be serialized"),          }      } diff --git a/stanza/src/xep_0060/pubsub.rs b/stanza/src/xep_0060/pubsub.rs index 25fc405..0f698dc 100644 --- a/stanza/src/xep_0060/pubsub.rs +++ b/stanza/src/xep_0060/pubsub.rs @@ -7,6 +7,8 @@ use peanuts::{  };  use crate::xep_0004::X; +#[cfg(feature = "xep_0084")] +use crate::xep_0084;  #[cfg(feature = "xep_0172")]  use crate::xep_0172::{self, Nick}; @@ -377,6 +379,10 @@ impl IntoElement for Item {  pub enum Content {      #[cfg(feature = "xep_0172")]      Nick(Nick), +    #[cfg(feature = "xep_0084")] +    AvatarData(xep_0084::Data), +    #[cfg(feature = "xep_0084")] +    AvatarMetadata(xep_0084::Metadata),      Unknown(Element),  } @@ -385,6 +391,14 @@ impl FromElement for Content {          match element.identify() {              #[cfg(feature = "xep_0172")]              (Some(xep_0172::XMLNS), "nick") => Ok(Content::Nick(Nick::from_element(element)?)), +            #[cfg(feature = "xep_0084")] +            (Some(xep_0084::data::XMLNS), "data") => { +                Ok(Content::AvatarData(xep_0084::Data::from_element(element)?)) +            } +            #[cfg(feature = "xep_0084")] +            (Some(xep_0084::metadata::XMLNS), "metadata") => Ok(Content::AvatarMetadata( +                xep_0084::Metadata::from_element(element)?, +            )),              _ => Ok(Self::Unknown(element)),          }      } @@ -395,6 +409,10 @@ impl IntoElement for Content {          match self {              #[cfg(feature = "xep_0172")]              Content::Nick(nick) => nick.builder(), +            #[cfg(feature = "xep_0084")] +            Content::AvatarData(data) => data.builder(), +            #[cfg(feature = "xep_0084")] +            Content::AvatarMetadata(metadata) => metadata.builder(),              Content::Unknown(_e) => panic!("unknown content cannot be serialized"),          }      } diff --git a/stanza/src/xep_0084/data.rs b/stanza/src/xep_0084/data.rs new file mode 100644 index 0000000..2a37df4 --- /dev/null +++ b/stanza/src/xep_0084/data.rs @@ -0,0 +1,30 @@ +use peanuts::{ +    element::{FromElement, IntoElement}, +    Element, +}; + +pub const XMLNS: &str = "urn:xmpp:avatar:data"; + +#[derive(Debug, Clone)] +pub struct Data(pub String); + +impl FromElement for Data { +    fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("data")?; +        element.check_namespace(XMLNS)?; + +        Ok(Self(element.pop_value_opt()?.unwrap_or_default())) +    } +} + +impl IntoElement for Data { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        let builder = Element::builder("data", Some(XMLNS)); + +        if self.0.is_empty() { +            builder +        } else { +            builder.push_text(self.0.clone()) +        } +    } +} diff --git a/stanza/src/xep_0084/metadata.rs b/stanza/src/xep_0084/metadata.rs new file mode 100644 index 0000000..c6a3fb4 --- /dev/null +++ b/stanza/src/xep_0084/metadata.rs @@ -0,0 +1,106 @@ +use peanuts::{ +    element::{FromElement, IntoElement}, +    Element, +}; + +pub const XMLNS: &str = "urn:xmpp:avatar:metadata"; + +#[derive(Debug, Clone)] +pub struct Metadata { +    pub info: Vec<Info>, +    pub pointers: Vec<Pointer>, +} + +impl FromElement for Metadata { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("metadata")?; +        element.check_namespace(XMLNS)?; + +        let info = element.pop_children()?; +        let pointers = element.pop_children()?; + +        Ok(Self { info, pointers }) +    } +} + +impl IntoElement for Metadata { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("metadata", Some(XMLNS)) +            .push_children(self.info.clone()) +            .push_children(self.pointers.clone()) +    } +} + +#[derive(Debug, Clone)] +pub struct Info { +    pub bytes: u32, +    pub height: Option<u16>, +    pub id: String, +    pub r#type: String, +    pub url: Option<String>, +    pub width: Option<u16>, +} + +impl FromElement for Info { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("info")?; +        element.check_namespace(XMLNS)?; + +        let bytes = element.attribute("bytes")?; +        let height = element.attribute_opt("height")?; +        let id = element.attribute("id")?; +        let r#type = element.attribute("type")?; +        let url = element.attribute_opt("url")?; +        let width = element.attribute_opt("width")?; + +        Ok(Self { +            bytes, +            height, +            id, +            r#type, +            url, +            width, +        }) +    } +} + +impl IntoElement for Info { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("info", Some(XMLNS)) +            .push_attribute("bytes", self.bytes) +            .push_attribute_opt("height", self.height) +            .push_attribute("id", self.id.clone()) +            .push_attribute("type", self.r#type.clone()) +            .push_attribute_opt("url", self.url.clone()) +            .push_attribute_opt("width", self.width) +    } +} + +#[derive(Debug, Clone)] +pub struct Pointer(pub PointerInner); + +impl FromElement for Pointer { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("pointer")?; +        element.check_namespace(XMLNS)?; + +        Ok(Self(PointerInner::Unsupported(element.pop_child_one()?))) +    } +} + +impl IntoElement for Pointer { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        let _builder = Element::builder("pointer", Some(XMLNS)); + +        match &self.0 { +            PointerInner::Unsupported(_element) => { +                panic!("cannot serialize unsupported PointerInner") +            } +        } +    } +} + +#[derive(Debug, Clone)] +pub enum PointerInner { +    Unsupported(Element), +} diff --git a/stanza/src/xep_0084/mod.rs b/stanza/src/xep_0084/mod.rs new file mode 100644 index 0000000..be7d5d7 --- /dev/null +++ b/stanza/src/xep_0084/mod.rs @@ -0,0 +1,8 @@ +pub use data::Data; +pub use metadata::Info; +pub use metadata::Metadata; +pub use metadata::Pointer; +pub use metadata::PointerInner; + +pub mod data; +pub mod metadata; | 
