1use std::fmt;
4
5#[derive(Debug)]
7pub struct Response {
8 pub error: Option<ErrorBody>,
10
11 pub apns_id: Option<String>,
14
15 pub apns_unique_id: Option<String>,
18
19 pub code: u16,
31}
32
33#[derive(Deserialize, Debug, PartialEq, Eq)]
35pub struct ErrorBody {
36 pub reason: ErrorReason,
38
39 pub timestamp: Option<u64>,
46}
47
48#[derive(Deserialize, Debug, PartialEq, Eq)]
50pub enum ErrorReason {
51 BadCollapseId,
53
54 BadDeviceToken,
56
57 BadExpirationDate,
59
60 BadMessageId,
62
63 BadPriority,
65
66 BadTopic,
68
69 DeviceTokenNotForTopic,
71
72 DuplicateHeaders,
74
75 IdleTimeout,
77
78 InvalidPushType,
80
81 MissingDeviceToken,
83
84 MissingTopic,
86
87 PayloadEmpty,
89
90 TopicDisallowed,
92
93 BadCertificate,
95
96 BadCertificateEnvironment,
98
99 ExpiredProviderToken,
101
102 Forbidden,
104
105 InvalidProviderToken,
107
108 MissingProviderToken,
110
111 UnrelatedKeyIdInToken,
113
114 BadEnvironmentKeyIdInToken,
116
117 BadPath,
119
120 MethodNotAllowed,
122
123 ExpiredToken,
125
126 Unregistered,
128
129 PayloadTooLarge,
131
132 TooManyProviderTokenUpdates,
134
135 TooManyRequests,
137
138 InternalServerError,
140
141 ServiceUnavailable,
143
144 Shutdown,
146}
147
148impl fmt::Display for ErrorReason {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 let s = match *self {
151 ErrorReason::BadCollapseId => "The collapse identifier exceeds the maximum allowed size.",
152 ErrorReason::BadDeviceToken => {
153 "The specified device token was bad. Verify that the request contains a valid token and that the token matches the environment."
154 }
155 ErrorReason::BadExpirationDate => "The `apns_expiration` in `NotificationOptions` is bad.",
156 ErrorReason::BadMessageId => "The `apns_id` in `NotificationOptions` is bad.",
157 ErrorReason::BadPriority => "The `apns_priority` in `NotificationOptions` is bad.",
158 ErrorReason::BadTopic => "The `apns_topic` in `NotificationOptions` is bad.",
159 ErrorReason::DeviceTokenNotForTopic => "The device token does not match the specified topic.",
160 ErrorReason::DuplicateHeaders => "One or more headers were repeated.",
161 ErrorReason::IdleTimeout => "Idle time out.",
162 ErrorReason::InvalidPushType => "The apns-push-type value is invalid.",
163 ErrorReason::MissingDeviceToken => "The device token is not specified in the payload.",
164 ErrorReason::MissingTopic => {
165 "The `apns_topic` of the `NotificationOptions` was not specified and was required. The `apns_topic` header is mandatory when the client is connected using the `CertificateConnector` and the included PKCS12 file includes multiple topics, or when using the `TokenConnector`."
166 }
167 ErrorReason::PayloadEmpty => "The message payload was empty.",
168 ErrorReason::TopicDisallowed => "Pushing to this topic is not allowed.",
169 ErrorReason::BadCertificate => "The certificate was bad.",
170 ErrorReason::BadCertificateEnvironment => "The client certificate was for the wrong environment.",
171 ErrorReason::ExpiredProviderToken => {
172 "The provider token is stale and a new token should be generated."
173 }
174 ErrorReason::Forbidden => "The specified action is not allowed.",
175 ErrorReason::InvalidProviderToken => {
176 "The provider token is not valid or the token signature could not be verified."
177 }
178 ErrorReason::MissingProviderToken => {
179 "No provider certificate was used to connect to APNs and Authorization header was missing or no provider token was specified."
180 }
181 ErrorReason::UnrelatedKeyIdInToken => {
182 "The key ID in the provider token isn't related to the key ID of the token used in the first push of this connection."
183 }
184 ErrorReason::BadEnvironmentKeyIdInToken => {
185 "The key ID in the provider token doesn't match the environment."
186 }
187 ErrorReason::BadPath => "The request path value is bad.",
188 ErrorReason::MethodNotAllowed => "The request method was not `POST`.",
189 ErrorReason::ExpiredToken => "The device token has expired.",
190 ErrorReason::Unregistered => {
191 "The device token is inactive for the specified topic. You should stop sending notifications to this token."
192 }
193 ErrorReason::PayloadTooLarge => "The message payload was too large (4096 bytes)",
194 ErrorReason::TooManyProviderTokenUpdates => "The provider token is being updated too often.",
195 ErrorReason::TooManyRequests => {
196 "Too many requests were made consecutively to the same device token."
197 }
198 ErrorReason::InternalServerError => "An internal server error occurred.",
199 ErrorReason::ServiceUnavailable => "The service is unavailable.",
200 ErrorReason::Shutdown => "The server is shutting down.",
201 };
202
203 f.write_str(s)
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use serde_json;
211
212 #[test]
213 fn test_error_response_parsing() {
214 let errors = vec![
215 (ErrorReason::BadCollapseId, "BadCollapseId", None),
216 (ErrorReason::BadDeviceToken, "BadDeviceToken", None),
217 (ErrorReason::BadExpirationDate, "BadExpirationDate", None),
218 (ErrorReason::BadMessageId, "BadMessageId", None),
219 (ErrorReason::BadPriority, "BadPriority", None),
220 (ErrorReason::BadTopic, "BadTopic", None),
221 (
222 ErrorReason::DeviceTokenNotForTopic,
223 "DeviceTokenNotForTopic",
224 None,
225 ),
226 (ErrorReason::DuplicateHeaders, "DuplicateHeaders", None),
227 (ErrorReason::IdleTimeout, "IdleTimeout", None),
228 (ErrorReason::InvalidPushType, "InvalidPushType", None),
229 (ErrorReason::MissingDeviceToken, "MissingDeviceToken", None),
230 (ErrorReason::MissingTopic, "MissingTopic", None),
231 (ErrorReason::PayloadEmpty, "PayloadEmpty", None),
232 (ErrorReason::TopicDisallowed, "TopicDisallowed", None),
233 (ErrorReason::BadCertificate, "BadCertificate", None),
234 (
235 ErrorReason::BadCertificateEnvironment,
236 "BadCertificateEnvironment",
237 None,
238 ),
239 (ErrorReason::ExpiredProviderToken, "ExpiredProviderToken", None),
240 (ErrorReason::Forbidden, "Forbidden", None),
241 (ErrorReason::InvalidProviderToken, "InvalidProviderToken", None),
242 (ErrorReason::MissingProviderToken, "MissingProviderToken", None),
243 (ErrorReason::UnrelatedKeyIdInToken, "UnrelatedKeyIdInToken", None),
244 (
245 ErrorReason::BadEnvironmentKeyIdInToken,
246 "BadEnvironmentKeyIdInToken",
247 None,
248 ),
249 (ErrorReason::BadPath, "BadPath", None),
250 (ErrorReason::MethodNotAllowed, "MethodNotAllowed", None),
251 (ErrorReason::ExpiredToken, "ExpiredToken", None),
252 (ErrorReason::Unregistered, "Unregistered", Some(1508249865488u64)),
253 (ErrorReason::PayloadTooLarge, "PayloadTooLarge", None),
254 (
255 ErrorReason::TooManyProviderTokenUpdates,
256 "TooManyProviderTokenUpdates",
257 None,
258 ),
259 (ErrorReason::TooManyRequests, "TooManyRequests", None),
260 (ErrorReason::InternalServerError, "InternalServerError", None),
261 (ErrorReason::ServiceUnavailable, "ServiceUnavailable", None),
262 (ErrorReason::Shutdown, "Shutdown", None),
263 ];
264
265 for error in errors.into_iter() {
266 let response_data = match error.2 {
267 None => json!({"reason": error.1}),
268 Some(ts) => json!({"reason": error.1, "timestamp": ts}),
269 };
270
271 let response_string = serde_json::to_string(&response_data).unwrap();
272
273 let response_body: ErrorBody = serde_json::from_str(&response_string).unwrap();
274
275 let expected_body = match error.2 {
276 None => ErrorBody {
277 reason: error.0,
278 timestamp: None,
279 },
280 Some(ts) => ErrorBody {
281 reason: error.0,
282 timestamp: Some(ts),
283 },
284 };
285
286 assert_eq!(expected_body, response_body);
287 }
288 }
289}