| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| use std::error::Error; |
| use std::fmt; |
| |
| use http::HeaderValue; |
| |
| pub const GRPC_STATUS: &str = "grpc-status"; |
| pub const GRPC_MESSAGE: &str = "grpc-message"; |
| |
| /// error codes for grpc APIs |
| /// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| pub enum Code { |
| // Not an error; returned on success |
| // |
| // HTTP Mapping: 200 OK |
| Ok = 0, |
| |
| // The operation was cancelled, typically by the caller. |
| // |
| // HTTP Mapping: 499 Client Closed Request |
| Cancelled = 1, |
| |
| // Unknown error. For example, this error may be returned when |
| // a `Status` value received from another address space belongs to |
| // an error space that is not known in this address space. Also |
| // errors raised by APIs that do not return enough error information |
| // may be converted to this error. |
| // |
| // HTTP Mapping: 500 INTERNAL Server Error |
| Unknown = 2, |
| |
| // The client specified an invalid argument. Note that this differs |
| // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments |
| // that are problematic regardless of the state of the system |
| // (e.g., a malformed file name). |
| // |
| // HTTP Mapping: 400 Bad Request |
| InvalidArgument = 3, |
| |
| // The deadline expired before the operation could complete. For operations |
| // that change the state of the system, this error may be returned |
| // even if the operation has completed successfully. For example, a |
| // successful response from a server could have been delayed long |
| // enough for the deadline to expire. |
| // |
| // HTTP Mapping: 504 Gateway Timeout |
| DeadlineExceeded = 4, |
| |
| // Some requested entity (e.g., file or directory) was not found. |
| // |
| // Note to server developers: if a request is denied for an entire class |
| // of users, such as gradual feature rollout or undocumented whitelist, |
| // `NOT_FOUND` may be used. If a request is denied for some users within |
| // a class of users, such as user-based access control, `PERMISSION_DENIED` |
| // must be used. |
| // |
| // HTTP Mapping: 404 Not Found |
| NotFound = 5, |
| |
| // The entity that a client attempted to create (e.g., file or directory) |
| // already exists. |
| // |
| // HTTP Mapping: 409 Conflict |
| AlreadyExists = 6, |
| |
| // The caller does not have permission to execute the specified |
| // operation. `PERMISSION_DENIED` must not be used for rejections |
| // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` |
| // instead for those errors). `PERMISSION_DENIED` must not be |
| // used if the caller can not be identified (use `UNAUTHENTICATED` |
| // instead for those errors). This error code does not imply the |
| // request is valid or the requested entity exists or satisfies |
| // other pre-conditions. |
| // |
| // HTTP Mapping: 403 Forbidden |
| PermissionDenied = 7, |
| |
| // Some resource has been exhausted, perhaps a per-user quota, or |
| // perhaps the entire file system is out of space. |
| // |
| // HTTP Mapping: 429 Too Many Requests |
| ResourceExhausted = 8, |
| |
| // The operation was rejected because the system is not in a state |
| // required for the operation's execution. For example, the directory |
| // to be deleted is non-empty, an rmdir operation is applied to |
| // a non-directory, etc. |
| // |
| // Service implementors can use the following guidelines to decide |
| // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: |
| // (a) Use `UNAVAILABLE` if the client can retry just the failing call. |
| // (b) Use `ABORTED` if the client should retry at a higher level |
| // (e.g., when a client-specified test-and-set fails, indicating the |
| // client should restart a read-modify-write sequence). |
| // (c) Use `FAILED_PRECONDITION` if the client should not retry until |
| // the system state has been explicitly fixed. E.g., if an "rmdir" |
| // fails because the directory is non-empty, `FAILED_PRECONDITION` |
| // should be returned since the client should not retry unless |
| // the files are deleted from the directory. |
| // |
| // HTTP Mapping: 400 Bad Request |
| FailedPrecondition = 9, |
| |
| // The operation was aborted, typically due to a concurrency issue such as |
| // a sequencer check failure or transaction abort. |
| // |
| // See the guidelines above for deciding between `FAILED_PRECONDITION`, |
| // `ABORTED`, and `UNAVAILABLE`. |
| // |
| // HTTP Mapping: 409 Conflict |
| Aborted = 10, |
| |
| // The operation was attempted past the valid range. E.g., seeking or |
| // reading past end-of-file. |
| // |
| // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may |
| // be fixed if the system state changes. For example, a 32-bit file |
| // system will generate `INVALID_ARGUMENT` if asked to read at an |
| // offset that is not in the range [0,2^32-1], but it will generate |
| // `OUT_OF_RANGE` if asked to read from an offset past the current |
| // file size. |
| // |
| // There is a fair bit of overlap between `FAILED_PRECONDITION` and |
| // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific |
| // error) when it applies so that callers who are iterating through |
| // a space can easily look for an `OUT_OF_RANGE` error to detect when |
| // they are done. |
| // |
| // HTTP Mapping: 400 Bad Request |
| OutOfRange = 11, |
| |
| // The operation is not implemented or is not supported/enabled in this |
| // service. |
| // |
| // HTTP Mapping: 501 Not Implemented |
| Unimplemented = 12, |
| |
| // INTERNAL errors. This means that some invariants expected by the |
| // underlying system have been broken. This error code is reserved |
| // for serious errors. |
| // |
| // HTTP Mapping: 500 INTERNAL Server Error |
| Internal = 13, |
| |
| // The service is currently unavailable. This is most likely a |
| // transient condition, which can be corrected by retrying with |
| // a backoff. Note that it is not always safe to retry |
| // non-idempotent operations. |
| // |
| // See the guidelines above for deciding between `FAILED_PRECONDITION`, |
| // `ABORTED`, and `UNAVAILABLE`. |
| // |
| // HTTP Mapping: 503 Service Unavailable |
| Unavailable = 14, |
| |
| // Unrecoverable data loss or corruption. |
| // |
| // HTTP Mapping: 500 INTERNAL Server Error |
| DataLoss = 15, |
| |
| // The request does not have valid authentication credentials for the |
| // operation. |
| // |
| // HTTP Mapping: 401 Unauthorized |
| Unauthenticated = 16, |
| } |
| |
| impl Code { |
| pub fn from_i32(i: i32) -> Code { |
| Code::from(i) |
| } |
| |
| pub fn description(&self) -> &'static str { |
| match self { |
| Code::Ok => "The operation completed successfully", |
| Code::Unknown => "Unknown error", |
| Code::Unimplemented => "Operation is not implemented or not supported", |
| Code::Internal => "Internal error", |
| _ => "aa", |
| } |
| } |
| |
| pub fn to_http_header_value(&self) -> HeaderValue { |
| match *self { |
| Code::Ok => HeaderValue::from_static("0"), |
| Code::Cancelled => HeaderValue::from_static("1"), |
| Code::Unknown => HeaderValue::from_static("2"), |
| Code::InvalidArgument => HeaderValue::from_static("3"), |
| Code::DeadlineExceeded => HeaderValue::from_static("4"), |
| Code::NotFound => HeaderValue::from_static("5"), |
| Code::AlreadyExists => HeaderValue::from_static("6"), |
| Code::PermissionDenied => HeaderValue::from_static("7"), |
| Code::ResourceExhausted => HeaderValue::from_static("8"), |
| Code::FailedPrecondition => HeaderValue::from_static("9"), |
| Code::Aborted => HeaderValue::from_static("10"), |
| Code::OutOfRange => HeaderValue::from_static("11"), |
| Code::Unimplemented => HeaderValue::from_static("12"), |
| Code::Internal => HeaderValue::from_static("13"), |
| Code::Unavailable => HeaderValue::from_static("14"), |
| Code::DataLoss => HeaderValue::from_static("15"), |
| Code::Unauthenticated => HeaderValue::from_static("16"), |
| } |
| } |
| } |
| |
| impl std::fmt::Display for Code { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| std::fmt::Display::fmt(self.description(), f) |
| } |
| } |
| |
| impl From<i32> for Code { |
| fn from(i: i32) -> Self { |
| match i { |
| 0 => Code::Ok, |
| 1 => Code::Cancelled, |
| 2 => Code::Unknown, |
| 3 => Code::InvalidArgument, |
| 4 => Code::DeadlineExceeded, |
| 5 => Code::NotFound, |
| 6 => Code::AlreadyExists, |
| 7 => Code::PermissionDenied, |
| 8 => Code::ResourceExhausted, |
| 9 => Code::FailedPrecondition, |
| 10 => Code::Aborted, |
| 11 => Code::OutOfRange, |
| 12 => Code::Unimplemented, |
| 13 => Code::Internal, |
| 14 => Code::Unavailable, |
| 15 => Code::DataLoss, |
| 16 => Code::Unauthenticated, |
| |
| _ => Code::Unknown, |
| } |
| } |
| } |
| |
| #[derive(Debug, Clone)] |
| pub struct Status { |
| // grpc-status |
| code: Code, |
| |
| // grpc-message |
| message: String, |
| } |
| |
| impl Status { |
| pub fn new(code: Code, message: impl Into<String>) -> Self { |
| Status { |
| code, |
| message: message.into(), |
| } |
| } |
| |
| pub fn with_message(self, message: impl Into<String>) -> Self { |
| Status { |
| message: message.into(), |
| ..self |
| } |
| } |
| |
| pub fn from_std_erro<T: std::error::Error>(err: T) -> Self { |
| Status::new(Code::Internal, err.to_string()) |
| } |
| |
| pub fn from_error(err: crate::Error) -> Self { |
| Status::new(Code::Internal, err.to_string()) |
| } |
| |
| pub fn code(&self) -> Code { |
| self.code |
| } |
| |
| pub fn to_http(&self) -> http::Response<crate::BoxBody> { |
| let (mut parts, _) = http::Response::new(()).into_parts(); |
| |
| parts.headers.insert( |
| http::header::CONTENT_TYPE, |
| http::HeaderValue::from_static("application/grpc"), |
| ); |
| |
| parts |
| .headers |
| .insert(GRPC_STATUS, self.code.to_http_header_value()); |
| parts.headers.insert( |
| GRPC_MESSAGE, |
| http::HeaderValue::from_str(&self.message).unwrap(), |
| ); |
| |
| parts.headers.insert( |
| "grpc-accept-encoding", |
| http::HeaderValue::from_static("gzip,identity"), |
| ); |
| |
| http::Response::from_parts(parts, crate::empty_body()) |
| } |
| |
| pub fn to_hyper_body(&self) -> http::Response<hyper::Body> { |
| let (mut parts, _) = http::Response::new(()).into_parts(); |
| |
| parts.headers.insert( |
| http::header::CONTENT_TYPE, |
| http::HeaderValue::from_static("application/grpc"), |
| ); |
| |
| parts |
| .headers |
| .insert(GRPC_STATUS, self.code.to_http_header_value()); |
| parts.headers.insert( |
| GRPC_MESSAGE, |
| http::HeaderValue::from_str(&self.message).unwrap(), |
| ); |
| |
| parts.headers.insert( |
| "grpc-accept-encoding", |
| http::HeaderValue::from_static("gzip,identity"), |
| ); |
| |
| http::Response::from_parts(parts, hyper::Body::empty()) |
| } |
| } |
| |
| impl From<std::io::Error> for Status { |
| fn from(err: std::io::Error) -> Self { |
| Status::new(crate::status::Code::Internal, err.to_string()) |
| } |
| } |
| |
| impl std::fmt::Display for Status { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| f.write_fmt(format_args!( |
| "grpc status, code: {}, message: {}", |
| self.code, self.message |
| )) |
| } |
| } |
| |
| impl Error for Status {} |
| |
| #[derive(Debug)] |
| pub struct DubboError { |
| message: String, |
| } |
| |
| impl DubboError { |
| pub fn new(message: String) -> Self { |
| Self { message } |
| } |
| } |
| |
| impl fmt::Display for DubboError { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(f, "Dubbo internal Error: {}", self.message) |
| } |
| } |
| |
| impl Error for DubboError {} |
| |
| unsafe impl Send for DubboError {} |
| |
| unsafe impl Sync for DubboError {} |