1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::{io, net::SocketAddr, sync::Arc};

use futures::future::IntoFuture;
use futures::{Future, Poll, Stream};
use hyper::{service::service_fn, Body, Chunk, Request, Response, Server};
use log::debug;

use ipp_proto::{
    attribute::STATUS_MESSAGE, ipp::DelimiterTag, AsyncIppParser, IppAttribute, IppRequestResponse, IppValue,
};

use crate::handler::IppRequestHandler;

struct DummyHandler;
impl IppRequestHandler for DummyHandler {}

/// Server-related errors
#[derive(Debug)]
pub enum ServerError {
    HyperError(hyper::Error),
    IOError(io::Error),
}

impl From<hyper::Error> for ServerError {
    fn from(err: hyper::Error) -> Self {
        ServerError::HyperError(err)
    }
}

impl From<io::Error> for ServerError {
    fn from(err: io::Error) -> Self {
        ServerError::IOError(err)
    }
}

/// IPP server
pub struct IppServer {
    inner: Box<dyn Future<Item = (), Error = ServerError> + Send>,
}

impl IppServer {
    fn new(address: SocketAddr, handler: Arc<dyn IppRequestHandler + Send + Sync>) -> Result<IppServer, ServerError> {
        let inner = Server::try_bind(&address)?
            .serve(move || {
                let handler = handler.clone();
                service_fn(move |req: Request<Body>| {
                    let stream: Box<dyn Stream<Item = Chunk, Error = io::Error> + Send> = Box::new(
                        req.into_body()
                            .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())),
                    );

                    let handler = handler.clone();

                    AsyncIppParser::from(stream).map(move |result| {
                        debug!("Received request, payload present: {}", result.payload.is_some());

                        let request = IppRequestResponse::from_parse_result(result);
                        let req_id = request.header().request_id;

                        let response = match handler.handle_request(request) {
                            Ok(response) => response,
                            Err(status) => {
                                let mut response = IppRequestResponse::new_response(handler.version(), status, req_id);
                                response.attributes_mut().add(
                                    DelimiterTag::OperationAttributes,
                                    IppAttribute::new(
                                        STATUS_MESSAGE,
                                        IppValue::TextWithoutLanguage(status.to_string()),
                                    ),
                                );
                                response
                            }
                        };
                        Response::new(Body::wrap_stream(response.into_stream()))
                    })
                })
            })
            .map_err(ServerError::from);

        Ok(IppServer { inner: Box::new(inner) })
    }
}

impl Future for IppServer {
    type Item = ();
    type Error = ServerError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.inner.poll()
    }
}

/// Builder to create IPP servers
pub struct IppServerBuilder {
    address: SocketAddr,
    handler: Arc<dyn IppRequestHandler + Send + Sync>,
}

impl IppServerBuilder {
    /// Create builder for a given listening address
    pub fn new<S>(address: S) -> IppServerBuilder
    where
        SocketAddr: From<S>,
    {
        IppServerBuilder {
            address: address.into(),
            handler: Arc::new(DummyHandler),
        }
    }

    /// Set request handler
    pub fn handler(mut self, handler: Arc<dyn IppRequestHandler + Send + Sync>) -> Self {
        self.handler = handler;
        self
    }

    /// Build server
    pub fn build(self) -> impl Future<Item = IppServer, Error = ServerError> {
        IppServer::new(self.address, self.handler).into_future()
    }
}