sms_client/http/
types.rs

1//! HTTP interface related request/response types.
2
3use serde::{Deserialize, Serialize};
4
5/// HTTP pagination options allow for lazy reading of large sets of data,
6/// for example if thousands of messages have been sent and received from
7/// a phone number it would be impractical to request all of them at the
8/// same time, instead it can be read in shorter pages using limit+offset.
9/// This is applied at the server level when requesting data from database.
10#[derive(Serialize, PartialEq, Default, Debug, Clone, Copy)]
11pub struct HttpPaginationOptions {
12    /// The maximum amount of return values.
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub limit: Option<u64>,
15
16    /// The offset in index to start getting values from.
17    /// Eg, if the limit was 5, and you want to view page 2,
18    /// the offset would be 5, then 10, 15, ...
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub offset: Option<u64>,
21
22    /// Should return values be reversed? This is useful for getting the
23    /// first results from a large set without having to know it's size.
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub reverse: Option<bool>,
26}
27impl HttpPaginationOptions {
28    /// Set the limit/page size.
29    #[must_use]
30    pub fn with_limit(mut self, limit: u64) -> Self {
31        self.limit = Some(limit);
32        self
33    }
34
35    /// Set request position offset.
36    #[must_use]
37    pub fn with_offset(mut self, offset: u64) -> Self {
38        self.offset = Some(offset);
39        self
40    }
41
42    /// Set the reverse state for options.
43    #[must_use]
44    pub fn with_reverse(mut self, reverse: bool) -> Self {
45        self.reverse = Some(reverse);
46        self
47    }
48
49    /// Add pagination options to a json Value.
50    pub fn add_to_body(&self, body: &mut serde_json::Value) {
51        if let Some(limit) = self.limit {
52            body["limit"] = serde_json::json!(limit);
53        }
54        if let Some(offset) = self.offset {
55            body["offset"] = serde_json::json!(offset);
56        }
57        if let Some(reverse) = self.reverse {
58            body["reverse"] = serde_json::json!(reverse);
59        }
60    }
61}
62
63/// The outgoing SMS message to be sent to a target number.
64#[derive(Serialize, PartialEq, Default, Debug, Clone)]
65pub struct HttpOutgoingSmsMessage {
66    /// The target phone number, this should be in international format.
67    pub to: String,
68
69    /// The full message content. This will be split into multiple messages
70    /// by the server if required. This also supports Unicode emojis etc.
71    pub content: String,
72
73    /// The relative validity period to use for message sending. This determines
74    /// how long the message should remain waiting while undelivered.
75    /// By default, this is determined by the server (24 hours).
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub validity_period: Option<u8>,
78
79    /// Should the SMS message be sent as a Silent class? This makes a popup
80    /// show on the users device with the message content if they're logged in.
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub flash: Option<bool>,
83
84    /// A timeout that should be applied to the entire request.
85    /// If one is not set, the default timeout is used.
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub timeout: Option<u32>,
88}
89impl HttpOutgoingSmsMessage {
90    /// Create a new outgoing message with a default validity period and no flash.
91    /// The default validity period is applied by SMS-API, so usually 24 hours.
92    pub fn simple_message(to: impl Into<String>, content: impl Into<String>) -> Self {
93        Self {
94            to: to.into(),
95            content: content.into(),
96            ..Default::default()
97        }
98    }
99
100    /// Set the message flash state. This will show a popup if the recipient is
101    /// logged-in to their phone, otherwise as a normal text message.
102    #[must_use]
103    pub fn with_flash(mut self, flash: bool) -> Self {
104        self.flash = Some(flash);
105        self
106    }
107
108    /// Set a relative validity period value.
109    #[must_use]
110    pub fn with_validity_period(mut self, period: u8) -> Self {
111        self.validity_period = Some(period);
112        self
113    }
114
115    /// Set a request timeout value.
116    #[must_use]
117    pub fn with_timeout(mut self, timeout: u32) -> Self {
118        self.timeout = Some(timeout);
119        self
120    }
121}
122
123/// Response returned after sending an SMS message.
124#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
125pub struct HttpSmsSendResponse {
126    /// The unique ID assigned to the already sent message.
127    pub message_id: i64,
128
129    /// Reference ID for tracking the message.
130    pub reference_id: u8,
131}
132
133/// Delivery report for an already sent SMS message.
134#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Copy)]
135pub struct HttpSmsDeliveryReport {
136    /// Unique identifier for this delivery report.
137    pub report_id: Option<i64>,
138
139    /// Delivery status code from the network.
140    pub status: u8,
141
142    /// Whether this is the final delivery report for the message.
143    pub is_final: bool,
144
145    /// Unix timestamp when this report was created.
146    pub created_at: Option<u32>,
147}
148
149/// Network registration status of the modem.
150#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
151pub struct HttpModemNetworkStatusResponse {
152    /// Registration status code (0=not registered, 1=registered home, 5=registered roaming).
153    pub registration: u8,
154
155    /// Network technology in use (e.g., 2G, 3G, 4G).
156    pub technology: u8,
157}
158
159/// Signal strength information from the modem.
160#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
161pub struct HttpModemSignalStrengthResponse {
162    /// Received Signal Strength Indicator (0-31, 99=unknown).
163    pub rssi: u8,
164
165    /// Bit Error Rate (0-7, 99=unknown).
166    pub ber: u8,
167}
168
169/// Network operator information from the modem.
170#[derive(Deserialize, PartialEq, Debug, Clone)]
171pub struct HttpModemNetworkOperatorResponse {
172    /// Operator selection status (0=automatic, 1=manual).
173    pub status: u8,
174
175    /// Format of the operator name (0=long alphanumeric, 1=short alphanumeric, 2=numeric).
176    pub format: u8,
177
178    /// Name or code of the network operator.
179    pub operator: String,
180}
181
182/// Battery status information from the modem.
183#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
184pub struct HttpModemBatteryLevelResponse {
185    /// Battery status (0=not charging, 1=charging, 2=no battery).
186    pub status: u8,
187
188    /// Battery charge level percentage (0-100).
189    pub charge: u8,
190
191    /// Battery voltage in volts.
192    pub voltage: f32,
193}
194
195/// Combine an outgoing message and send response into a dummy `SmsStoredMessage`.
196impl From<(HttpOutgoingSmsMessage, HttpSmsSendResponse)> for crate::types::SmsStoredMessage {
197    fn from(
198        value: (HttpOutgoingSmsMessage, HttpSmsSendResponse),
199    ) -> crate::types::SmsStoredMessage {
200        crate::types::SmsStoredMessage {
201            message_id: value.1.message_id,
202            phone_number: value.0.to,
203            message_content: value.0.content,
204            message_reference: Some(value.1.reference_id),
205            is_outgoing: true,
206            status: "Unknown".to_string(),
207            created_at: None,
208            completed_at: None,
209        }
210    }
211}
212
213/// The raw `DeviceInfoResponse` with raw values.
214#[derive(Deserialize, PartialEq, Debug, Clone)]
215pub struct HttpSmsDeviceInfoResponse {
216    /// SMS API version string, including features.
217    pub version: String,
218
219    /// The phone number associated with the SMS device
220    pub phone_number: Option<String>,
221
222    /// The name of the cellular service provider
223    pub service_provider: Option<String>,
224
225    /// Network operator information as (code1, code2, `operator_name`)
226    pub network_operator: Option<(u8, u8, String)>,
227
228    /// Current network connection status as (`status_code`, `strength_indicator`)
229    pub network_status: Option<(u8, u8)>,
230
231    /// Battery information as (`level_percentage`, `charging_status`, voltage)
232    pub battery: Option<(u8, u8, f32)>,
233
234    /// Signal strength information as (`strength_level`, `quality_indicator`)
235    pub signal: Option<(u8, u8)>,
236}
237
238/// Formatted device info response, with each value packed into a proper optional response.
239#[derive(Deserialize, PartialEq, Debug, Clone)]
240pub struct HttpSmsDeviceInfoData {
241    /// SMS API version string, including features.
242    pub version: String,
243
244    /// The phone number associated with the SMS device
245    pub phone_number: Option<String>,
246
247    /// The name of the cellular service provider
248    pub service_provider: Option<String>,
249
250    /// Detailed network operator information and capabilities
251    pub network_operator: Option<HttpModemNetworkOperatorResponse>,
252
253    /// Current network connection status and diagnostics
254    pub network_status: Option<HttpModemNetworkStatusResponse>,
255
256    /// Battery level, charging state, and power metrics
257    pub battery: Option<HttpModemBatteryLevelResponse>,
258
259    /// Signal strength measurements and quality indicators
260    pub signal: Option<HttpModemSignalStrengthResponse>,
261}
262impl From<HttpSmsDeviceInfoResponse> for HttpSmsDeviceInfoData {
263    fn from(value: HttpSmsDeviceInfoResponse) -> HttpSmsDeviceInfoData {
264        HttpSmsDeviceInfoData {
265            version: value.version,
266            phone_number: value.phone_number,
267            service_provider: value.service_provider,
268            network_operator: value
269                .network_operator
270                .map(|v| HttpModemNetworkOperatorResponse {
271                    status: v.0,
272                    format: v.1,
273                    operator: v.2,
274                }),
275            network_status: value
276                .network_status
277                .map(|v| HttpModemNetworkStatusResponse {
278                    registration: v.0,
279                    technology: v.1,
280                }),
281            battery: value.battery.map(|v| HttpModemBatteryLevelResponse {
282                status: v.0,
283                charge: v.1,
284                voltage: v.2,
285            }),
286            signal: value.signal.map(|v| HttpModemSignalStrengthResponse {
287                rssi: v.0,
288                ber: v.1,
289            }),
290        }
291    }
292}
293
294/// Used in latest-numbers return value, as a number and friendly name.
295pub type LatestNumberFriendlyNamePair = (String, Option<String>);