1use relay_auth::{KeyParseError, UnpackError};
2use relay_event_normalization::GeoIpError;
3use relay_event_schema::processor::ProcessingAction;
4use relay_ffi::Panic;
5use sentry_release_parser::InvalidRelease;
6
7use crate::core::RelayStr;
8
9#[repr(u32)]
11#[allow(missing_docs)]
12pub enum RelayErrorCode {
13 NoError = 0,
14 Panic = 1,
15 Unknown = 2,
16
17 InvalidJsonError = 101, KeyParseErrorBadEncoding = 1000,
21 KeyParseErrorBadKey = 1001,
22
23 UnpackErrorBadSignature = 1003,
25 UnpackErrorBadPayload = 1004,
26 UnpackErrorSignatureExpired = 1005,
27 UnpackErrorBadEncoding = 1006,
28 UnpackErrorRelayIdMismatch = 1007,
29
30 ProcessingErrorInvalidTransaction = 2001,
32 ProcessingErrorInvalidGeoIp = 2002,
33
34 InvalidReleaseErrorTooLong = 3001,
36 InvalidReleaseErrorRestrictedName = 3002,
37 InvalidReleaseErrorBadCharacters = 3003,
38
39 PatternError = 4001,
41 PatternOutOfGas = 4002,
43}
44
45impl RelayErrorCode {
46 pub fn from_error(error: &anyhow::Error) -> RelayErrorCode {
48 for cause in error.chain() {
49 if cause.downcast_ref::<Panic>().is_some() {
50 return RelayErrorCode::Panic;
51 }
52 if cause.downcast_ref::<serde_json::Error>().is_some() {
53 return RelayErrorCode::InvalidJsonError;
54 }
55 if cause.downcast_ref::<GeoIpError>().is_some() {
56 return RelayErrorCode::ProcessingErrorInvalidGeoIp;
57 }
58 if cause.downcast_ref::<relay_pattern::Error>().is_some() {
59 return RelayErrorCode::PatternError;
60 }
61 if cause.downcast_ref::<relay_pattern::OutOfGas>().is_some() {
62 return RelayErrorCode::PatternOutOfGas;
63 }
64 if let Some(err) = cause.downcast_ref::<KeyParseError>() {
65 return match err {
66 KeyParseError::BadEncoding => RelayErrorCode::KeyParseErrorBadEncoding,
67 KeyParseError::BadKey => RelayErrorCode::KeyParseErrorBadKey,
68 };
69 }
70 if let Some(err) = cause.downcast_ref::<UnpackError>() {
71 return match err {
72 UnpackError::BadSignature => RelayErrorCode::UnpackErrorBadSignature,
73 UnpackError::BadPayload(..) => RelayErrorCode::UnpackErrorBadPayload,
74 UnpackError::Time(_) => RelayErrorCode::UnpackErrorSignatureExpired,
75 UnpackError::BadEncoding => RelayErrorCode::UnpackErrorBadEncoding,
76 UnpackError::RelayIdMismatch => RelayErrorCode::UnpackErrorRelayIdMismatch,
77 };
78 }
79 if let Some(err) = cause.downcast_ref::<ProcessingAction>() {
80 return match err {
81 ProcessingAction::InvalidTransaction(_) => {
82 RelayErrorCode::ProcessingErrorInvalidTransaction
83 }
84 _ => RelayErrorCode::Unknown,
85 };
86 }
87 if let Some(err) = cause.downcast_ref::<InvalidRelease>() {
88 return match err {
89 InvalidRelease::TooLong => RelayErrorCode::InvalidReleaseErrorTooLong,
90 InvalidRelease::RestrictedName => {
91 RelayErrorCode::InvalidReleaseErrorRestrictedName
92 }
93 InvalidRelease::BadCharacters => {
94 RelayErrorCode::InvalidReleaseErrorBadCharacters
95 }
96 };
97 }
98 }
99 RelayErrorCode::Unknown
100 }
101}
102
103#[unsafe(no_mangle)]
105pub extern "C" fn relay_init() {
106 relay_ffi::set_panic_hook();
107}
108
109#[unsafe(no_mangle)]
113pub extern "C" fn relay_err_get_last_code() -> RelayErrorCode {
114 relay_ffi::with_last_error(RelayErrorCode::from_error).unwrap_or(RelayErrorCode::NoError)
115}
116
117#[unsafe(no_mangle)]
122pub extern "C" fn relay_err_get_last_message() -> RelayStr {
123 use std::fmt::Write;
124 relay_ffi::with_last_error(|err| {
125 let mut msg = err.to_string();
126 for cause in err.chain().skip(1) {
127 write!(&mut msg, "\n caused by: {cause}").ok();
128 }
129 RelayStr::from_string(msg)
130 })
131 .unwrap_or_default()
132}
133
134#[unsafe(no_mangle)]
136pub extern "C" fn relay_err_get_backtrace() -> RelayStr {
137 let backtrace = relay_ffi::with_last_error(|error| error.backtrace().to_string())
138 .filter(|bt| !bt.is_empty());
139
140 match backtrace {
141 Some(backtrace) => RelayStr::from_string(format!("stacktrace: {backtrace}")),
142 None => RelayStr::default(),
143 }
144}
145
146#[unsafe(no_mangle)]
148pub extern "C" fn relay_err_clear() {
149 relay_ffi::take_last_error();
150}