use std::io::{self, Read};
use bytes::{BufMut, Bytes, BytesMut};
#[cfg(feature = "async")]
use futures_util::io::{AsyncRead, AsyncReadExt};
use http::Uri;
use log::trace;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{
attribute::{IppAttribute, IppAttributes},
model::{DelimiterTag, IppVersion, Operation, StatusCode},
payload::IppPayload,
value::*,
IppHeader,
};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct IppRequestResponse {
pub(crate) header: IppHeader,
pub(crate) attributes: IppAttributes,
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) payload: IppPayload,
}
impl IppRequestResponse {
pub fn new(version: IppVersion, operation: Operation, uri: Option<Uri>) -> IppRequestResponse {
let header = IppHeader::new(version, operation as u16, 1);
let mut attributes = IppAttributes::new();
attributes.add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::ATTRIBUTES_CHARSET, IppValue::Charset("utf-8".to_string())),
);
attributes.add(
DelimiterTag::OperationAttributes,
IppAttribute::new(
IppAttribute::ATTRIBUTES_NATURAL_LANGUAGE,
IppValue::NaturalLanguage("en".to_string()),
),
);
if let Some(uri) = uri {
attributes.add(
DelimiterTag::OperationAttributes,
IppAttribute::new(
IppAttribute::PRINTER_URI,
IppValue::Uri(crate::util::canonicalize_uri(&uri).to_string()),
),
);
}
IppRequestResponse {
header,
attributes,
payload: IppPayload::empty(),
}
}
pub fn new_response(version: IppVersion, status: StatusCode, id: u32) -> IppRequestResponse {
let header = IppHeader::new(version, status as u16, id);
let mut response = IppRequestResponse {
header,
attributes: IppAttributes::new(),
payload: IppPayload::empty(),
};
response.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(IppAttribute::ATTRIBUTES_CHARSET, IppValue::Charset("utf-8".to_string())),
);
response.attributes_mut().add(
DelimiterTag::OperationAttributes,
IppAttribute::new(
IppAttribute::ATTRIBUTES_NATURAL_LANGUAGE,
IppValue::NaturalLanguage("en".to_string()),
),
);
response
}
pub fn header(&self) -> &IppHeader {
&self.header
}
pub fn header_mut(&mut self) -> &mut IppHeader {
&mut self.header
}
pub fn attributes(&self) -> &IppAttributes {
&self.attributes
}
pub fn attributes_mut(&mut self) -> &mut IppAttributes {
&mut self.attributes
}
pub fn payload(&self) -> &IppPayload {
&self.payload
}
pub fn payload_mut(&mut self) -> &mut IppPayload {
&mut self.payload
}
pub fn to_bytes(&self) -> Bytes {
let mut buffer = BytesMut::new();
buffer.put(self.header.to_bytes());
buffer.put(self.attributes.to_bytes());
buffer.freeze()
}
#[cfg(feature = "async")]
pub fn into_async_read(self) -> impl AsyncRead + Send + Sync + 'static {
let header = self.to_bytes();
trace!("IPP header size: {}", header.len(),);
futures_util::io::Cursor::new(header).chain(self.payload)
}
pub fn into_read(self) -> impl Read + Send + Sync + 'static {
let header = self.to_bytes();
trace!("IPP header size: {}", header.len(),);
io::Cursor::new(header).chain(self.payload)
}
pub fn into_payload(self) -> IppPayload {
self.payload
}
}