diff options
| author | 2025-04-30 14:41:40 +0100 | |
|---|---|---|
| committer | 2025-04-30 16:15:15 +0100 | |
| commit | 74e5ab6702bbbe292fcb38ccb97036ce5b376956 (patch) | |
| tree | 54416ab9cb9794a46f42a56a38e0a05abf354ae4 /stanza | |
| parent | 1f1f267df88638229f09b875e72fd118c08a7ae7 (diff) | |
| download | luz-74e5ab6702bbbe292fcb38ccb97036ce5b376956.tar.gz luz-74e5ab6702bbbe292fcb38ccb97036ce5b376956.tar.bz2 luz-74e5ab6702bbbe292fcb38ccb97036ce5b376956.zip | |
feat(stanza): XRD
Diffstat (limited to '')
| -rw-r--r-- | stanza/Cargo.toml | 1 | ||||
| -rw-r--r-- | stanza/src/lib.rs | 2 | ||||
| -rw-r--r-- | stanza/src/xep_0156.rs | 233 | 
3 files changed, 236 insertions, 0 deletions
| diff --git a/stanza/Cargo.toml b/stanza/Cargo.toml index 2832ed6..54577ff 100644 --- a/stanza/Cargo.toml +++ b/stanza/Cargo.toml @@ -20,6 +20,7 @@ xep_0084 = []  xep_0115 = []  xep_0128 = ["xep_0004"]  xep_0131 = [] +xep_0156 = ["dep:chrono"]  xep_0172 = []  xep_0199 = []  xep_0203 = ["dep:chrono"] diff --git a/stanza/src/lib.rs b/stanza/src/lib.rs index 5e30cd0..8f8d430 100644 --- a/stanza/src/lib.rs +++ b/stanza/src/lib.rs @@ -25,6 +25,8 @@ pub mod xep_0084;  pub mod xep_0115;  #[cfg(feature = "xep_0131")]  pub mod xep_0131; +#[cfg(feature = "xep_0156")] +pub mod xep_0156;  #[cfg(feature = "xep_0172")]  pub mod xep_0172;  #[cfg(feature = "xep_0199")] diff --git a/stanza/src/xep_0156.rs b/stanza/src/xep_0156.rs new file mode 100644 index 0000000..ad22f7e --- /dev/null +++ b/stanza/src/xep_0156.rs @@ -0,0 +1,233 @@ +use chrono::{DateTime, Utc}; +use peanuts::{ +    element::{FromElement, IntoElement}, +    Element, XML_NS, +}; + +pub const XMLNS: &str = "http://docs.oasis-open.org/ns/xri/xrd-1.0"; +pub const SIGNATURE_XMLNS: &str = "http://www.w3.org/2000/09/xmldsig#"; + +#[derive(Debug, Clone)] +pub struct XRD { +    pub id: Option<String>, +    pub expires: Option<Expires>, +    pub subject: Option<Subject>, +    pub aliases: Vec<Alias>, +    pub properties: Vec<Property>, +    pub links: Vec<Link>, +    pub signature: Vec<Signature>, +} + +impl FromElement for XRD { +    fn from_element(mut element: peanuts::Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("XRD")?; +        element.check_namespace(XMLNS)?; + +        let id = element.attribute_opt_namespaced("id", XML_NS)?; + +        let expires = element.child_opt()?; +        let subject = element.child_opt()?; +        let aliases = element.children()?; +        let properties = element.children()?; +        let links = element.children()?; +        let signature = element.children()?; + +        Ok(Self { +            id, +            expires, +            subject, +            aliases, +            properties, +            links, +            signature, +        }) +    } +} + +impl IntoElement for XRD { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("XRD", Some(XMLNS)) +            .push_attribute_opt_namespaced(XML_NS, "id", self.id.clone()) +            .push_child_opt(self.expires.clone()) +            .push_child_opt(self.subject.clone()) +            .push_children(self.aliases.clone()) +            .push_children(self.properties.clone()) +            .push_children(self.links.clone()) +            .push_children(self.signature.clone()) +    } +} + +#[derive(Debug, Clone)] +pub struct Expires(pub DateTime<Utc>); + +impl FromElement for Expires { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Expires")?; +        element.check_namespace(XMLNS)?; + +        Ok(Self(element.pop_value()?)) +    } +} + +impl IntoElement for Expires { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Expires", Some(XMLNS)) +            .push_text(self.0.format("%C%y-%m-%dT%H:%M:%S%.3f%:z")) +    } +} + +// anyURI +#[derive(Debug, Clone)] +pub struct Subject(pub String); + +impl FromElement for Subject { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Subject")?; +        element.check_namespace(XMLNS)?; + +        Ok(Self(element.pop_value()?)) +    } +} + +impl IntoElement for Subject { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Subject", Some(XMLNS)).push_text(self.0.clone()) +    } +} + +// anyURI +#[derive(Debug, Clone)] +pub struct Alias(pub String); + +impl FromElement for Alias { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Alias")?; +        element.check_namespace(XMLNS)?; + +        Ok(Self(element.pop_value()?)) +    } +} + +impl IntoElement for Alias { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Alias", Some(XMLNS)).push_text(self.0.clone()) +    } +} + +#[derive(Debug, Clone)] +pub struct Property { +    pub r#type: String, +    pub property: Option<String>, +} + +impl FromElement for Property { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Property")?; +        element.check_name(XMLNS)?; + +        let r#type = element.attribute("type")?; + +        let property = element.pop_value_opt()?; + +        Ok(Self { r#type, property }) +    } +} + +impl IntoElement for Property { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Property", Some(XMLNS)) +            .push_attribute("type", self.r#type.clone()) +            .push_text_opt(self.property.clone()) +    } +} + +#[derive(Debug, Clone)] +pub struct Link { +    pub rel: Option<String>, +    pub r#type: Option<String>, +    pub href: Option<String>, +    pub template: Option<String>, +    pub titles: Vec<Title>, +    pub properties: Vec<Property>, +} + +impl FromElement for Link { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Link")?; +        element.check_namespace(XMLNS)?; + +        let rel = element.attribute_opt("rel")?; +        let r#type = element.attribute_opt("type")?; +        let href = element.attribute_opt("href")?; +        let template = element.attribute_opt("template")?; + +        let titles = element.children()?; +        let properties = element.children()?; + +        Ok(Self { +            rel, +            r#type, +            href, +            template, +            titles, +            properties, +        }) +    } +} + +impl IntoElement for Link { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Link", Some(XMLNS)) +            .push_attribute_opt("rel", self.rel.clone()) +            .push_attribute_opt("type", self.r#type.clone()) +            .push_attribute_opt("href", self.href.clone()) +            .push_attribute_opt("template", self.template.clone()) +            .push_children(self.titles.clone()) +            .push_children(self.properties.clone()) +    } +} + +#[derive(Debug, Clone)] +pub struct Title { +    pub lang: Option<String>, +    pub title: String, +} + +impl FromElement for Title { +    fn from_element(mut element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Title")?; +        element.check_namespace(XMLNS)?; + +        let lang = element.attribute_opt_namespaced("lang", XML_NS)?; + +        let title = element.pop_value_opt()?.unwrap_or_default(); + +        Ok(Self { lang, title }) +    } +} + +impl IntoElement for Title { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Title", Some(XMLNS)) +            .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone()) +            .push_text(self.title.clone()) +    } +} + +#[derive(Debug, Clone, Copy)] +pub struct Signature; + +impl FromElement for Signature { +    fn from_element(element: Element) -> peanuts::element::DeserializeResult<Self> { +        element.check_name("Signature")?; +        element.check_namespace(SIGNATURE_XMLNS)?; + +        Ok(Self) +    } +} + +impl IntoElement for Signature { +    fn builder(&self) -> peanuts::element::ElementBuilder { +        Element::builder("Signature", Some(SIGNATURE_XMLNS)) +    } +} | 
