#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
use super::message::Request;
use super::service::ServiceError;
use crate::base::message_builder::AdditionalBuilder;
use crate::base::opt::{AllOptData, ComposeOptData, LongOptData, OptRecord};
use crate::base::{Message, MessageBuilder, ParsedName, Rtype, StreamTarget};
use crate::dep::octseq::Octets;
use crate::rdata::AllRecordData;
use std::boxed::Box;
use std::future::Future;
use std::pin::Pin;
use std::vec::Vec;
pub trait SingleService<RequestOcts: Send + Sync, RequestMeta, CR> {
fn call(
&self,
request: Request<RequestOcts, RequestMeta>,
) -> Pin<Box<dyn Future<Output = Result<CR, ServiceError>> + Send + Sync>>
where
RequestOcts: AsRef<[u8]> + Octets;
}
pub trait ComposeReply {
fn from_message<Octs>(msg: &Message<Octs>) -> Result<Self, ServiceError>
where
Octs: AsRef<[u8]>,
Self: Sized;
fn add_opt(
&mut self,
opt: &impl ComposeOptData,
) -> Result<(), LongOptData>;
fn additional_builder_stream_target(
&self,
) -> Result<AdditionalBuilder<StreamTarget<Vec<u8>>>, ServiceError>;
}
#[derive(Debug)]
pub struct ReplyMessage {
msg: Message<Vec<u8>>,
opt: Option<OptRecord<Vec<u8>>>,
}
impl ReplyMessage {
fn add_opt_impl(&mut self, opt: &impl ComposeOptData) {
self.opt_mut().push(opt).expect("push should not fail");
}
fn opt_mut(&mut self) -> &mut OptRecord<Vec<u8>> {
self.opt.get_or_insert_with(Default::default)
}
}
impl ComposeReply for ReplyMessage {
fn from_message<Octs>(msg: &Message<Octs>) -> Result<Self, ServiceError>
where
Octs: AsRef<[u8]>,
{
let vec = msg.as_slice().to_vec();
let msg = Message::from_octets(vec)
.expect("creating a Message from a Message should not fail");
let mut repl = Self { msg, opt: None };
let msg = repl.msg.clone();
if let Some(optrec) = msg.opt() {
let opt = repl.opt_mut();
opt.set_udp_payload_size(optrec.udp_payload_size());
opt.set_dnssec_ok(optrec.dnssec_ok());
for opt in optrec.opt().iter::<AllOptData<_, _>>() {
let opt = opt?;
if let AllOptData::ClientSubnet(_ecs) = opt {
repl.add_opt_impl(&opt);
}
if let AllOptData::ExtendedError(ref _ede) = opt {
repl.add_opt_impl(&opt);
}
}
}
Ok(repl)
}
fn add_opt(
&mut self,
opt: &impl ComposeOptData,
) -> Result<(), LongOptData> {
self.add_opt_impl(opt);
Ok(())
}
fn additional_builder_stream_target(
&self,
) -> Result<AdditionalBuilder<StreamTarget<Vec<u8>>>, ServiceError> {
let source = &self.msg;
let mut target = MessageBuilder::from_target(
StreamTarget::<Vec<u8>>::new(Default::default())
.expect("new StreamTarget should not fail"),
)
.expect("new MessageBuilder should not fail");
let header = source.header();
*target.header_mut() = header;
let source = source.question();
let mut target = target.additional().builder().question();
for rr in source {
let rr = rr?;
target.push(rr).expect("push should not fail");
}
let mut source = source.answer()?;
let mut target = target.answer();
for rr in &mut source {
let rr = rr?;
let rr = rr
.into_record::<AllRecordData<_, ParsedName<_>>>()?
.expect("AllRecordData should not fail");
target.push(rr).expect("push should not fail");
}
let mut source = source
.next_section()?
.expect("authority section should be present");
let mut target = target.authority();
for rr in &mut source {
let rr = rr?;
let rr = rr
.into_record::<AllRecordData<_, ParsedName<_>>>()?
.expect("AllRecordData should not fail");
target.push(rr).expect("push should not fail");
}
let source = source
.next_section()?
.expect("additional section should be present");
let mut target = target.additional();
for rr in source {
let rr = rr?;
if rr.rtype() == Rtype::OPT {
} else {
let rr = rr
.into_record::<AllRecordData<_, ParsedName<_>>>()?
.expect("AllRecordData should not fail");
target.push(rr).expect("push should not fail");
}
}
if let Some(opt) = self.opt.as_ref() {
target.push(opt.as_record()).expect("push should not fail");
}
Ok(target)
}
}