blob: 68e15a4fdb05f884bc030938f78c7121ff3789ea [file] [log] [blame]
/*
* 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 {}