diameter_interface/modeling/avp/
time.rs

1/*
2    Credit to: Mr. Jason Lee
3*/
4
5use crate::errors::Error::EncodeError;
6use crate::errors::{DiameterResult, Error};
7use crate::modeling::avp::avp::AvpValue;
8use crate::modeling::avp::AvpData;
9use chrono::{DateTime, TimeZone, Utc};
10use std::io::{Read, Write};
11
12pub type Time = AvpData<DateTime<Utc>>;
13
14const RFC868_OFFSET: u32 = 2208988800; // Diff. between 1970 and 1900 in seconds.
15
16impl Time {
17    pub(super) fn encode_to<W: Write>(&self, writer: &mut W) -> DiameterResult<()> {
18        let unix_timestamp = self.0.timestamp();
19        let diameter_timestamp = unix_timestamp + RFC868_OFFSET as i64;
20        if diameter_timestamp > u32::MAX as i64 {
21            Err(EncodeError(
22                "Time is too far in the future to fit into 32 bits",
23            ))?
24        }
25        let diameter_timestamp = diameter_timestamp as u32;
26        let encoded_data = Vec::from(diameter_timestamp.to_be_bytes());
27        writer.write(&encoded_data)?;
28        Ok(())
29    }
30
31    pub(super) fn decode_from<R: Read>(reader: &mut R) -> DiameterResult<AvpData<DateTime<Utc>>> {
32        let mut b = [0; 4];
33        reader.read_exact(&mut b)?;
34
35        let diameter_timestamp = u32::from_be_bytes(b); // seconds since 1900
36        let unix_timestamp = diameter_timestamp as i64 - RFC868_OFFSET as i64;
37        let timestamp = Utc
38            .timestamp_opt(unix_timestamp, 0)
39            .single()
40            .ok_or_else(|| Error::DecodeError("Invalid time"))?;
41        Ok(Time::new(timestamp))
42    }
43
44    pub(super) fn len(&self) -> u32 {
45        4
46    }
47}
48
49impl Into<AvpValue> for Time {
50    fn into(self) -> AvpValue {
51        AvpValue::Time(self)
52    }
53}