apache_dubbo/
status.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18use std::error::Error;
19use std::fmt;
20
21use http::HeaderValue;
22
23pub const GRPC_STATUS: &str = "grpc-status";
24pub const GRPC_MESSAGE: &str = "grpc-message";
25
26/// error codes for grpc APIs
27/// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum Code {
30    // Not an error; returned on success
31    //
32    // HTTP Mapping: 200 OK
33    Ok = 0,
34
35    // The operation was cancelled, typically by the caller.
36    //
37    // HTTP Mapping: 499 Client Closed Request
38    Cancelled = 1,
39
40    // Unknown error.  For example, this error may be returned when
41    // a `Status` value received from another address space belongs to
42    // an error space that is not known in this address space.  Also
43    // errors raised by APIs that do not return enough error information
44    // may be converted to this error.
45    //
46    // HTTP Mapping: 500 INTERNAL Server Error
47    Unknown = 2,
48
49    // The client specified an invalid argument.  Note that this differs
50    // from `FAILED_PRECONDITION`.  `INVALID_ARGUMENT` indicates arguments
51    // that are problematic regardless of the state of the system
52    // (e.g., a malformed file name).
53    //
54    // HTTP Mapping: 400 Bad Request
55    InvalidArgument = 3,
56
57    // The deadline expired before the operation could complete. For operations
58    // that change the state of the system, this error may be returned
59    // even if the operation has completed successfully.  For example, a
60    // successful response from a server could have been delayed long
61    // enough for the deadline to expire.
62    //
63    // HTTP Mapping: 504 Gateway Timeout
64    DeadlineExceeded = 4,
65
66    // Some requested entity (e.g., file or directory) was not found.
67    //
68    // Note to server developers: if a request is denied for an entire class
69    // of users, such as gradual feature rollout or undocumented whitelist,
70    // `NOT_FOUND` may be used. If a request is denied for some users within
71    // a class of users, such as user-based access control, `PERMISSION_DENIED`
72    // must be used.
73    //
74    // HTTP Mapping: 404 Not Found
75    NotFound = 5,
76
77    // The entity that a client attempted to create (e.g., file or directory)
78    // already exists.
79    //
80    // HTTP Mapping: 409 Conflict
81    AlreadyExists = 6,
82
83    // The caller does not have permission to execute the specified
84    // operation. `PERMISSION_DENIED` must not be used for rejections
85    // caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
86    // instead for those errors). `PERMISSION_DENIED` must not be
87    // used if the caller can not be identified (use `UNAUTHENTICATED`
88    // instead for those errors). This error code does not imply the
89    // request is valid or the requested entity exists or satisfies
90    // other pre-conditions.
91    //
92    // HTTP Mapping: 403 Forbidden
93    PermissionDenied = 7,
94
95    // Some resource has been exhausted, perhaps a per-user quota, or
96    // perhaps the entire file system is out of space.
97    //
98    // HTTP Mapping: 429 Too Many Requests
99    ResourceExhausted = 8,
100
101    // The operation was rejected because the system is not in a state
102    // required for the operation's execution.  For example, the directory
103    // to be deleted is non-empty, an rmdir operation is applied to
104    // a non-directory, etc.
105    //
106    // Service implementors can use the following guidelines to decide
107    // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`:
108    //  (a) Use `UNAVAILABLE` if the client can retry just the failing call.
109    //  (b) Use `ABORTED` if the client should retry at a higher level
110    //      (e.g., when a client-specified test-and-set fails, indicating the
111    //      client should restart a read-modify-write sequence).
112    //  (c) Use `FAILED_PRECONDITION` if the client should not retry until
113    //      the system state has been explicitly fixed.  E.g., if an "rmdir"
114    //      fails because the directory is non-empty, `FAILED_PRECONDITION`
115    //      should be returned since the client should not retry unless
116    //      the files are deleted from the directory.
117    //
118    // HTTP Mapping: 400 Bad Request
119    FailedPrecondition = 9,
120
121    // The operation was aborted, typically due to a concurrency issue such as
122    // a sequencer check failure or transaction abort.
123    //
124    // See the guidelines above for deciding between `FAILED_PRECONDITION`,
125    // `ABORTED`, and `UNAVAILABLE`.
126    //
127    // HTTP Mapping: 409 Conflict
128    Aborted = 10,
129
130    // The operation was attempted past the valid range.  E.g., seeking or
131    // reading past end-of-file.
132    //
133    // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may
134    // be fixed if the system state changes. For example, a 32-bit file
135    // system will generate `INVALID_ARGUMENT` if asked to read at an
136    // offset that is not in the range [0,2^32-1], but it will generate
137    // `OUT_OF_RANGE` if asked to read from an offset past the current
138    // file size.
139    //
140    // There is a fair bit of overlap between `FAILED_PRECONDITION` and
141    // `OUT_OF_RANGE`.  We recommend using `OUT_OF_RANGE` (the more specific
142    // error) when it applies so that callers who are iterating through
143    // a space can easily look for an `OUT_OF_RANGE` error to detect when
144    // they are done.
145    //
146    // HTTP Mapping: 400 Bad Request
147    OutOfRange = 11,
148
149    // The operation is not implemented or is not supported/enabled in this
150    // service.
151    //
152    // HTTP Mapping: 501 Not Implemented
153    Unimplemented = 12,
154
155    // INTERNAL errors.  This means that some invariants expected by the
156    // underlying system have been broken.  This error code is reserved
157    // for serious errors.
158    //
159    // HTTP Mapping: 500 INTERNAL Server Error
160    Internal = 13,
161
162    // The service is currently unavailable.  This is most likely a
163    // transient condition, which can be corrected by retrying with
164    // a backoff. Note that it is not always safe to retry
165    // non-idempotent operations.
166    //
167    // See the guidelines above for deciding between `FAILED_PRECONDITION`,
168    // `ABORTED`, and `UNAVAILABLE`.
169    //
170    // HTTP Mapping: 503 Service Unavailable
171    Unavailable = 14,
172
173    // Unrecoverable data loss or corruption.
174    //
175    // HTTP Mapping: 500 INTERNAL Server Error
176    DataLoss = 15,
177
178    // The request does not have valid authentication credentials for the
179    // operation.
180    //
181    // HTTP Mapping: 401 Unauthorized
182    Unauthenticated = 16,
183}
184
185impl Code {
186    pub fn from_i32(i: i32) -> Code {
187        Code::from(i)
188    }
189
190    pub fn description(&self) -> &'static str {
191        match self {
192            Code::Ok => "The operation completed successfully",
193            Code::Unknown => "Unknown error",
194            Code::Unimplemented => "Operation is not implemented or not supported",
195            Code::Internal => "Internal error",
196            _ => "aa",
197        }
198    }
199
200    pub fn to_http_header_value(&self) -> HeaderValue {
201        match *self {
202            Code::Ok => HeaderValue::from_static("0"),
203            Code::Cancelled => HeaderValue::from_static("1"),
204            Code::Unknown => HeaderValue::from_static("2"),
205            Code::InvalidArgument => HeaderValue::from_static("3"),
206            Code::DeadlineExceeded => HeaderValue::from_static("4"),
207            Code::NotFound => HeaderValue::from_static("5"),
208            Code::AlreadyExists => HeaderValue::from_static("6"),
209            Code::PermissionDenied => HeaderValue::from_static("7"),
210            Code::ResourceExhausted => HeaderValue::from_static("8"),
211            Code::FailedPrecondition => HeaderValue::from_static("9"),
212            Code::Aborted => HeaderValue::from_static("10"),
213            Code::OutOfRange => HeaderValue::from_static("11"),
214            Code::Unimplemented => HeaderValue::from_static("12"),
215            Code::Internal => HeaderValue::from_static("13"),
216            Code::Unavailable => HeaderValue::from_static("14"),
217            Code::DataLoss => HeaderValue::from_static("15"),
218            Code::Unauthenticated => HeaderValue::from_static("16"),
219        }
220    }
221}
222
223impl std::fmt::Display for Code {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        std::fmt::Display::fmt(self.description(), f)
226    }
227}
228
229impl From<i32> for Code {
230    fn from(i: i32) -> Self {
231        match i {
232            0 => Code::Ok,
233            1 => Code::Cancelled,
234            2 => Code::Unknown,
235            3 => Code::InvalidArgument,
236            4 => Code::DeadlineExceeded,
237            5 => Code::NotFound,
238            6 => Code::AlreadyExists,
239            7 => Code::PermissionDenied,
240            8 => Code::ResourceExhausted,
241            9 => Code::FailedPrecondition,
242            10 => Code::Aborted,
243            11 => Code::OutOfRange,
244            12 => Code::Unimplemented,
245            13 => Code::Internal,
246            14 => Code::Unavailable,
247            15 => Code::DataLoss,
248            16 => Code::Unauthenticated,
249
250            _ => Code::Unknown,
251        }
252    }
253}
254
255#[derive(Debug, Clone)]
256pub struct Status {
257    // grpc-status
258    code: Code,
259
260    // grpc-message
261    message: String,
262}
263
264impl Status {
265    pub fn new(code: Code, message: String) -> Self {
266        Status { code, message }
267    }
268
269    pub fn with_message(self, message: String) -> Self {
270        Status { message, ..self }
271    }
272
273    pub fn from_std_erro<T: std::error::Error>(err: T) -> Self {
274        Status::new(Code::Internal, err.to_string())
275    }
276
277    pub fn from_error(err: crate::Error) -> Self {
278        Status::new(Code::Internal, err.to_string())
279    }
280
281    pub fn code(&self) -> Code {
282        self.code
283    }
284
285    pub fn to_http(&self) -> http::Response<crate::BoxBody> {
286        let (mut parts, _) = http::Response::new(()).into_parts();
287
288        parts.headers.insert(
289            http::header::CONTENT_TYPE,
290            http::HeaderValue::from_static("application/grpc"),
291        );
292
293        parts
294            .headers
295            .insert(GRPC_STATUS, self.code.to_http_header_value());
296        parts.headers.insert(
297            GRPC_MESSAGE,
298            http::HeaderValue::from_str(&self.message).unwrap(),
299        );
300
301        parts.headers.insert(
302            "grpc-accept-encoding",
303            http::HeaderValue::from_static("gzip,identity"),
304        );
305
306        http::Response::from_parts(parts, crate::empty_body())
307    }
308}
309
310impl From<std::io::Error> for Status {
311    fn from(err: std::io::Error) -> Self {
312        Status::new(crate::status::Code::Internal, err.to_string())
313    }
314}
315
316impl std::fmt::Display for Status {
317    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318        f.write_fmt(format_args!(
319            "grpc status, code: {}, message: {}",
320            self.code, self.message
321        ))
322    }
323}
324
325impl Error for Status {}
326
327#[derive(Debug)]
328pub struct DubboError {
329    message: String,
330}
331
332impl DubboError {
333    pub fn new(message: String) -> Self {
334        Self { message }
335    }
336}
337
338impl fmt::Display for DubboError {
339    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        write!(f, "Dubbo internal Error: {}", self.message)
341    }
342}
343
344impl Error for DubboError {}
345
346unsafe impl Send for DubboError {}
347
348unsafe impl Sync for DubboError {}