1use axum::http::StatusCode;
2use prost::Message;
3use serde::Serialize;
4
5use crate::{prelude::RpcResult, response::RpcIntoResponse};
6
7#[derive(Clone, Serialize)]
8pub struct RpcError {
9 pub code: RpcErrorCode,
10 pub message: String,
11 pub details: Vec<RpcErrorDetail>,
12}
13
14pub trait RpcIntoError {
15 fn rpc_into_error(self) -> RpcError;
16}
17
18impl RpcIntoError for RpcError {
19 fn rpc_into_error(self) -> RpcError {
20 self
21 }
22}
23
24impl RpcError {
25 pub fn new(code: RpcErrorCode, message: String) -> Self {
26 Self {
27 code,
28 message,
29 details: vec![],
30 }
31 }
32}
33
34impl<C, M> RpcIntoError for (C, M)
35where
36 C: Into<RpcErrorCode>,
37 M: Into<String>,
38{
39 fn rpc_into_error(self) -> RpcError {
40 RpcError {
41 code: self.0.into(),
42 message: self.1.into(),
43 details: vec![],
44 }
45 }
46}
47
48#[derive(Clone, Serialize)]
49pub struct RpcErrorDetail {
50 #[serde(rename = "type")]
51 pub proto_type: String,
52 #[serde(rename = "value")]
53 pub proto_b62_value: String,
54}
55
56#[derive(Clone, Serialize)]
57#[serde(rename_all = "snake_case")]
58pub enum RpcErrorCode {
59 Canceled,
60 Unknown,
61 InvalidArgument,
62 DeadlineExceeded,
63 NotFound,
64 AlreadyExists,
65 PermissionDenied,
66 ResourceExhausted,
67 FailedPrecondition,
68 Aborted,
69 OutOfRange,
70 Unimplemented,
71 Internal,
72 Unavailable,
73 DataLoss,
74 Unauthenticated,
75}
76
77impl From<RpcErrorCode> for StatusCode {
78 fn from(val: RpcErrorCode) -> Self {
79 match val {
80 RpcErrorCode::Canceled => StatusCode::REQUEST_TIMEOUT,
82 RpcErrorCode::Unknown => StatusCode::INTERNAL_SERVER_ERROR,
83 RpcErrorCode::InvalidArgument => StatusCode::BAD_REQUEST,
84 RpcErrorCode::DeadlineExceeded => StatusCode::REQUEST_TIMEOUT,
85 RpcErrorCode::NotFound => StatusCode::NOT_FOUND,
86 RpcErrorCode::AlreadyExists => StatusCode::CONFLICT,
87 RpcErrorCode::PermissionDenied => StatusCode::FORBIDDEN,
88 RpcErrorCode::ResourceExhausted => StatusCode::TOO_MANY_REQUESTS,
89 RpcErrorCode::FailedPrecondition => StatusCode::PRECONDITION_FAILED,
90 RpcErrorCode::Aborted => StatusCode::CONFLICT,
91 RpcErrorCode::OutOfRange => StatusCode::BAD_REQUEST,
92 RpcErrorCode::Unimplemented => StatusCode::NOT_FOUND,
93 RpcErrorCode::Internal => StatusCode::INTERNAL_SERVER_ERROR,
94 RpcErrorCode::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
95 RpcErrorCode::DataLoss => StatusCode::INTERNAL_SERVER_ERROR,
96 RpcErrorCode::Unauthenticated => StatusCode::UNAUTHORIZED,
97 }
98 }
99}
100
101impl<T> RpcIntoResponse<T> for RpcErrorCode
102where
103 T: Message,
104{
105 fn rpc_into_response(self) -> RpcResult<T> {
106 Err(RpcError::new(self, "".to_string()))
107 }
108}
109
110impl<T> RpcIntoResponse<T> for RpcError
111where
112 T: Message,
113{
114 fn rpc_into_response(self) -> RpcResult<T> {
115 Err(self)
116 }
117}
118
119