sm.rs

  1// Copyright (c) 2018 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7use stanza_error::DefinedCondition;
  8
  9generate_element!(
 10    /// Acknowledgement of the currently received stanzas.
 11    A, "a", SM,
 12    attributes: [
 13        /// The last handled stanza.
 14        h: u32 = "h" => required,
 15    ]
 16);
 17
 18impl A {
 19    /// Generates a new `<a/>` element.
 20    pub fn new(h: u32) -> A {
 21        A { h }
 22    }
 23}
 24
 25generate_attribute!(
 26    /// Whether to allow resumption of a previous stream.
 27    ResumeAttr, "resume", bool
 28);
 29
 30generate_element!(
 31    /// Client request for enabling stream management.
 32    Enable, "enable", SM,
 33    attributes: [
 34        /// The preferred resumption time in seconds by the client.
 35        // TODO: should be the infinite integer set ≥ 1.
 36        max: Option<u32> = "max" => optional,
 37
 38        /// Whether the client wants to be allowed to resume the stream.
 39        resume: ResumeAttr = "resume" => default,
 40    ]
 41);
 42
 43impl Enable {
 44    /// Generates a new `<enable/>` element.
 45    pub fn new() -> Self {
 46        Enable {
 47            max: None,
 48            resume: ResumeAttr::False,
 49        }
 50    }
 51
 52    /// Sets the preferred resumption time in seconds.
 53    pub fn with_max(mut self, max: u32) -> Self {
 54        self.max = Some(max);
 55        self
 56    }
 57
 58    /// Asks for resumption to be possible.
 59    pub fn with_resume(mut self) -> Self {
 60        self.resume = ResumeAttr::True;
 61        self
 62    }
 63}
 64
 65generate_id!(
 66    /// A random identifier used for stream resumption.
 67    StreamId
 68);
 69
 70generate_element!(
 71    /// Server response once stream management is enabled.
 72    Enabled, "enabled", SM,
 73    attributes: [
 74        /// A random identifier used for stream resumption.
 75        id: Option<StreamId> = "id" => optional,
 76
 77        /// The preferred IP, domain, IP:port or domain:port location for
 78        /// resumption.
 79        location: Option<String> = "location" => optional,
 80
 81        /// The preferred resumption time in seconds by the server.
 82        // TODO: should be the infinite integer set ≥ 1.
 83        max: Option<u32> = "max" => optional,
 84
 85        /// Whether stream resumption is allowed.
 86        resume: ResumeAttr = "resume" => default,
 87    ]
 88);
 89
 90generate_element!(
 91    /// A stream management error happened.
 92    Failed, "failed", SM,
 93    attributes: [
 94        /// The last handled stanza.
 95        h: Option<u32> = "h" => optional,
 96    ],
 97    children: [
 98        /// The error returned.
 99        // XXX: implement the * handling.
100        error: Option<DefinedCondition> = ("*", XMPP_STANZAS) => DefinedCondition
101    ]
102);
103
104generate_empty_element!(
105    /// Requests the currently received stanzas by the other party.
106    R, "r", SM
107);
108
109generate_element!(
110    /// Requests a stream resumption.
111    Resume, "resume", SM,
112    attributes: [
113        /// The last handled stanza.
114        h: u32 = "h" => required,
115
116        /// The previous id given by the server on
117        /// [enabled](struct.Enabled.html).
118        previd: StreamId = "previd" => required,
119    ]
120);
121
122generate_element!(
123    /// The response by the server for a successfully resumed stream.
124    Resumed, "resumed", SM,
125    attributes: [
126        /// The last handled stanza.
127        h: u32 = "h" => required,
128
129        /// The previous id given by the server on
130        /// [enabled](struct.Enabled.html).
131        previd: StreamId = "previd" => required,
132    ]
133);
134
135// TODO: add support for optional and required.
136generate_empty_element!(
137    /// Represents availability of Stream Management in `<stream:features/>`.
138    StreamManagement, "sm", SM
139);
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use try_from::TryFrom;
145    use minidom::Element;
146
147    #[test]
148    fn test_size() {
149        assert_size!(A, 4);
150        assert_size!(ResumeAttr, 1);
151        assert_size!(Enable, 12);
152        assert_size!(StreamId, 24);
153        assert_size!(Enabled, 64);
154        assert_size!(Failed, 12);
155        assert_size!(R, 0);
156        assert_size!(Resume, 32);
157        assert_size!(Resumed, 32);
158        assert_size!(StreamManagement, 0);
159    }
160
161    #[test]
162    fn a() {
163        let elem: Element = "<a xmlns='urn:xmpp:sm:3' h='5'".parse().unwrap();
164        let a = A::try_from(elem).unwrap();
165        assert_eq!(a.h, 5);
166    }
167
168    #[test]
169    fn stream_feature() {
170        let elem: Element = "<sm xmlns='urn:xmpp:sm:3'/>".parse().unwrap();
171        StreamManagement::try_from(elem).unwrap();
172    }
173
174    #[test]
175    fn resume() {
176        let elem: Element = "<enable xmlns='urn:xmpp:sm:3' resume='true'/>".parse().unwrap();
177        let enable = Enable::try_from(elem).unwrap();
178        assert_eq!(enable.max, None);
179        assert_eq!(enable.resume, ResumeAttr::True);
180
181        let elem: Element = "<enabled xmlns='urn:xmpp:sm:3' resume='true' id='coucou' max='600'/>".parse().unwrap();
182        let enabled = Enabled::try_from(elem).unwrap();
183        let previd = enabled.id.unwrap();
184        assert_eq!(enabled.resume, ResumeAttr::True);
185        assert_eq!(previd, StreamId(String::from("coucou")));
186        assert_eq!(enabled.max, Some(600));
187        assert_eq!(enabled.location, None);
188
189        let elem: Element = "<resume xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>".parse().unwrap();
190        let resume = Resume::try_from(elem).unwrap();
191        assert_eq!(resume.h, 5);
192        assert_eq!(resume.previd, previd);
193
194        let elem: Element = "<resumed xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>".parse().unwrap();
195        let resumed = Resumed::try_from(elem).unwrap();
196        assert_eq!(resumed.h, 5);
197        assert_eq!(resumed.previd, previd);
198    }
199}