1mod container;
2mod delivery;
3mod payload;
4mod state;
5mod types;
6mod wire;
7
8pub use container::MessageContainer;
9pub use delivery::{decide_delivery, DeliveryDecision};
10pub use payload::Payload;
11pub use state::State;
12pub use types::{MessageMethod, MessageState, TransportMethod, UnverifiedReason};
13pub use wire::WireMessage;
14
15use crate::error::LxmfError;
16use alloc::string::String;
17use alloc::vec::Vec;
18use rns_core::identity::PrivateIdentity;
19
20#[cfg(feature = "std")]
21fn now_secs_f64() -> f64 {
22 let now =
23 std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default();
24 now.as_secs_f64()
25}
26
27#[cfg(not(feature = "std"))]
28fn now_secs_f64() -> f64 {
29 0.0
30}
31
32#[derive(Debug, Clone)]
33pub struct Message {
34 pub destination_hash: Option<[u8; 16]>,
35 pub source_hash: Option<[u8; 16]>,
36 pub signature: Option<[u8; wire::SIGNATURE_LENGTH]>,
37 pub content: Vec<u8>,
38 pub title: Vec<u8>,
39 pub fields: Option<rmpv::Value>,
40 pub stamp: Option<Vec<u8>>,
41 pub timestamp: Option<f64>,
42 state: State,
43}
44
45impl Message {
46 pub fn new() -> Self {
47 Self {
48 destination_hash: None,
49 source_hash: None,
50 signature: None,
51 content: Vec::new(),
52 title: Vec::new(),
53 fields: None,
54 stamp: None,
55 timestamp: None,
56 state: State::Generating,
57 }
58 }
59
60 pub fn set_state(&mut self, state: State) {
61 self.state = state;
62 }
63
64 pub fn is_outbound(&self) -> bool {
65 self.state == State::Outbound
66 }
67
68 pub fn set_title_from_string(&mut self, title: &str) {
69 self.title = title.as_bytes().to_vec();
70 }
71
72 pub fn set_title_from_bytes(&mut self, title: &[u8]) {
73 self.title = title.to_vec();
74 }
75
76 pub fn title_as_string(&self) -> Option<String> {
77 String::from_utf8(self.title.clone()).ok()
78 }
79
80 pub fn set_content_from_string(&mut self, content: &str) {
81 self.content = content.as_bytes().to_vec();
82 }
83
84 pub fn set_content_from_bytes(&mut self, content: &[u8]) {
85 self.content = content.to_vec();
86 }
87
88 pub fn set_stamp_from_bytes(&mut self, stamp: &[u8]) {
89 self.stamp = Some(stamp.to_vec());
90 }
91
92 pub fn stamp_bytes(&self) -> Option<Vec<u8>> {
93 self.stamp.clone()
94 }
95
96 pub fn content_as_string(&self) -> Option<String> {
97 String::from_utf8(self.content.clone()).ok()
98 }
99
100 pub fn from_wire(bytes: &[u8]) -> Result<Self, LxmfError> {
101 let wire = WireMessage::unpack(bytes)?;
102 let payload = wire.payload;
103 Ok(Self {
104 destination_hash: Some(wire.destination),
105 source_hash: Some(wire.source),
106 signature: wire.signature,
107 content: payload.content.as_ref().map(|c| c.to_vec()).unwrap_or_default(),
108 title: payload.title.as_ref().map(|t| t.to_vec()).unwrap_or_default(),
109 fields: payload.fields,
110 stamp: payload.stamp.as_ref().map(|s| s.to_vec()),
111 timestamp: Some(payload.timestamp),
112 state: State::Generating,
113 })
114 }
115
116 pub fn to_wire(&self, signer: Option<&PrivateIdentity>) -> Result<Vec<u8>, LxmfError> {
117 let destination =
118 self.destination_hash.ok_or_else(|| LxmfError::Encode("missing destination".into()))?;
119 let source = self.source_hash.ok_or_else(|| LxmfError::Encode("missing source".into()))?;
120
121 let timestamp = self.timestamp.unwrap_or_else(now_secs_f64);
122
123 let payload = Payload::new(
124 timestamp,
125 Some(self.content.clone()),
126 Some(self.title.clone()),
127 self.fields.clone(),
128 self.stamp.clone(),
129 );
130
131 let mut wire = WireMessage::new(destination, source, payload);
132 if let Some(signature) = self.signature {
133 wire.signature = Some(signature);
134 } else if let Some(signer) = signer {
135 wire.sign(signer)?;
136 } else {
137 return Err(LxmfError::Encode("missing signature".into()));
138 }
139
140 wire.pack()
141 }
142}
143
144impl Default for Message {
145 fn default() -> Self {
146 Self::new()
147 }
148}