Skip to main content

ntex_grpc/client/
mod.rs

1#![allow(async_fn_in_trait)]
2
3use ntex_bytes::Bytes;
4use ntex_error::{ErrorDiagnostic, ResultType};
5use ntex_h2::{OperationError, StreamError, client};
6use ntex_http::{HeaderMap, StatusCode, error::Error as HttpError};
7
8mod request;
9mod transport;
10
11pub use self::request::{Request, RequestContext, Response};
12
13use crate::{encoding::DecodeError, service::MethodDef, status::GrpcStatus};
14
15pub trait Transport<T: MethodDef> {
16    /// Errors produced by the transport.
17    type Error;
18
19    async fn request(
20        &self,
21        args: &T::Input,
22        ctx: &mut RequestContext,
23    ) -> Result<Response<T>, Self::Error>;
24}
25
26/// Client utils methods
27pub trait ClientInformation<T> {
28    /// Create new client instance
29    fn create(transport: T) -> Self;
30
31    /// Get reference to underlying transport
32    fn transport(&self) -> &T;
33
34    /// Get mut referece to underlying transport
35    fn transport_mut(&mut self) -> &mut T;
36
37    /// Consume client and return inner transport
38    fn into_inner(self) -> T;
39}
40
41#[derive(Clone)]
42pub struct Client(client::Client);
43
44impl Client {
45    #[inline]
46    /// Get reference to h2 client
47    pub fn new(client: client::Client) -> Self {
48        Self(client)
49    }
50
51    #[inline]
52    /// Get reference to h2 client
53    pub fn get_ref(&self) -> &client::Client {
54        &self.0
55    }
56}
57
58#[derive(thiserror::Error, Debug)]
59pub enum ClientError {
60    #[error("")]
61    Client(
62        #[from]
63        #[source]
64        client::ClientError,
65    ),
66    #[error("Http error {0:?}")]
67    Http(
68        #[from]
69        #[source]
70        HttpError,
71    ),
72    #[error("Decode")]
73    Decode(
74        #[from]
75        #[source]
76        DecodeError,
77    ),
78    #[error("HTTP2 Operation")]
79    Operation(
80        #[from]
81        #[source]
82        OperationError,
83    ),
84    #[error("HTTP2 Stream")]
85    Stream(
86        #[from]
87        #[source]
88        StreamError,
89    ),
90    #[error("Http response {0:?}, headers: {1:?}, body: {2:?}")]
91    Response(Option<StatusCode>, HeaderMap, Bytes),
92    #[error("Got eof without payload")]
93    UnexpectedEof(Option<StatusCode>, HeaderMap),
94    #[error("Deadline exceeded")]
95    DeadlineExceeded(HeaderMap),
96    #[error("Grpc status")]
97    GrpcStatus(GrpcStatus, HeaderMap),
98}
99
100impl Clone for ClientError {
101    fn clone(&self) -> Self {
102        match self {
103            Self::Client(err) => Self::Client(err.clone()),
104            Self::Http(err) => Self::Http(*err),
105            Self::Decode(err) => Self::Decode(err.clone()),
106            Self::Operation(err) => Self::Operation(err.clone()),
107            Self::Stream(err) => Self::Stream(*err),
108            Self::Response(st, hdrs, payload) => {
109                Self::Response(*st, hdrs.clone(), payload.clone())
110            }
111            Self::UnexpectedEof(st, hdrs) => Self::UnexpectedEof(*st, hdrs.clone()),
112            Self::DeadlineExceeded(hdrs) => Self::DeadlineExceeded(hdrs.clone()),
113            Self::GrpcStatus(st, hdrs) => Self::GrpcStatus(*st, hdrs.clone()),
114        }
115    }
116}
117
118impl ErrorDiagnostic for ClientError {
119    fn typ(&self) -> ResultType {
120        if matches!(self, ClientError::Http(_)) {
121            ResultType::ClientError
122        } else {
123            ResultType::ServiceError
124        }
125    }
126
127    fn signature(&self) -> &'static str {
128        match self {
129            ClientError::Client(err) => err.signature(),
130            ClientError::Http(_) => "grpc-Http",
131            ClientError::Decode(_) => "grpc-Decode",
132            ClientError::Operation(err) => err.signature(),
133            ClientError::Stream(err) => err.signature(),
134            ClientError::Response(_, _, _) => "grpc-Response",
135            ClientError::UnexpectedEof(_, _) => "grpc-UnexpectedEof",
136            ClientError::DeadlineExceeded(_) => "grpc-BackendCallTimedout",
137            ClientError::GrpcStatus(status, _) => status.signature(),
138        }
139    }
140}