autopush_common/
errors.rs1use std::fmt::{self, Display};
4use std::io;
5use std::num;
6
7use actix_web::{
8 dev::ServiceResponse, http::StatusCode, middleware::ErrorHandlerResponse, HttpResponse,
9 HttpResponseBuilder, ResponseError,
10};
11use backtrace::Backtrace;
13use serde::ser::{Serialize, SerializeMap, Serializer};
14use thiserror::Error;
15
16#[cfg(feature = "reliable_report")]
17use redis::RedisError;
18
19pub type Result<T> = std::result::Result<T, ApcError>;
20
21pub fn render_404<B>(
23 res: ServiceResponse<B>,
24) -> std::result::Result<ErrorHandlerResponse<B>, actix_web::Error> {
25 let resp = HttpResponseBuilder::new(StatusCode::NOT_FOUND).finish();
27 Ok(ErrorHandlerResponse::Response(
28 res.into_response(resp).map_into_right_body(),
29 ))
30}
31
32#[derive(Debug)]
34pub struct ApcError {
35 pub kind: ApcErrorKind,
36 pub backtrace: Box<Backtrace>,
37}
38
39impl Display for ApcError {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 self.kind.fmt(f)
42 }
43}
44
45impl std::error::Error for ApcError {
46 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47 self.kind.source()
48 }
49}
50
51impl<T> From<T> for ApcError
54where
55 ApcErrorKind: From<T>,
56{
57 fn from(item: T) -> Self {
58 ApcError {
59 kind: ApcErrorKind::from(item),
60 backtrace: Box::new(Backtrace::new()), }
62 }
63}
64
65impl ResponseError for ApcError {
67 fn status_code(&self) -> StatusCode {
68 self.kind.status()
69 }
70
71 fn error_response(&self) -> HttpResponse {
72 let mut builder = HttpResponse::build(self.status_code());
73 builder.json(self)
74 }
75}
76
77impl Serialize for ApcError {
78 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
79 where
80 S: Serializer,
81 {
82 let status = self.kind.status();
83 let mut map = serializer.serialize_map(Some(5))?;
84
85 map.serialize_entry("code", &status.as_u16())?;
86 map.serialize_entry("error", &status.canonical_reason())?;
87 map.serialize_entry("message", &self.kind.to_string())?;
88 map.end()
90 }
91}
92
93#[derive(Error, Debug)]
94pub enum ApcErrorKind {
95 #[error(transparent)]
96 Io(#[from] io::Error),
97 #[error(transparent)]
98 UuidError(#[from] uuid::Error),
99 #[error(transparent)]
100 ParseIntError(#[from] num::ParseIntError),
101 #[error(transparent)]
102 ParseUrlError(#[from] url::ParseError),
103 #[error(transparent)]
104 ConfigError(#[from] config::ConfigError),
105 #[cfg(feature = "reliable_report")]
106 #[error(transparent)]
107 RedisError(#[from] RedisError),
108 #[error("Broadcast Error: {0}")]
109 BroadcastError(String),
110 #[error("Payload Error: {0}")]
111 PayloadError(String),
112 #[error("General Error: {0}")]
113 GeneralError(String),
114}
115
116impl ApcErrorKind {
117 pub fn status(&self) -> StatusCode {
119 match self {
120 Self::ParseIntError(_) | Self::ParseUrlError(_) => StatusCode::BAD_REQUEST,
121 _ => StatusCode::INTERNAL_SERVER_ERROR,
122 }
123 }
124
125 pub fn is_sentry_event(&self) -> bool {
126 match self {
127 Self::PayloadError(_) => false,
130 _ => true,
131 }
132 }
133
134 pub fn metric_label(&self) -> Option<&'static str> {
135 match self {
137 Self::PayloadError(_) => Some("payload"),
138 _ => None,
139 }
140 }
141}
142
143pub trait ReportableError: std::error::Error {
145 fn reportable_source(&self) -> Option<&(dyn ReportableError + 'static)> {
150 None
151 }
152
153 fn backtrace(&self) -> Option<&Backtrace> {
155 None
156 }
157 fn is_sentry_event(&self) -> bool {
159 true
160 }
161
162 fn metric_label(&self) -> Option<&'static str> {
165 None
166 }
167
168 fn tags(&self) -> Vec<(&str, String)> {
170 vec![]
171 }
172
173 fn extras(&self) -> Vec<(&str, String)> {
176 vec![]
177 }
178}
179
180impl ReportableError for ApcError {
181 fn backtrace(&self) -> Option<&Backtrace> {
182 Some(&self.backtrace)
183 }
184
185 fn is_sentry_event(&self) -> bool {
186 self.kind.is_sentry_event()
187 }
188
189 fn metric_label(&self) -> Option<&'static str> {
190 self.kind.metric_label()
191 }
192}