Skip to main content

ntex_grpc/server/
mod.rs

1use std::ops;
2
3use ntex_bytes::{BytePages, ByteString, Bytes};
4use ntex_http::{HeaderMap, HeaderName, HeaderValue};
5
6mod error;
7mod service;
8
9pub use self::error::{MethodResult, ServerError, StreamResult};
10pub use self::service::GrpcServer;
11pub use crate::GrpcStatus;
12
13use crate::stream::CallStreams;
14use crate::{MethodDef, RecvStream, SendStream};
15
16/// A service that serves one gRPC service, such as `helloworld.Greeter`.
17///
18/// [`GrpcServer::new()`] and [`GrpcServer::service()`] pass it the calls for
19/// [`NAME`](Self::NAME).
20/// `#[server]` implements it for the type it is used on, implement it for
21/// the factory by hand otherwise.
22pub trait NamedService {
23    /// Full service name with the package, e.g. `helloworld.Greeter`.
24    const NAME: &'static str;
25
26    /// Returns `true` if `method` is a streaming method.
27    ///
28    /// The server passes a streaming call to the service as soon as its
29    /// headers arrive, with the request and response streams in
30    /// [`ServerRequest::streams`]. The other calls are passed once the
31    /// request message is read. `#[server]` implements it for the streaming
32    /// methods, the default returns `false`.
33    fn is_streaming(method: &str) -> bool {
34        let _ = method;
35        false
36    }
37}
38
39/// Helpers for the code `#[server]` generates.
40#[doc(hidden)]
41pub mod __private {
42    use super::{
43        CallStreams, GrpcStatus, MethodDef, RecvStream, SendStream, ServerError, ServerRequest,
44    };
45
46    /// Takes the streams of a streaming call.
47    ///
48    /// # Errors
49    ///
50    /// Fails if the call is not passed as a streaming call, e.g. the
51    /// service is added with `GrpcServer::service_named()`.
52    pub fn streams(req: &mut ServerRequest) -> Result<CallStreams, ServerError> {
53        req.streams.take().ok_or_else(|| {
54            ServerError::new(
55                GrpcStatus::Unimplemented,
56                crate::encode_grpc_message(&format!(
57                    "Streaming is not supported for method: {}",
58                    req.name
59                )),
60                None,
61            )
62        })
63    }
64
65    /// The request stream of method `M`.
66    pub fn recv<M: MethodDef>(_: &M, streams: &mut CallStreams) -> RecvStream<M::Input> {
67        streams.recv()
68    }
69
70    /// The response stream of method `M`.
71    pub fn send<M: MethodDef>(_: &M, streams: &mut CallStreams) -> SendStream<M::Output> {
72        streams.send()
73    }
74
75    /// Fails to compile if the handler kind does not match method `M`.
76    pub const fn check_kind<M: MethodDef, const CLIENT: bool, const SERVER: bool>(_: &M) {
77        const {
78            assert!(
79                M::CLIENT_STREAMING == CLIENT && M::SERVER_STREAMING == SERVER,
80                "The method signature does not match the streaming kind of the rpc"
81            );
82        }
83    }
84}
85
86/// A call as [`GrpcServer`] receives it, before the message is decoded.
87///
88/// The service given to `GrpcServer` handles these and answers with a
89/// [`ServerResponse`] or a [`ServerError`]. The `#[server]` attribute
90/// writes that service for you; implement it by hand only when you need
91/// the raw bytes.
92#[derive(Debug)]
93pub struct ServerRequest {
94    /// Full service name with the package, e.g. `helloworld.Greeter`.
95    pub service: ByteString,
96    /// Method name without the service, e.g. `SayHello`.
97    pub name: ByteString,
98    /// The encoded request message, without the 5-byte message prefix.
99    /// Empty for a streaming call.
100    pub payload: Bytes,
101    /// Request headers, plus the trailers if the client sent any. Only the
102    /// headers for a streaming call.
103    pub headers: HeaderMap,
104    /// The request and response streams of a streaming call, `None` for a
105    /// unary call.
106    #[doc(hidden)]
107    pub streams: Option<CallStreams>,
108}
109
110/// Successful answer to a [`ServerRequest`].
111#[derive(Debug)]
112pub struct ServerResponse {
113    /// The encoded reply message, the server adds the message prefix.
114    /// Ignored for a streaming call, its messages are sent on its stream.
115    pub payload: BytePages,
116    /// Extra trailers, sent after `grpc-status`. `grpc-status` and
117    /// `grpc-message` are ignored, the status is `OK`.
118    pub headers: Vec<(HeaderName, HeaderValue)>,
119}
120
121impl ServerResponse {
122    #[inline]
123    /// Answer with an encoded message and no extra trailers.
124    pub fn new(payload: BytePages) -> ServerResponse {
125        ServerResponse::with_headers(payload, Vec::new())
126    }
127
128    #[inline]
129    /// Answer with an encoded message and extra trailers.
130    pub fn with_headers(
131        payload: BytePages,
132        headers: Vec<(HeaderName, HeaderValue)>,
133    ) -> ServerResponse {
134        ServerResponse { payload, headers }
135    }
136}
137
138/// Argument types a `#[server]` method can take.
139///
140/// A method takes either the request message itself, or [`Request<T>`]
141/// when it also needs the headers:
142///
143/// ```rust,ignore
144/// #[server(helloworld::Greeter)]
145/// impl GreeterServer {
146///     // `req: HelloRequest` works too, if the headers are not needed
147///     #[method(SayHello)]
148///     async fn say_hello(&self, req: Request<HelloRequest>) -> HelloReply {
149///         let id = req.headers.get("x-request-id");
150///         // `req.name` is the method name, the message is in `req.message`
151///         HelloReply { message: format!("Hello {} ({id:?})", req.message.name).into() }
152///     }
153/// }
154/// ```
155pub trait FromRequest<T> {
156    /// Build the argument from the decoded request.
157    fn from(input: Request<T>) -> Self;
158}
159
160/// Decoded request message, with the method name and headers.
161///
162/// Derefs to the message. Message fields called `service`, `name`,
163/// `headers` or `message` are hidden behind the fields below, reach them through
164/// `req.message`.
165pub struct Request<T> {
166    /// Full service name with the package, e.g. `helloworld.Greeter`.
167    pub service: ByteString,
168    /// Method name, e.g. `SayHello`.
169    pub name: ByteString,
170    /// Request headers.
171    pub headers: HeaderMap,
172    /// The request message.
173    pub message: T,
174}
175
176impl<T> FromRequest<T> for T {
177    #[inline]
178    fn from(input: Request<T>) -> T {
179        ntex_h2::release_header_map(input.headers);
180        input.message
181    }
182}
183
184impl<T> FromRequest<T> for Request<T> {
185    #[inline]
186    fn from(input: Request<T>) -> Request<T> {
187        input
188    }
189}
190
191impl<T> Request<T> {
192    /// Take the request message and drop the headers.
193    pub fn into_inner(self) -> T {
194        ntex_h2::release_header_map(self.headers);
195        self.message
196    }
197}
198
199impl<T> ops::Deref for Request<T> {
200    type Target = T;
201
202    #[inline]
203    fn deref(&self) -> &T {
204        &self.message
205    }
206}
207
208impl<T> ops::DerefMut for Request<T> {
209    #[inline]
210    fn deref_mut(&mut self) -> &mut T {
211        &mut self.message
212    }
213}
214
215/// Reply message plus extra trailers.
216///
217/// A unary or client-streaming `#[server]` method can return it, or
218/// `Result<Response<T>, E>`, to send `headers` after `grpc-status`. See
219/// [`MethodResult`].
220pub struct Response<T> {
221    /// The reply message.
222    pub message: T,
223    /// Extra trailers, sent after `grpc-status`. `grpc-status` and
224    /// `grpc-message` are ignored, the status is `OK`.
225    pub headers: Vec<(HeaderName, HeaderValue)>,
226}
227
228impl<T> Response<T> {
229    /// Wrap a message, with no extra trailers.
230    pub fn new(message: T) -> Self {
231        Self {
232            message,
233            headers: Vec::new(),
234        }
235    }
236}
237
238impl<T> From<T> for Response<T> {
239    fn from(message: T) -> Self {
240        Response {
241            message,
242            headers: Vec::new(),
243        }
244    }
245}
246
247#[cfg(test)]
248mod tests {
249    use super::*;
250
251    fn pages(data: &[u8]) -> BytePages {
252        let mut buf = BytePages::default();
253        buf.extend_from_slice(data);
254        buf
255    }
256
257    #[test]
258    fn server_response() {
259        let res = ServerResponse::new(pages(b"hi"));
260        assert_eq!(res.payload.len(), 2);
261        assert!(res.headers.is_empty());
262
263        let res = ServerResponse::with_headers(
264            pages(b"hi"),
265            vec![(
266                HeaderName::from_static("x-a"),
267                HeaderValue::from_static("1"),
268            )],
269        );
270        assert_eq!(res.headers.len(), 1);
271        assert_eq!(res.headers[0].1, HeaderValue::from_static("1"));
272        assert!(format!("{res:?}").contains("ServerResponse"));
273    }
274
275    #[test]
276    fn server_request_debug() {
277        let req = ServerRequest {
278            service: ByteString::from_static("helloworld.Greeter"),
279            name: ByteString::from_static("SayHello"),
280            payload: Bytes::from_static(b"x"),
281            headers: HeaderMap::new(),
282            streams: None,
283        };
284        assert!(format!("{req:?}").contains("SayHello"));
285    }
286
287    fn request(message: u32) -> Request<u32> {
288        let mut headers = HeaderMap::new();
289        headers.insert(
290            HeaderName::from_static("x-a"),
291            HeaderValue::from_static("1"),
292        );
293        Request {
294            service: ByteString::from_static("helloworld.Greeter"),
295            name: ByteString::from_static("SayHello"),
296            headers,
297            message,
298        }
299    }
300
301    #[test]
302    fn from_request_message() {
303        // a method that only needs the message gets the message
304        assert_eq!(<u32 as FromRequest<u32>>::from(request(5)), 5);
305    }
306
307    #[test]
308    fn from_request_full() {
309        let req = <Request<u32> as FromRequest<u32>>::from(request(6));
310        assert_eq!(req.name, "SayHello");
311        assert_eq!(
312            req.headers.get("x-a").unwrap(),
313            &HeaderValue::from_static("1")
314        );
315        assert_eq!(*req, 6);
316        assert_eq!(req.into_inner(), 6);
317    }
318
319    #[test]
320    fn request_deref_mut() {
321        let mut req = request(7);
322        *req = 8;
323        assert_eq!(req.message, 8);
324    }
325
326    #[test]
327    fn response_wrapper() {
328        let res = Response::new(1_u32);
329        assert_eq!(res.message, 1);
330        assert!(res.headers.is_empty());
331
332        let res = <Response<u32> as From<u32>>::from(2_u32);
333        assert_eq!(res.message, 2);
334        assert!(res.headers.is_empty());
335    }
336}