Skip to main content

apns_h2/request/notification/
options.rs

1use crate::error::Error;
2use std::fmt;
3
4#[derive(Debug, Clone)]
5pub struct CollapseId<'a> {
6    pub value: &'a str,
7}
8
9/// A collapse-id container. Will not allow bigger id's than 64 bytes.
10impl<'a> CollapseId<'a> {
11    pub fn new(value: &'a str) -> Result<CollapseId<'a>, Error> {
12        if value.len() > 64 {
13            Err(Error::InvalidOptions(String::from(
14                "The collapse-id is too big. Maximum 64 bytes.",
15            )))
16        } else {
17            Ok(CollapseId { value })
18        }
19    }
20}
21
22#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
23/// The apns-push-type header field has the following valid values.
24/// The descriptions below describe when and how to use these values.
25/// Send an apns-push-type header with each push. Recent and upcoming features
26/// may not work if this header is missing. See the table above to determine if
27/// this header is required or optional.
28///
29/// see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#4294485
30pub enum PushType {
31    /// The push type for notifications that trigger a user interaction—for example,
32    /// an alert, badge, or sound.
33    #[default]
34    Alert,
35    /// The push type for notifications that deliver content in the background, and
36    /// don’t trigger any user interactions.
37    Background,
38    /// The push type for notifications that request a user’s location.
39    Location,
40    /// The push type for notifications that provide information about an incoming
41    /// Voice-over-IP (VoIP) call.
42    Voip,
43    /// The push type to signal changes to a File Provider extension.
44    FileProvider,
45    /// The push type for notifications that tell managed devices to contact the
46    /// MDM server.
47    Mdm,
48    ///  The push type to signal changes to a live activity session.
49    LiveActivity,
50    /// The push type for notifications that provide information about updates to
51    /// your application’s push to talk services.
52    PushToTalk,
53}
54
55impl fmt::Display for PushType {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        f.write_str(match self {
58            PushType::Alert => "alert",
59            PushType::Background => "background",
60            PushType::Location => "location",
61            PushType::Voip => "voip",
62            PushType::FileProvider => "fileprovider",
63            PushType::Mdm => "mdm",
64            PushType::LiveActivity => "liveactivity",
65            PushType::PushToTalk => "pushtotalk",
66        })
67    }
68}
69
70/// Headers to specify options to the notification.
71#[derive(Debug, Default, Clone)]
72pub struct NotificationOptions<'a> {
73    /// A canonical UUID that identifies the notification. If there is an error
74    /// sending the notification, APNs uses this value to identify the
75    /// notification to your server.
76    pub apns_id: Option<&'a str>,
77
78    /// The apns-push-type header field has the following valid values.
79    ///
80    /// Recent and upcoming features may not work if this header is missing.
81    /// See the table above to determine if this header is required or optional.
82    pub apns_push_type: Option<PushType>,
83
84    /// A UNIX epoch date expressed in seconds (UTC). This header identifies the
85    /// date when the notification is no longer valid and can be discarded.
86    ///
87    /// If this value is nonzero, APNs stores the notification and tries to
88    /// deliver it at least once, repeating the attempt as needed if it is unable
89    /// to deliver the notification the first time. If the value is 0, APNs
90    /// treats the notification as if it expires immediately and does not store
91    /// the notification or attempt to redeliver it.
92    pub apns_expiration: Option<u64>,
93
94    /// The priority of the notification. If `None`, the APNs server sets the priority to High.
95    pub apns_priority: Option<Priority>,
96
97    /// The topic of the remote notification, which is typically the bundle ID
98    /// for your app. The certificate you create in your developer account must
99    /// include the capability for this topic.
100    ///
101    /// If your certificate includes multiple topics, you must specify a value
102    /// for this header.
103    ///
104    /// If you omit this request header and your APNs certificate does not
105    /// specify multiple topics, the APNs server uses the certificate’s Subject
106    /// as the default topic.
107    ///
108    /// If you are using a provider token instead of a certificate, you must
109    /// specify a value for this request header. The topic you provide should be
110    /// provisioned for the your team named in your developer account.
111    pub apns_topic: Option<&'a str>,
112
113    /// Multiple notifications with the same collapse identifier are displayed to the
114    /// user as a single notification. The value of this key must not exceed 64
115    /// bytes.
116    pub apns_collapse_id: Option<CollapseId<'a>>,
117}
118
119/// The importance how fast to bring the notification for the user..
120#[derive(Debug, Clone)]
121pub enum Priority {
122    /// Send the push message immediately. Notifications with this priority must
123    /// trigger an alert, sound, or badge on the target device. Cannot be used
124    /// with the silent notification.
125    High,
126
127    /// Send the push message at a time that takes into account power
128    /// considerations for the device. Notifications with this priority might be
129    /// grouped and delivered in bursts. They are throttled, and in some cases
130    /// are not delivered.
131    Normal,
132}
133
134impl fmt::Display for Priority {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        let priority = match self {
137            Priority::High => "10",
138            Priority::Normal => "5",
139        };
140
141        write!(f, "{}", priority)
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148    use std::str;
149
150    #[test]
151    fn test_collapse_id_under_64_chars() {
152        let collapse_id = CollapseId::new("foo").unwrap();
153        assert_eq!("foo", collapse_id.value);
154    }
155
156    #[test]
157    fn test_collapse_id_over_64_chars() {
158        let mut long_string = Vec::with_capacity(65);
159        long_string.extend_from_slice(&[65; 65]);
160
161        let collapse_id = CollapseId::new(str::from_utf8(&long_string).unwrap());
162        assert!(collapse_id.is_err());
163    }
164}