mirror of
https://gitlab.com/xmpp-rs/xmpp-rs.git
synced 2024-07-12 22:21:53 +00:00
parent
8db6b5602e
commit
2d7bf32ad4
5 changed files with 138 additions and 0 deletions
|
@ -1,3 +1,8 @@
|
|||
Version TODO:
|
||||
TODO Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
||||
* New parsers/serialisers:
|
||||
- Entity Time (XEP-0202).
|
||||
|
||||
Version 0.13.1:
|
||||
2019-04-12 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
||||
* Bugfixes:
|
||||
|
|
15
src/date.rs
15
src/date.rs
|
@ -15,6 +15,20 @@ use std::str::FromStr;
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct DateTime(ChronoDateTime<FixedOffset>);
|
||||
|
||||
impl DateTime {
|
||||
pub fn timezone(&self) -> FixedOffset {
|
||||
self.0.timezone()
|
||||
}
|
||||
|
||||
pub fn with_timezone(&self, tz: &FixedOffset) -> DateTime {
|
||||
DateTime(self.0.with_timezone(tz))
|
||||
}
|
||||
|
||||
pub fn format(&self, fmt: &str) -> String {
|
||||
format!("{}", self.0.format(fmt))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for DateTime {
|
||||
type Err = Error;
|
||||
|
||||
|
@ -41,6 +55,7 @@ mod tests {
|
|||
use chrono::{Datelike, Timelike};
|
||||
use std::error::Error as StdError;
|
||||
|
||||
// DateTime’s size doesn’t depend on the architecture.
|
||||
#[test]
|
||||
fn test_size() {
|
||||
assert_size!(DateTime, 16);
|
||||
|
|
|
@ -128,6 +128,9 @@ pub mod sm;
|
|||
/// XEP-0199: XMPP Ping
|
||||
pub mod ping;
|
||||
|
||||
/// XEP-0202: Entity Time
|
||||
pub mod time;
|
||||
|
||||
/// XEP-0203: Delayed Delivery
|
||||
pub mod delay;
|
||||
|
||||
|
|
|
@ -112,6 +112,9 @@ pub const SM: &str = "urn:xmpp:sm:3";
|
|||
/// XEP-0199: XMPP Ping
|
||||
pub const PING: &str = "urn:xmpp:ping";
|
||||
|
||||
/// XEP-0202: Entity Time
|
||||
pub const TIME: &str = "urn:xmpp:time";
|
||||
|
||||
/// XEP-0203: Delayed Delivery
|
||||
pub const DELAY: &str = "urn:xmpp:delay";
|
||||
|
||||
|
|
112
src/time.rs
Normal file
112
src/time.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
use chrono::FixedOffset;
|
||||
use crate::date::DateTime;
|
||||
use crate::iq::{IqGetPayload, IqResultPayload};
|
||||
use crate::ns;
|
||||
use crate::util::error::Error;
|
||||
use minidom::Element;
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
|
||||
generate_empty_element!(
|
||||
TimeQuery, "time", TIME
|
||||
);
|
||||
|
||||
impl IqGetPayload for TimeQuery {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TimeResult(pub DateTime);
|
||||
|
||||
impl IqResultPayload for TimeResult {}
|
||||
|
||||
impl TryFrom<Element> for TimeResult {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(elem: Element) -> Result<TimeResult, Error> {
|
||||
check_self!(elem, "time", TIME);
|
||||
check_no_attributes!(elem, "time");
|
||||
|
||||
let mut tzo = None;
|
||||
let mut utc = None;
|
||||
|
||||
for child in elem.children() {
|
||||
if child.is("tzo", ns::TIME) {
|
||||
if tzo.is_some() {
|
||||
return Err(Error::ParseError("More than one tzo element in time."));
|
||||
}
|
||||
check_no_children!(child, "tzo");
|
||||
check_no_attributes!(child, "tzo");
|
||||
// TODO: Add a FromStr implementation to FixedOffset to avoid this hack.
|
||||
let fake_date = String::from("2019-04-22T11:38:00") + &child.text();
|
||||
let date_time = DateTime::from_str(&fake_date)?;
|
||||
tzo = Some(date_time.timezone());
|
||||
} else if child.is("utc", ns::TIME) {
|
||||
if utc.is_some() {
|
||||
return Err(Error::ParseError("More than one utc element in time."));
|
||||
}
|
||||
check_no_children!(child, "utc");
|
||||
check_no_attributes!(child, "utc");
|
||||
let date_time = DateTime::from_str(&child.text())?;
|
||||
if date_time.timezone() != FixedOffset::east(0) {
|
||||
return Err(Error::ParseError("Non-UTC timezone for utc element."));
|
||||
}
|
||||
utc = Some(date_time);
|
||||
} else {
|
||||
return Err(Error::ParseError(
|
||||
"Unknown child in time element.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let tzo = tzo.ok_or(Error::ParseError("Missing tzo child in time element."))?;
|
||||
let utc = utc.ok_or(Error::ParseError("Missing utc child in time element."))?;
|
||||
let date = utc.with_timezone(&tzo);
|
||||
|
||||
Ok(TimeResult(date))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TimeResult> for Element {
|
||||
fn from(time: TimeResult) -> Element {
|
||||
Element::builder("time")
|
||||
.ns(ns::TIME)
|
||||
.append(Element::builder("tzo")
|
||||
.append(format!("{}", time.0.timezone()))
|
||||
.build())
|
||||
.append(Element::builder("utc")
|
||||
.append(time.0.with_timezone(&FixedOffset::east(0)).format("%FT%TZ"))
|
||||
.build())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// DateTime’s size doesn’t depend on the architecture.
|
||||
#[test]
|
||||
fn test_size() {
|
||||
assert_size!(TimeQuery, 0);
|
||||
assert_size!(TimeResult, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_response() {
|
||||
let elem: Element =
|
||||
"<time xmlns='urn:xmpp:time'><tzo>-06:00</tzo><utc>2006-12-19T17:58:35Z</utc></time>"
|
||||
.parse()
|
||||
.unwrap();
|
||||
let elem1 = elem.clone();
|
||||
let time = TimeResult::try_from(elem).unwrap();
|
||||
assert_eq!(time.0.timezone(), FixedOffset::west(6 * 3600));
|
||||
assert_eq!(time.0, DateTime::from_str("2006-12-19T12:58:35-05:00").unwrap());
|
||||
let elem2 = Element::from(time);
|
||||
assert_eq!(elem1, elem2);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue