1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! Describes a sensor reading and related structures.

use crate::core::value::Value;
use chrono::prelude::*;
use serde::Deserialize;

// TODO: still make a separate `Reading` struct which only used to store readings in database.
/// Services use messages to exchange sensor readings between each other.
/// Message contains a single sensor reading alongside with some metadata.
#[derive(Debug, Clone, PartialEq)]
pub struct Message {
    /// Message type.
    pub type_: Type,

    /// A sensor. For example: `buienradar::6240::wind_speed_bft`.
    ///
    /// Note that sensors do not exist as separate entities. Sensor is only a sort of "label"
    /// that corresponds to a sensor in the physical world and used to distinguish readings
    /// between different "real" sensors.
    pub sensor: String,

    /// Timestamp when the value was actually measured. This may be earlier than a moment of sending the message.
    pub timestamp: DateTime<Local>,

    /// Attached value.
    pub value: Value,
}

/// Message type.
#[derive(Clone, Copy, PartialEq, Debug, Deserialize)]
pub enum Type {
    /// Normal persistently stored sensor reading. The most frequently used message type.
    ReadLogged,

    /// Sensor reading which become non-actual just right after it was sent, thus not persisted at all.
    /// Think of, for example, a chat message.
    ReadNonLogged,

    /// Sensor reading that invalidates previous reading. Only last reading is stored.
    /// Think of, for example, a camera snapshot.
    ReadSnapshot,

    /// Used to control other services. One service may send this to control a sensor of another service.
    Write,
}

/// Message builder. Prefer to use it instead of directly instantiating a `Message`.
pub struct Composer {
    message: Message,
}

impl Composer {
    pub fn new<S: Into<String>>(sensor: S) -> Self {
        Self {
            message: Message {
                sensor: sensor.into(),
                type_: Type::ReadLogged,
                timestamp: Local::now(),
                value: Value::None,
            },
        }
    }

    pub fn type_(mut self, type_: Type) -> Self {
        self.message.type_ = type_;
        self
    }

    pub fn timestamp<T: Into<DateTime<Local>>>(mut self, timestamp: T) -> Self {
        self.message.timestamp = timestamp.into();
        self
    }

    pub fn value<V: Into<Value>>(mut self, value: V) -> Self {
        self.message.value = value.into();
        self
    }
}

impl From<Composer> for Message {
    fn from(composer: Composer) -> Self {
        composer.message
    }
}