initial implementation of domain manager

This commit is contained in:
Brian Picciano 2023-05-10 13:34:33 +02:00
parent a704c7ad34
commit e5b64f4968
2 changed files with 200 additions and 0 deletions

View File

@ -1,2 +1,3 @@
pub mod checker;
pub mod config;
pub mod manager;

199
src/domain/manager.rs Normal file
View File

@ -0,0 +1,199 @@
use crate::domain::{checker, config};
use crate::origin;
use std::error::Error;
#[derive(thiserror::Error, Debug)]
pub enum GetConfigError {
#[error("not found")]
NotFound,
#[error(transparent)]
Unexpected(Box<dyn Error>),
}
impl From<config::GetError> for GetConfigError {
fn from(e: config::GetError) -> GetConfigError {
match e {
config::GetError::NotFound => GetConfigError::NotFound,
config::GetError::Unexpected(e) => GetConfigError::Unexpected(e),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum GetOriginError {
#[error("not found")]
NotFound,
#[error(transparent)]
Unexpected(Box<dyn Error>),
}
impl From<config::GetError> for GetOriginError {
fn from(e: config::GetError) -> GetOriginError {
match e {
config::GetError::NotFound => GetOriginError::NotFound,
config::GetError::Unexpected(e) => GetOriginError::Unexpected(e),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum SyncError {
#[error("not found")]
NotFound,
#[error(transparent)]
Unexpected(Box<dyn Error>),
}
impl From<config::GetError> for SyncError {
fn from(e: config::GetError) -> SyncError {
match e {
config::GetError::NotFound => SyncError::NotFound,
config::GetError::Unexpected(e) => SyncError::Unexpected(e),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum SyncWithConfigError {
#[error("invalid url")]
InvalidURL,
#[error("invalid branch name")]
InvalidBranchName,
#[error("invalid domain name")]
InvalidDomainName,
#[error("target CNAME not set")]
TargetCNAMENotSet,
#[error("challenge token not set")]
ChallengeTokenNotSet,
#[error(transparent)]
Unexpected(Box<dyn Error>),
}
impl From<origin::store::SyncError> for SyncWithConfigError {
fn from(e: origin::store::SyncError) -> SyncWithConfigError {
match e {
origin::store::SyncError::InvalidURL => SyncWithConfigError::InvalidURL,
origin::store::SyncError::InvalidBranchName => SyncWithConfigError::InvalidBranchName,
origin::store::SyncError::Unexpected(e) => SyncWithConfigError::Unexpected(e),
}
}
}
impl From<checker::CheckDomainError> for SyncWithConfigError {
fn from(e: checker::CheckDomainError) -> SyncWithConfigError {
match e {
checker::CheckDomainError::InvalidDomainName => SyncWithConfigError::InvalidDomainName,
checker::CheckDomainError::TargetCNAMENotSet => SyncWithConfigError::TargetCNAMENotSet,
checker::CheckDomainError::ChallengeTokenNotSet => {
SyncWithConfigError::ChallengeTokenNotSet
}
checker::CheckDomainError::Unexpected(e) => SyncWithConfigError::Unexpected(e),
}
}
}
impl From<config::SetError> for SyncWithConfigError {
fn from(e: config::SetError) -> SyncWithConfigError {
match e {
config::SetError::Unexpected(e) => SyncWithConfigError::Unexpected(e),
}
}
}
#[mockall::automock]
pub trait Manager {
fn get_config(&self, domain: &str) -> Result<config::Config, GetConfigError>;
fn get_origin(&self, domain: &str) -> Result<Box<dyn origin::Origin>, GetOriginError>;
fn sync(&self, domain: &str) -> Result<(), SyncError>;
fn sync_with_config(
&self,
domain: &str,
config: &config::Config,
) -> Result<(), SyncWithConfigError>;
}
pub fn new_manager<OriginStore, DomainConfigStore, DomainChecker>(
origin_store: OriginStore,
domain_config_store: DomainConfigStore,
domain_checker: DomainChecker,
) -> impl Manager
where
OriginStore: for<'a> origin::store::Store<'a>,
DomainConfigStore: config::Store,
DomainChecker: checker::Checker,
{
ManagerImpl {
origin_store,
domain_config_store,
domain_checker,
}
}
struct ManagerImpl<OriginStore, DomainConfigStore, DomainChecker>
where
OriginStore: for<'a> origin::store::Store<'a>,
DomainConfigStore: config::Store,
DomainChecker: checker::Checker,
{
origin_store: OriginStore,
domain_config_store: DomainConfigStore,
domain_checker: DomainChecker,
}
impl<OriginStore, DomainConfigStore, DomainChecker> Manager
for ManagerImpl<OriginStore, DomainConfigStore, DomainChecker>
where
OriginStore: for<'a> origin::store::Store<'a>,
DomainConfigStore: config::Store,
DomainChecker: checker::Checker,
{
fn get_config(&self, domain: &str) -> Result<config::Config, GetConfigError> {
Ok(self.domain_config_store.get(domain)?)
}
fn get_origin(&self, domain: &str) -> Result<Box<dyn origin::Origin>, GetOriginError> {
let config = self.domain_config_store.get(domain)?;
let origin = self
.origin_store
.get(config.origin_descr)
// if there's a config there should be an origin, any error here is unexpected
.map_err(|e| GetOriginError::Unexpected(Box::from(e)))?;
Ok(origin)
}
fn sync(&self, domain: &str) -> Result<(), SyncError> {
let config = self.domain_config_store.get(domain)?;
self.origin_store
.sync(&config.origin_descr, origin::store::Limits {})
// if there's a config there should be an origin, any error here is unexpected
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
Ok(())
}
fn sync_with_config(
&self,
domain: &str,
config: &config::Config,
) -> Result<(), SyncWithConfigError> {
let config_hash = config
.hash()
.map_err(|e| SyncWithConfigError::Unexpected(Box::from(e)))?;
self.domain_checker.check_domain(domain, &config_hash)?;
self.origin_store
.sync(&config.origin_descr, origin::store::Limits {})?;
self.domain_config_store.set(domain, config)?;
Ok(())
}
}