ipp_client/
lib.rs

1use std::{
2    fmt, io,
3    path::{Path, PathBuf},
4};
5
6use ipp_proto::{ipp::StatusCode, ParseError};
7
8pub use crate::client::IppClient;
9
10pub mod client;
11
12/// IPP error
13#[derive(Debug)]
14pub enum IppError {
15    /// HTTP error
16    HttpError(reqwest::Error),
17    /// Network or file I/O error
18    IOError(::std::io::Error),
19    /// IPP status error
20    StatusError(StatusCode),
21    /// Printer state error
22    PrinterStateError(Vec<String>),
23    /// Printer stopped
24    PrinterStopped,
25    /// Parameter error
26    ParamError(String),
27    /// Parsing error
28    ParseError(ParseError),
29    /// Missing attribute in response
30    MissingAttribute,
31    /// Invalid attribute type
32    InvalidAttributeType,
33}
34
35impl fmt::Display for IppError {
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        match *self {
38            IppError::HttpError(ref e) => write!(f, "{}", e),
39            IppError::IOError(ref e) => write!(f, "{}", e),
40            IppError::StatusError(ref e) => write!(f, "IPP status error: {}", e),
41            IppError::ParamError(ref e) => write!(f, "IPP param error: {}", e),
42            IppError::PrinterStateError(ref e) => write!(f, "IPP printer state error: {:?}", e),
43            IppError::PrinterStopped => write!(f, "IPP printer stopped"),
44            IppError::ParseError(ref e) => write!(f, "{}", e),
45            IppError::MissingAttribute => write!(f, "Missing attribute in response"),
46            IppError::InvalidAttributeType => write!(f, "Invalid attribute type"),
47        }
48    }
49}
50
51impl From<io::Error> for IppError {
52    fn from(error: io::Error) -> Self {
53        IppError::IOError(error)
54    }
55}
56
57impl From<StatusCode> for IppError {
58    fn from(code: StatusCode) -> Self {
59        IppError::StatusError(code)
60    }
61}
62
63impl From<reqwest::Error> for IppError {
64    fn from(error: reqwest::Error) -> Self {
65        IppError::HttpError(error)
66    }
67}
68
69impl From<ParseError> for IppError {
70    fn from(error: ParseError) -> Self {
71        IppError::ParseError(error)
72    }
73}
74
75impl std::error::Error for IppError {}
76
77/// Builder to create IPP client
78pub struct IppClientBuilder {
79    uri: String,
80    ca_certs: Vec<PathBuf>,
81    verify_hostname: bool,
82    verify_certificate: bool,
83    timeout: u64,
84}
85
86impl IppClientBuilder {
87    /// Create a client builder for a given URI
88    pub fn new(uri: &str) -> Self {
89        IppClientBuilder {
90            uri: uri.to_owned(),
91            ca_certs: Vec::new(),
92            verify_hostname: true,
93            verify_certificate: true,
94            timeout: 0,
95        }
96    }
97
98    /// Add CA certificate
99    pub fn ca_cert<P>(mut self, path: P) -> Self
100    where
101        P: AsRef<Path>,
102    {
103        self.ca_certs.push(path.as_ref().to_owned());
104        self
105    }
106
107    /// Add CA certificates
108    pub fn ca_certs<I, P>(mut self, paths: I) -> Self
109    where
110        I: IntoIterator<Item = P>,
111        P: AsRef<Path>,
112    {
113        self.ca_certs.extend(paths.into_iter().map(|p| p.as_ref().to_owned()));
114        self
115    }
116
117    /// Enable or disable host name verification. Default is true.
118    pub fn verify_hostname(mut self, verify: bool) -> Self {
119        self.verify_hostname = verify;
120        self
121    }
122
123    /// Enable or disable server certificate verification. Default is true.
124    pub fn verify_certificate(mut self, verify: bool) -> Self {
125        self.verify_certificate = verify;
126        self
127    }
128
129    /// Set network timeout in seconds. Default is 0 (no timeout)
130    pub fn timeout(mut self, timeout: u64) -> Self {
131        self.timeout = timeout;
132        self
133    }
134
135    /// Build the client
136    pub fn build(self) -> IppClient {
137        IppClient {
138            uri: self.uri,
139            ca_certs: self.ca_certs,
140            verify_hostname: self.verify_hostname,
141            verify_certificate: self.verify_certificate,
142            timeout: self.timeout,
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn test_builder() {
153        let mut builder = IppClientBuilder::new("foobar");
154        assert_eq!(builder.uri, "foobar");
155
156        let cert = PathBuf::from("mycert");
157        builder = builder.ca_cert(&cert);
158        assert_eq!(builder.ca_certs, vec![cert.clone()]);
159
160        builder = builder.ca_certs(&[cert.clone()]);
161        assert_eq!(builder.ca_certs, vec![cert.clone(), cert.clone()]);
162
163        builder = builder.verify_hostname(false);
164        assert!(!builder.verify_hostname);
165
166        builder = builder.verify_certificate(false);
167        assert!(!builder.verify_certificate);
168
169        builder = builder.timeout(100);
170        assert_eq!(builder.timeout, 100);
171
172        let _ = builder.build();
173    }
174}