use core::future::{ready, Future};
use core::ops::Deref;
use core::pin::Pin;
use octseq::Octets;
use std::boxed::Box;
use std::vec::Vec;
use crate::base::wire::ParseError;
use crate::base::Serial;
use crate::net::server::message::Request;
use crate::zonetree::types::EmptyZoneDiff;
use crate::zonetree::{Zone, ZoneDiff, ZoneTree};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum XfrDataProviderError {
ParseError(ParseError),
UnknownZone,
Refused,
TemporarilyUnavailable,
}
impl From<ParseError> for XfrDataProviderError {
fn from(err: ParseError) -> Self {
Self::ParseError(err)
}
}
pub struct XfrData<Diff> {
zone: Zone,
diffs: Vec<Diff>,
compatibility_mode: bool,
}
impl<Diff> XfrData<Diff> {
pub fn new(
zone: Zone,
diffs: Vec<Diff>,
backward_compatible: bool,
) -> Self {
Self {
zone,
diffs,
compatibility_mode: backward_compatible,
}
}
pub fn zone(&self) -> &Zone {
&self.zone
}
pub fn diffs(&self) -> &[Diff] {
&self.diffs
}
pub fn into_diffs(self) -> Vec<Diff> {
self.diffs
}
pub fn compatibility_mode(&self) -> bool {
self.compatibility_mode
}
}
pub trait XfrDataProvider<RequestMeta> {
type Diff: ZoneDiff + Send + Sync;
#[allow(clippy::type_complexity)]
fn request<Octs>(
&self,
req: &Request<Octs, RequestMeta>,
diff_from: Option<Serial>,
) -> Pin<
Box<
dyn Future<
Output = Result<
XfrData<Self::Diff>,
XfrDataProviderError,
>,
> + Sync
+ Send
+ '_,
>,
>
where
Octs: Octets + Send + Sync;
}
impl<RequestMeta, T, U> XfrDataProvider<RequestMeta> for U
where
T: XfrDataProvider<RequestMeta> + 'static,
U: Deref<Target = T>,
{
type Diff = T::Diff;
fn request<Octs>(
&self,
req: &Request<Octs, RequestMeta>,
diff_from: Option<Serial>,
) -> Pin<
Box<
dyn Future<
Output = Result<
XfrData<Self::Diff>,
XfrDataProviderError,
>,
> + Sync
+ Send
+ '_,
>,
>
where
Octs: Octets + Send + Sync,
{
(**self).request(req, diff_from)
}
}
impl<RequestMeta> XfrDataProvider<RequestMeta> for Zone {
type Diff = EmptyZoneDiff;
fn request<Octs>(
&self,
req: &Request<Octs, RequestMeta>,
_diff_from: Option<Serial>,
) -> Pin<
Box<
dyn Future<
Output = Result<
XfrData<Self::Diff>,
XfrDataProviderError,
>,
> + Sync
+ Send,
>,
>
where
Octs: Octets + Send + Sync,
{
let res = req
.message()
.sole_question()
.map_err(XfrDataProviderError::ParseError)
.and_then(|q| {
if q.qname() == self.apex_name() && q.qclass() == self.class()
{
Ok(XfrData::new(self.clone(), vec![], false))
} else {
Err(XfrDataProviderError::UnknownZone)
}
});
Box::pin(ready(res))
}
}
impl<RequestMeta> XfrDataProvider<RequestMeta> for ZoneTree {
type Diff = EmptyZoneDiff;
fn request<Octs>(
&self,
req: &Request<Octs, RequestMeta>,
_diff_from: Option<Serial>,
) -> Pin<
Box<
dyn Future<
Output = Result<
XfrData<Self::Diff>,
XfrDataProviderError,
>,
> + Sync
+ Send,
>,
>
where
Octs: Octets + Send + Sync,
{
let res = req
.message()
.sole_question()
.map_err(XfrDataProviderError::ParseError)
.and_then(|q| {
if let Some(zone) = self.find_zone(q.qname(), q.qclass()) {
Ok(XfrData::new(zone.clone(), vec![], false))
} else {
Err(XfrDataProviderError::UnknownZone)
}
});
Box::pin(ready(res))
}
}