-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patherror.rs
More file actions
147 lines (128 loc) · 5.21 KB
/
error.rs
File metadata and controls
147 lines (128 loc) · 5.21 KB
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
136
137
138
139
140
141
142
143
144
145
146
147
use magnus::{
Error as MagnusError, RModule, Ruby, exception::ExceptionClass, prelude::*, value::Lazy,
};
use tokio::sync::mpsc::error::SendError;
const RACE_CONDITION_ERROR_MSG: &str = r#"Due to Rust's memory management with borrowing,
you cannot use certain instances multiple times as they may be consumed.
This error can occur in the following cases:
1) You passed a non-clonable instance to a function that requires ownership.
2) You attempted to use a method that consumes ownership more than once (e.g., reading a response body twice).
3) You tried to reference an instance after it was borrowed.
Potential solutions:
1) Avoid sharing instances; create a new instance each time you use it.
2) Refrain from performing actions that consume ownership multiple times.
3) Change the order of operations to reference the instance before borrowing it.
"#;
static WREQ: Lazy<RModule> = Lazy::new(|ruby| ruby.define_module(crate::RUBY_MODULE_NAME).unwrap());
macro_rules! define_exception {
($name:ident, $ruby_name:literal, $parent_method:ident) => {
static $name: Lazy<ExceptionClass> = Lazy::new(|ruby| {
ruby.get_inner(&WREQ)
.define_error($ruby_name, ruby.$parent_method())
.unwrap()
});
};
}
macro_rules! map_wreq_error {
($ruby:expr, $err:expr, $msg:expr, $($check_method:ident => $exception:ident),* $(,)?) => {
{
$(
if $err.$check_method() {
return MagnusError::new($ruby.get_inner(&$exception), $msg);
}
)*
MagnusError::new($ruby.exception_runtime_error(), $msg)
}
};
}
// System-level and runtime errors
define_exception!(MEMORY, "MemoryError", exception_runtime_error);
// Network connection errors
define_exception!(CONNECTION_ERROR, "ConnectionError", exception_runtime_error);
define_exception!(
PROXY_CONNECTION_ERROR,
"ProxyConnectionError",
exception_runtime_error
);
define_exception!(
CONNECTION_RESET_ERROR,
"ConnectionResetError",
exception_runtime_error
);
define_exception!(TLS_ERROR, "TlsError", exception_runtime_error);
// HTTP protocol and request/response errors
define_exception!(REQUEST_ERROR, "RequestError", exception_runtime_error);
define_exception!(STATUS_ERROR, "StatusError", exception_runtime_error);
define_exception!(REDIRECT_ERROR, "RedirectError", exception_runtime_error);
define_exception!(TIMEOUT_ERROR, "TimeoutError", exception_runtime_error);
// Data processing and encoding errors
define_exception!(BODY_ERROR, "BodyError", exception_runtime_error);
define_exception!(DECODING_ERROR, "DecodingError", exception_runtime_error);
// Configuration and builder errors
define_exception!(BUILDER_ERROR, "BuilderError", exception_runtime_error);
// Thread interruption error
define_exception!(INTERRUPT_ERROR, "InterruptError", exception_interrupt);
/// Memory error constant
pub fn memory_error() -> MagnusError {
MagnusError::new(ruby!().get_inner(&MEMORY), RACE_CONDITION_ERROR_MSG)
}
/// Thread interruption error (raised when Thread.kill cancels a request)
pub fn interrupt_error() -> MagnusError {
MagnusError::new(ruby!().get_inner(&INTERRUPT_ERROR), "request interrupted")
}
/// Map [`tokio::sync::mpsc::error::SendError`] to corresponding [`magnus::Error`]
pub fn mpsc_send_error_to_magnus<T>(err: SendError<T>) -> MagnusError {
MagnusError::new(
ruby!().get_inner(&BODY_ERROR),
format!("failed to send body chunk: {}", err),
)
}
/// Map [`wreq::header::InvalidHeaderName`] to corresponding [`magnus::Error`]
pub fn header_name_error_to_magnus(err: wreq::header::InvalidHeaderName) -> MagnusError {
MagnusError::new(
ruby!().get_inner(&BUILDER_ERROR),
format!("invalid header name: {err}"),
)
}
/// Map [`wreq::header::InvalidHeaderValue`] to corresponding [`magnus::Error`]
pub fn header_value_error_to_magnus(err: wreq::header::InvalidHeaderValue) -> MagnusError {
MagnusError::new(
ruby!().get_inner(&BUILDER_ERROR),
format!("invalid header value: {err}"),
)
}
/// Map [`wreq::Error`] to corresponding [`magnus::Error`]
pub fn wreq_error_to_magnus(err: wreq::Error) -> MagnusError {
let error_msg = err.to_string();
map_wreq_error!(
ruby!(),
err,
error_msg,
is_builder => BUILDER_ERROR,
is_body => BODY_ERROR,
is_tls => TLS_ERROR,
is_connection_reset => CONNECTION_RESET_ERROR,
is_connect => CONNECTION_ERROR,
is_proxy_connect => PROXY_CONNECTION_ERROR,
is_decode => DECODING_ERROR,
is_redirect => REDIRECT_ERROR,
is_timeout => TIMEOUT_ERROR,
is_status => STATUS_ERROR,
is_request => REQUEST_ERROR,
)
}
pub fn include(ruby: &Ruby) {
Lazy::force(&MEMORY, ruby);
Lazy::force(&CONNECTION_ERROR, ruby);
Lazy::force(&PROXY_CONNECTION_ERROR, ruby);
Lazy::force(&CONNECTION_RESET_ERROR, ruby);
Lazy::force(&TLS_ERROR, ruby);
Lazy::force(&REQUEST_ERROR, ruby);
Lazy::force(&STATUS_ERROR, ruby);
Lazy::force(&REDIRECT_ERROR, ruby);
Lazy::force(&TIMEOUT_ERROR, ruby);
Lazy::force(&BODY_ERROR, ruby);
Lazy::force(&DECODING_ERROR, ruby);
Lazy::force(&BUILDER_ERROR, ruby);
Lazy::force(&INTERRUPT_ERROR, ruby);
}