1use serde::{Deserialize, Serialize};
4
5#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
7pub struct SmsMessage {
8 pub message_id: Option<i64>,
10
11 pub phone_number: String,
13
14 pub message_content: String,
16
17 pub message_reference: Option<u8>,
20
21 pub is_outgoing: bool,
23
24 pub created_at: Option<u32>,
26
27 pub completed_at: Option<u32>,
29
30 pub status: Option<u8>,
32}
33impl SmsMessage {
34 #[must_use]
36 pub fn with_message_id(&self, id: Option<i64>) -> Self {
37 Self {
38 message_id: id,
39 ..self.clone()
40 }
41 }
42
43 #[must_use]
45 pub fn created_at(&self) -> Option<std::time::SystemTime> {
46 self.created_at
47 .map(|ts| std::time::UNIX_EPOCH + std::time::Duration::from_secs(u64::from(ts)))
48 }
49}
50
51#[derive(Serialize, PartialEq, Default, Debug, Clone)]
53pub struct SmsOutgoingMessage {
54 pub to: String,
56
57 pub content: String,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
65 pub validity_period: Option<u8>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
70 pub flash: Option<bool>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
75 pub timeout: Option<u32>,
76}
77impl SmsOutgoingMessage {
78 pub fn simple_message(to: impl Into<String>, content: impl Into<String>) -> Self {
81 Self {
82 to: to.into(),
83 content: content.into(),
84 ..Default::default()
85 }
86 }
87
88 #[must_use]
91 pub fn with_flash(mut self, flash: bool) -> Self {
92 self.flash = Some(flash);
93 self
94 }
95
96 #[must_use]
98 pub fn with_validity_period(mut self, period: u8) -> Self {
99 self.validity_period = Some(period);
100 self
101 }
102
103 #[must_use]
105 pub fn with_timeout(mut self, timeout: u32) -> Self {
106 self.timeout = Some(timeout);
107 self
108 }
109
110 #[must_use]
113 pub fn get_validity_period(&self) -> u8 {
114 if self.flash.unwrap_or(false) {
115 return 0;
116 }
117 self.validity_period.unwrap_or(167) }
119}
120impl From<&SmsOutgoingMessage> for SmsMessage {
121 fn from(outgoing: &SmsOutgoingMessage) -> Self {
122 SmsMessage {
123 message_id: None,
124 phone_number: outgoing.to.clone(),
125 message_content: outgoing.content.clone(),
126 message_reference: None,
127 is_outgoing: true,
128 status: None,
129 created_at: None,
130 completed_at: None,
131 }
132 }
133}
134
135#[derive(Debug, Clone)]
137pub struct SmsIncomingMessage {
138 pub phone_number: String,
141
142 pub user_data_header: Option<SmsMultipartHeader>,
144
145 pub content: String,
147}
148impl From<&SmsIncomingMessage> for SmsMessage {
149 fn from(incoming: &SmsIncomingMessage) -> Self {
150 SmsMessage {
151 message_id: None,
152 phone_number: incoming.phone_number.clone(),
153 message_content: incoming.content.clone(),
154 message_reference: None,
155 is_outgoing: false,
156 status: None,
157 created_at: None,
158 completed_at: None,
159 }
160 }
161}
162
163#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
165#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
166pub struct SmsDeliveryReport {
167 pub report_id: Option<i64>,
169
170 pub status: u8,
172
173 pub is_final: bool,
175
176 pub created_at: Option<u32>,
178}
179
180#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
182pub struct SmsPartialDeliveryReport {
183 pub phone_number: String,
185 pub reference_id: u8,
188
189 pub status: u8,
191}
192
193#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
195pub enum SmsDeliveryReportStatusCategory {
196 Sent,
198
199 Received,
201
202 Retrying,
204
205 Failed,
207}
208impl From<u8> for SmsDeliveryReportStatusCategory {
209 fn from(value: u8) -> Self {
210 match value {
211 0x00 => SmsDeliveryReportStatusCategory::Received, 0x01..=0x02 => SmsDeliveryReportStatusCategory::Sent, 0x03..=0x1F => SmsDeliveryReportStatusCategory::Sent, 0x20..=0x3F => SmsDeliveryReportStatusCategory::Retrying,
215 0x40..=0x6F => SmsDeliveryReportStatusCategory::Failed,
216 _ => SmsDeliveryReportStatusCategory::Failed,
217 }
218 }
219}
220impl std::fmt::Display for SmsDeliveryReportStatusCategory {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 f.write_str(match self {
223 SmsDeliveryReportStatusCategory::Sent => "Sent",
224 SmsDeliveryReportStatusCategory::Received => "Received",
225 SmsDeliveryReportStatusCategory::Retrying => "Retrying",
226 SmsDeliveryReportStatusCategory::Failed => "Failed",
227 })
228 }
229}
230impl From<&SmsDeliveryReport> for SmsDeliveryReportStatusCategory {
231 fn from(value: &SmsDeliveryReport) -> Self {
232 SmsDeliveryReportStatusCategory::from(value.status)
233 }
234}
235impl From<&SmsPartialDeliveryReport> for SmsDeliveryReportStatusCategory {
236 fn from(value: &SmsPartialDeliveryReport) -> Self {
237 SmsDeliveryReportStatusCategory::from(value.status)
238 }
239}
240
241#[derive(Debug, Clone, Copy)]
243pub struct SmsMultipartHeader {
244 pub message_reference: u8,
246
247 pub total: u8,
249
250 pub index: u8,
252}
253impl TryFrom<Vec<u8>> for SmsMultipartHeader {
254 type Error = &'static str;
255
256 fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
257 if data.len() != 3 {
258 return Err("Invalid user data length!");
259 }
260 Ok(Self {
261 message_reference: data[0],
262 total: data[1],
263 index: data[2],
264 })
265 }
266}