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 crate::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,
 28    "resume",
 29    bool
 30);
 31
 32generate_element!(
 33    /// Client request for enabling stream management.
 34    Enable, "enable", SM,
 35    attributes: [
 36        /// The preferred resumption time in seconds by the client.
 37        // TODO: should be the infinite integer set ≥ 1.
 38        max: Option<u32> = "max" => optional,
 39
 40        /// Whether the client wants to be allowed to resume the stream.
 41        resume: ResumeAttr = "resume" => default,
 42    ]
 43);
 44
 45impl Enable {
 46    /// Generates a new `<enable/>` element.
 47    pub fn new() -> Self {
 48        Enable {
 49            max: None,
 50            resume: ResumeAttr::False,
 51        }
 52    }
 53
 54    /// Sets the preferred resumption time in seconds.
 55    pub fn with_max(mut self, max: u32) -> Self {
 56        self.max = Some(max);
 57        self
 58    }
 59
 60    /// Asks for resumption to be possible.
 61    pub fn with_resume(mut self) -> Self {
 62        self.resume = ResumeAttr::True;
 63        self
 64    }
 65}
 66
 67generate_id!(
 68    /// A random identifier used for stream resumption.
 69    StreamId
 70);
 71
 72generate_element!(
 73    /// Server response once stream management is enabled.
 74    Enabled, "enabled", SM,
 75    attributes: [
 76        /// A random identifier used for stream resumption.
 77        id: Option<StreamId> = "id" => optional,
 78
 79        /// The preferred IP, domain, IP:port or domain:port location for
 80        /// resumption.
 81        location: Option<String> = "location" => optional,
 82
 83        /// The preferred resumption time in seconds by the server.
 84        // TODO: should be the infinite integer set ≥ 1.
 85        max: Option<u32> = "max" => optional,
 86
 87        /// Whether stream resumption is allowed.
 88        resume: ResumeAttr = "resume" => default,
 89    ]
 90);
 91
 92generate_element!(
 93    /// A stream management error happened.
 94    Failed, "failed", SM,
 95    attributes: [
 96        /// The last handled stanza.
 97        h: Option<u32> = "h" => optional,
 98    ],
 99    children: [
100        /// The error returned.
101        // XXX: implement the * handling.
102        error: Option<DefinedCondition> = ("*", XMPP_STANZAS) => DefinedCondition
103    ]
104);
105
106generate_empty_element!(
107    /// Requests the currently received stanzas by the other party.
108    R,
109    "r",
110    SM
111);
112
113generate_element!(
114    /// Requests a stream resumption.
115    Resume, "resume", SM,
116    attributes: [
117        /// The last handled stanza.
118        h: u32 = "h" => required,
119
120        /// The previous id given by the server on
121        /// [enabled](struct.Enabled.html).
122        previd: StreamId = "previd" => required,
123    ]
124);
125
126generate_element!(
127    /// The response by the server for a successfully resumed stream.
128    Resumed, "resumed", SM,
129    attributes: [
130        /// The last handled stanza.
131        h: u32 = "h" => required,
132
133        /// The previous id given by the server on
134        /// [enabled](struct.Enabled.html).
135        previd: StreamId = "previd" => required,
136    ]
137);
138
139// TODO: add support for optional and required.
140generate_empty_element!(
141    /// Represents availability of Stream Management in `<stream:features/>`.
142    StreamManagement,
143    "sm",
144    SM
145);
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use minidom::Element;
151    use try_from::TryFrom;
152
153    #[cfg(target_pointer_width = "32")]
154    #[test]
155    fn test_size() {
156        assert_size!(A, 4);
157        assert_size!(ResumeAttr, 1);
158        assert_size!(Enable, 12);
159        assert_size!(StreamId, 12);
160        assert_size!(Enabled, 36);
161        assert_size!(Failed, 12);
162        assert_size!(R, 0);
163        assert_size!(Resume, 16);
164        assert_size!(Resumed, 16);
165        assert_size!(StreamManagement, 0);
166    }
167
168    #[cfg(target_pointer_width = "64")]
169    #[test]
170    fn test_size() {
171        assert_size!(A, 4);
172        assert_size!(ResumeAttr, 1);
173        assert_size!(Enable, 12);
174        assert_size!(StreamId, 24);
175        assert_size!(Enabled, 64);
176        assert_size!(Failed, 12);
177        assert_size!(R, 0);
178        assert_size!(Resume, 32);
179        assert_size!(Resumed, 32);
180        assert_size!(StreamManagement, 0);
181    }
182
183    #[test]
184    fn a() {
185        let elem: Element = "<a xmlns='urn:xmpp:sm:3' h='5'".parse().unwrap();
186        let a = A::try_from(elem).unwrap();
187        assert_eq!(a.h, 5);
188    }
189
190    #[test]
191    fn stream_feature() {
192        let elem: Element = "<sm xmlns='urn:xmpp:sm:3'/>".parse().unwrap();
193        StreamManagement::try_from(elem).unwrap();
194    }
195
196    #[test]
197    fn resume() {
198        let elem: Element = "<enable xmlns='urn:xmpp:sm:3' resume='true'/>"
199            .parse()
200            .unwrap();
201        let enable = Enable::try_from(elem).unwrap();
202        assert_eq!(enable.max, None);
203        assert_eq!(enable.resume, ResumeAttr::True);
204
205        let elem: Element = "<enabled xmlns='urn:xmpp:sm:3' resume='true' id='coucou' max='600'/>"
206            .parse()
207            .unwrap();
208        let enabled = Enabled::try_from(elem).unwrap();
209        let previd = enabled.id.unwrap();
210        assert_eq!(enabled.resume, ResumeAttr::True);
211        assert_eq!(previd, StreamId(String::from("coucou")));
212        assert_eq!(enabled.max, Some(600));
213        assert_eq!(enabled.location, None);
214
215        let elem: Element = "<resume xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>"
216            .parse()
217            .unwrap();
218        let resume = Resume::try_from(elem).unwrap();
219        assert_eq!(resume.h, 5);
220        assert_eq!(resume.previd, previd);
221
222        let elem: Element = "<resumed xmlns='urn:xmpp:sm:3' h='5' previd='coucou'/>"
223            .parse()
224            .unwrap();
225        let resumed = Resumed::try_from(elem).unwrap();
226        assert_eq!(resumed.h, 5);
227        assert_eq!(resumed.previd, previd);
228    }
229}