over_there/core/msg/
mod.rs1pub mod content;
2
3use chrono::prelude::{DateTime, Utc};
4use content::{Content, Reply, Request};
5use derive_more::{Display, Error};
6use rand::random;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Display, Error)]
10pub enum MsgError {
11 AssembleMsg(serde_cbor::Error),
12 DisassembleMsg(serde_cbor::Error),
13}
14
15#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
16pub struct Header {
17 pub id: u32,
19
20 pub creation_date: DateTime<Utc>,
22}
23
24impl Default for Header {
25 fn default() -> Self {
26 Self {
27 id: random(),
28 creation_date: Utc::now(),
29 }
30 }
31}
32
33#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
34pub struct Msg {
35 pub header: Header,
37
38 pub parent_header: Option<Header>,
41
42 pub content: Content,
44}
45
46impl Msg {
47 pub fn new(content: Content, parent_header: Option<Header>) -> Self {
48 Self {
49 header: Header::default(),
50 parent_header,
51 content,
52 }
53 }
54
55 pub fn to_vec(&self) -> Result<Vec<u8>, MsgError> {
56 serde_cbor::ser::to_vec(&self).map_err(MsgError::AssembleMsg)
58 }
59
60 pub fn from_slice(slice: &[u8]) -> Result<Self, MsgError> {
61 serde_cbor::from_slice(slice).map_err(MsgError::DisassembleMsg)
62 }
63
64 pub fn with_parent_header(&mut self, header: Header) -> &mut Self {
66 self.parent_header = Some(header);
67 self
68 }
69
70 pub fn with_parent(&mut self, parent: &Self) -> &mut Self {
72 self.with_parent_header(parent.header.clone())
73 }
74}
75
76impl From<Content> for Msg {
78 fn from(content: Content) -> Self {
79 Self {
80 header: Header::default(),
81 parent_header: None,
82 content,
83 }
84 }
85}
86
87impl From<Request> for Msg {
88 fn from(request: Request) -> Self {
89 Self::from(Content::from(request))
90 }
91}
92
93impl From<Reply> for Msg {
94 fn from(reply: Reply) -> Self {
95 Self::from(Content::from(reply))
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn default_header_should_have_creation_date_set_to_now() {
105 let header = Header::default();
106
107 assert!(
109 Utc::now()
110 .signed_duration_since(header.creation_date)
111 .num_milliseconds()
112 >= 0,
113 "Unexpected creation date: {:?}",
114 header.creation_date
115 );
116 }
117
118 #[test]
119 fn from_content_should_create_msg_with_content() {
120 let msg = Msg::from(Request::Heartbeat);
121
122 assert_eq!(msg.parent_header, None);
123
124 match msg.content {
125 Content::Request(Request::Heartbeat) => (),
126 x => panic!("Unexpected content: {:?}", x),
127 }
128 }
129
130 #[test]
131 fn with_parent_header_should_set_header() {
132 let mut msg = Msg::from(Reply::Heartbeat);
133 let header = Header::default();
134
135 msg.with_parent_header(header.clone());
136
137 assert_eq!(msg.parent_header, Some(header));
138 }
139
140 #[test]
141 fn with_parent_should_set_header_to_that_of_parent() {
142 let mut msg = Msg::from(Reply::Heartbeat);
143 let parent = Msg::from(Request::Heartbeat);
144
145 msg.with_parent(&parent);
146
147 assert_eq!(msg.parent_header, Some(parent.header));
148 }
149}