ipp_server/
server.rs

1use std::{io, net::SocketAddr, sync::Arc};
2
3use futures::future::IntoFuture;
4use futures::{Future, Poll, Stream};
5use hyper::{service::service_fn, Body, Chunk, Request, Response, Server};
6use log::debug;
7
8use ipp_proto::{
9    attribute::STATUS_MESSAGE, ipp::DelimiterTag, AsyncIppParser, IppAttribute, IppRequestResponse, IppValue,
10};
11
12use crate::handler::IppRequestHandler;
13
14struct DummyHandler;
15impl IppRequestHandler for DummyHandler {}
16
17/// Server-related errors
18#[derive(Debug)]
19pub enum ServerError {
20    HyperError(hyper::Error),
21    IOError(io::Error),
22}
23
24impl From<hyper::Error> for ServerError {
25    fn from(err: hyper::Error) -> Self {
26        ServerError::HyperError(err)
27    }
28}
29
30impl From<io::Error> for ServerError {
31    fn from(err: io::Error) -> Self {
32        ServerError::IOError(err)
33    }
34}
35
36/// IPP server
37pub struct IppServer {
38    inner: Box<dyn Future<Item = (), Error = ServerError> + Send>,
39}
40
41impl IppServer {
42    fn new(address: SocketAddr, handler: Arc<dyn IppRequestHandler + Send + Sync>) -> Result<IppServer, ServerError> {
43        let inner = Server::try_bind(&address)?
44            .serve(move || {
45                let handler = handler.clone();
46                service_fn(move |req: Request<Body>| {
47                    let stream: Box<dyn Stream<Item = Chunk, Error = io::Error> + Send> = Box::new(
48                        req.into_body()
49                            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())),
50                    );
51
52                    let handler = handler.clone();
53
54                    AsyncIppParser::from(stream).map(move |result| {
55                        debug!("Received request, payload present: {}", result.payload.is_some());
56
57                        let request = IppRequestResponse::from_parse_result(result);
58                        let req_id = request.header().request_id;
59
60                        let response = match handler.handle_request(request) {
61                            Ok(response) => response,
62                            Err(status) => {
63                                let mut response = IppRequestResponse::new_response(handler.version(), status, req_id);
64                                response.attributes_mut().add(
65                                    DelimiterTag::OperationAttributes,
66                                    IppAttribute::new(
67                                        STATUS_MESSAGE,
68                                        IppValue::TextWithoutLanguage(status.to_string()),
69                                    ),
70                                );
71                                response
72                            }
73                        };
74                        Response::new(Body::wrap_stream(response.into_stream()))
75                    })
76                })
77            })
78            .map_err(ServerError::from);
79
80        Ok(IppServer { inner: Box::new(inner) })
81    }
82}
83
84impl Future for IppServer {
85    type Item = ();
86    type Error = ServerError;
87
88    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
89        self.inner.poll()
90    }
91}
92
93/// Builder to create IPP servers
94pub struct IppServerBuilder {
95    address: SocketAddr,
96    handler: Arc<dyn IppRequestHandler + Send + Sync>,
97}
98
99impl IppServerBuilder {
100    /// Create builder for a given listening address
101    pub fn new<S>(address: S) -> IppServerBuilder
102    where
103        SocketAddr: From<S>,
104    {
105        IppServerBuilder {
106            address: address.into(),
107            handler: Arc::new(DummyHandler),
108        }
109    }
110
111    /// Set request handler
112    pub fn handler(mut self, handler: Arc<dyn IppRequestHandler + Send + Sync>) -> Self {
113        self.handler = handler;
114        self
115    }
116
117    /// Build server
118    pub fn build(self) -> impl Future<Item = IppServer, Error = ServerError> {
119        IppServer::new(self.address, self.handler).into_future()
120    }
121}