use crate::{DnsRecord, DnsRecordType, Error, IntoFqdn, NamedDnsRecord};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct InMemoryProvider {
records: Arc<Mutex<Vec<NamedDnsRecord>>>,
}
impl InMemoryProvider {
pub(crate) fn new(records: Arc<Mutex<Vec<NamedDnsRecord>>>) -> Self {
Self { records }
}
pub(crate) async fn set_rrset(
&self,
name: impl IntoFqdn<'_>,
record_type: DnsRecordType,
_ttl: u32,
records: Vec<DnsRecord>,
_origin: impl IntoFqdn<'_>,
) -> crate::Result<()> {
check_record_types(record_type, &records)?;
let name = name.into_fqdn().into_owned();
let mut store = self.records.lock().unwrap();
store.retain(|r| !(r.name == name && r.record.as_type() == record_type));
for record in records {
store.push(NamedDnsRecord {
name: name.clone(),
record,
});
}
Ok(())
}
pub(crate) async fn add_to_rrset(
&self,
name: impl IntoFqdn<'_>,
record_type: DnsRecordType,
_ttl: u32,
records: Vec<DnsRecord>,
_origin: impl IntoFqdn<'_>,
) -> crate::Result<()> {
check_record_types(record_type, &records)?;
if records.is_empty() {
return Ok(());
}
let name = name.into_fqdn().into_owned();
let mut store = self.records.lock().unwrap();
for record in records {
let already_present = store.iter().any(|r| r.name == name && r.record == record);
if !already_present {
store.push(NamedDnsRecord {
name: name.clone(),
record,
});
}
}
Ok(())
}
pub(crate) async fn remove_from_rrset(
&self,
name: impl IntoFqdn<'_>,
record_type: DnsRecordType,
records: Vec<DnsRecord>,
_origin: impl IntoFqdn<'_>,
) -> crate::Result<()> {
check_record_types(record_type, &records)?;
if records.is_empty() {
return Ok(());
}
let name = name.into_fqdn().into_owned();
let mut store = self.records.lock().unwrap();
store.retain(|r| !(r.name == name && records.contains(&r.record)));
Ok(())
}
pub(crate) async fn list_rrset(
&self,
_name: impl IntoFqdn<'_>,
_record_type: DnsRecordType,
_origin: impl IntoFqdn<'_>,
) -> crate::Result<Vec<DnsRecord>> {
Err(Error::Unsupported(
"InMemory does not support listing records".to_string(),
))
}
}
fn check_record_types(expected: DnsRecordType, records: &[DnsRecord]) -> crate::Result<()> {
for r in records {
if r.as_type() != expected {
return Err(Error::Api(format!(
"RRSet record type mismatch: expected {}, got {}",
expected.as_str(),
r.as_type().as_str(),
)));
}
}
Ok(())
}