forked from AzureMarker/a2
/
payload.rs
135 lines (121 loc) · 4.71 KB
/
payload.rs
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
///! Payload with `aps` and custom data
use crate::error::Error;
use crate::request::notification::{DefaultAlert, NotificationOptions, WebPushAlert};
use erased_serde::Serialize;
use serde_json::{self, Value};
use std::collections::BTreeMap;
/// The data and options for a push notification.
#[derive(Debug, Clone)]
pub struct Payload<'a> {
/// Send options
pub options: NotificationOptions<'a>,
/// The token for the receiving device
pub device_token: &'a str,
/// The pre-defined notification payload
pub aps: APS<'a>,
/// Application specific payload
pub data: BTreeMap<&'a str, Value>,
}
impl<'a> Payload<'a> {
/// Client-specific custom data to be added in the payload.
/// The `root_key` defines the JSON key in the root of the request
/// data, and `data` the object containing custom data. The `data`
/// should implement `Serialize`, which allows using of any Rust
/// collection or if needing more strict type definitions, any struct
/// that has `#[derive(Serialize)]` from [Serde](https://serde.rs).
///
/// Using a `HashMap`:
///
/// ```rust
/// # use a2::request::notification::{DefaultNotificationBuilder, NotificationBuilder};
/// # use std::collections::HashMap;
/// # fn main() {
/// let mut payload = DefaultNotificationBuilder::new()
/// .set_content_available()
/// .build("token", Default::default());
/// let mut custom_data = HashMap::new();
///
/// custom_data.insert("foo", "bar");
/// payload.add_custom_data("foo_data", &custom_data).unwrap();
///
/// assert_eq!(
/// "{\"aps\":{\"content-available\":1,\"mutable-content\":0},\"foo_data\":{\"foo\":\"bar\"}}",
/// &payload.to_json_string().unwrap()
/// );
/// # }
/// ```
///
/// Using a custom struct:
///
/// ```rust
/// #[macro_use] extern crate serde;
/// use a2::request::notification::{DefaultNotificationBuilder, NotificationBuilder};
/// fn main() {
/// #[derive(Serialize)]
/// struct CompanyData {
/// foo: &'static str,
/// }
///
/// let mut payload = DefaultNotificationBuilder::new()
/// .set_content_available()
/// .build("token", Default::default());
/// let mut custom_data = CompanyData { foo: "bar" };
///
/// payload.add_custom_data("foo_data", &custom_data).unwrap();
///
/// assert_eq!(
/// "{\"aps\":{\"content-available\":1,\"mutable-content\":0},\"foo_data\":{\"foo\":\"bar\"}}",
/// &payload.to_json_string().unwrap()
/// );
/// }
/// ```
pub fn add_custom_data(&mut self, root_key: &'a str, data: &dyn Serialize) -> Result<&mut Self, Error> {
self.data.insert(root_key, serde_json::to_value(data)?);
Ok(self)
}
/// Combine the APS payload and the custom data to a final payload JSON.
/// Returns an error if serialization fails.
#[allow(clippy::wrong_self_convention)]
pub fn to_json_string(mut self) -> Result<String, Error> {
let aps_data = serde_json::to_value(&self.aps)?;
self.data.insert("aps", aps_data);
Ok(serde_json::to_string(&self.data)?)
}
}
/// The pre-defined notification data.
#[derive(Serialize, Default, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
#[allow(clippy::upper_case_acronyms)]
pub struct APS<'a> {
/// The notification content. Can be empty for silent notifications.
#[serde(skip_serializing_if = "Option::is_none")]
pub alert: Option<APSAlert<'a>>,
/// A number shown on top of the app icon.
#[serde(skip_serializing_if = "Option::is_none")]
pub badge: Option<u32>,
/// The name of the sound file to play when user receives the notification.
#[serde(skip_serializing_if = "Option::is_none")]
pub sound: Option<&'a str>,
/// Set to one for silent notifications.
#[serde(skip_serializing_if = "Option::is_none")]
pub content_available: Option<u8>,
/// When a notification includes the category key, the system displays the
/// actions for that category as buttons in the banner or alert interface.
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<&'a str>,
/// If set to one, the app can change the notification content before
/// displaying it to the user.
#[serde(skip_serializing_if = "Option::is_none")]
pub mutable_content: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url_args: Option<&'a [&'a str]>,
}
/// Different notification content types.
#[derive(Serialize, Debug, Clone)]
#[serde(untagged)]
pub enum APSAlert<'a> {
/// A notification that supports all of the iOS features
Default(DefaultAlert<'a>),
/// Safari web push notification
WebPush(WebPushAlert<'a>),
}