Introduced separate 'Boxed' traits, to allow for mocks
This commit is contained in:
parent
d9676a4ce7
commit
cab7a837a7
@ -1,6 +1,6 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{fs, io};
|
use std::{fs, io, sync};
|
||||||
|
|
||||||
use crate::domain;
|
use crate::domain;
|
||||||
use crate::origin::Descr;
|
use crate::origin::Descr;
|
||||||
@ -39,20 +39,22 @@ pub enum SetError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[mockall::automock]
|
#[mockall::automock]
|
||||||
pub trait Store: std::marker::Send + std::marker::Sync {
|
pub trait Store {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<Config, GetError>;
|
fn get(&self, domain: &domain::Name) -> Result<Config, GetError>;
|
||||||
fn set(&self, domain: &domain::Name, config: &Config) -> Result<(), SetError>;
|
fn set(&self, domain: &domain::Name, config: &Config) -> Result<(), SetError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait BoxedStore: Store + Send + Sync + Clone {}
|
||||||
|
|
||||||
struct FSStore {
|
struct FSStore {
|
||||||
dir_path: PathBuf,
|
dir_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(dir_path: &Path) -> io::Result<impl Store> {
|
pub fn new(dir_path: &Path) -> io::Result<impl BoxedStore> {
|
||||||
fs::create_dir_all(dir_path)?;
|
fs::create_dir_all(dir_path)?;
|
||||||
Ok(FSStore {
|
Ok(sync::Arc::new(FSStore {
|
||||||
dir_path: dir_path.into(),
|
dir_path: dir_path.into(),
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FSStore {
|
impl FSStore {
|
||||||
@ -65,7 +67,9 @@ impl FSStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store for FSStore {
|
impl BoxedStore for sync::Arc<FSStore> {}
|
||||||
|
|
||||||
|
impl Store for sync::Arc<FSStore> {
|
||||||
fn get(&self, domain: &domain::Name) -> Result<Config, GetError> {
|
fn get(&self, domain: &domain::Name) -> Result<Config, GetError> {
|
||||||
let config_file =
|
let config_file =
|
||||||
fs::File::open(self.config_file_path(domain)).map_err(|e| match e.kind() {
|
fs::File::open(self.config_file_path(domain)).map_err(|e| match e.kind() {
|
||||||
|
@ -2,7 +2,7 @@ use crate::domain::{self, checker, config};
|
|||||||
use crate::origin;
|
use crate::origin;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin;
|
use std::{pin, sync};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum GetConfigError {
|
pub enum GetConfigError {
|
||||||
@ -113,8 +113,8 @@ impl From<config::SetError> for SyncWithConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[mockall::automock(type Origin=origin::MockOrigin;)]
|
//#[mockall::automock]
|
||||||
pub trait Manager: Send + Sync {
|
pub trait Manager {
|
||||||
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError>;
|
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError>;
|
||||||
fn get_origin(
|
fn get_origin(
|
||||||
&self,
|
&self,
|
||||||
@ -128,36 +128,47 @@ pub trait Manager: Send + Sync {
|
|||||||
) -> pin::Pin<Box<dyn Future<Output = Result<(), SyncWithConfigError>> + Send + '_>>;
|
) -> pin::Pin<Box<dyn Future<Output = Result<(), SyncWithConfigError>> + Send + '_>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait BoxedManager: Manager + Send + Sync + Clone {}
|
||||||
|
|
||||||
|
struct ManagerImpl<OriginStore, DomainConfigStore>
|
||||||
|
where
|
||||||
|
OriginStore: origin::store::BoxedStore,
|
||||||
|
DomainConfigStore: config::BoxedStore,
|
||||||
|
{
|
||||||
|
origin_store: OriginStore,
|
||||||
|
domain_config_store: DomainConfigStore,
|
||||||
|
domain_checker: checker::DNSChecker,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new<OriginStore, DomainConfigStore>(
|
pub fn new<OriginStore, DomainConfigStore>(
|
||||||
origin_store: OriginStore,
|
origin_store: OriginStore,
|
||||||
domain_config_store: DomainConfigStore,
|
domain_config_store: DomainConfigStore,
|
||||||
domain_checker: checker::DNSChecker,
|
domain_checker: checker::DNSChecker,
|
||||||
) -> impl Manager
|
) -> impl BoxedManager
|
||||||
where
|
where
|
||||||
OriginStore: origin::store::Store,
|
OriginStore: origin::store::BoxedStore,
|
||||||
DomainConfigStore: config::Store,
|
DomainConfigStore: config::BoxedStore,
|
||||||
{
|
{
|
||||||
ManagerImpl {
|
sync::Arc::new(ManagerImpl {
|
||||||
origin_store,
|
origin_store,
|
||||||
domain_config_store,
|
domain_config_store,
|
||||||
domain_checker,
|
domain_checker,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ManagerImpl<OriginStore, DomainConfigStore>
|
impl<OriginStore, DomainConfigStore> BoxedManager
|
||||||
|
for sync::Arc<ManagerImpl<OriginStore, DomainConfigStore>>
|
||||||
where
|
where
|
||||||
OriginStore: origin::store::Store,
|
OriginStore: origin::store::BoxedStore,
|
||||||
DomainConfigStore: config::Store,
|
DomainConfigStore: config::BoxedStore,
|
||||||
{
|
{
|
||||||
origin_store: OriginStore,
|
|
||||||
domain_config_store: DomainConfigStore,
|
|
||||||
domain_checker: checker::DNSChecker,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<OriginStore, DomainConfigStore> Manager for ManagerImpl<OriginStore, DomainConfigStore>
|
impl<OriginStore, DomainConfigStore> Manager
|
||||||
|
for sync::Arc<ManagerImpl<OriginStore, DomainConfigStore>>
|
||||||
where
|
where
|
||||||
OriginStore: origin::store::Store,
|
OriginStore: origin::store::BoxedStore,
|
||||||
DomainConfigStore: config::Store,
|
DomainConfigStore: config::BoxedStore,
|
||||||
{
|
{
|
||||||
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError> {
|
fn get_config(&self, domain: &domain::Name) -> Result<config::Config, GetConfigError> {
|
||||||
Ok(self.domain_config_store.get(domain)?)
|
Ok(self.domain_config_store.get(domain)?)
|
||||||
|
@ -123,7 +123,6 @@ fn main() {
|
|||||||
.expect("domain config store initialized");
|
.expect("domain config store initialized");
|
||||||
|
|
||||||
let manager = domiply::domain::manager::new(origin_store, domain_config_store, domain_checker);
|
let manager = domiply::domain::manager::new(origin_store, domain_config_store, domain_checker);
|
||||||
let manager = sync::Arc::new(manager);
|
|
||||||
|
|
||||||
let service = domiply::service::new(
|
let service = domiply::service::new(
|
||||||
manager,
|
manager,
|
||||||
|
@ -41,13 +41,17 @@ pub enum AllDescrsError {
|
|||||||
/// Used in the return from all_descrs from Store.
|
/// Used in the return from all_descrs from Store.
|
||||||
pub type AllDescrsResult<T> = Result<T, AllDescrsError>;
|
pub type AllDescrsResult<T> = Result<T, AllDescrsError>;
|
||||||
|
|
||||||
|
#[mockall::automock(
|
||||||
|
type Origin=origin::MockOrigin;
|
||||||
|
type AllDescrsIter=Vec<AllDescrsResult<origin::Descr>>;
|
||||||
|
)]
|
||||||
/// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr.
|
/// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr.
|
||||||
pub trait Store: Send + Sync + Clone {
|
pub trait Store {
|
||||||
type Origin<'store>: origin::Origin + 'store
|
type Origin<'store>: origin::Origin + 'store
|
||||||
where
|
where
|
||||||
Self: 'store;
|
Self: 'store;
|
||||||
|
|
||||||
type AllDescrsIter<'store>: IntoIterator<Item = AllDescrsResult<origin::Descr>> + Send + 'store
|
type AllDescrsIter<'store>: IntoIterator<Item = AllDescrsResult<origin::Descr>> + 'store
|
||||||
where
|
where
|
||||||
Self: 'store;
|
Self: 'store;
|
||||||
|
|
||||||
@ -58,3 +62,5 @@ pub trait Store: Send + Sync + Clone {
|
|||||||
fn get(&self, descr: origin::Descr) -> Result<Self::Origin<'_>, GetError>;
|
fn get(&self, descr: origin::Descr) -> Result<Self::Origin<'_>, GetError>;
|
||||||
fn all_descrs(&self) -> AllDescrsResult<Self::AllDescrsIter<'_>>;
|
fn all_descrs(&self) -> AllDescrsResult<Self::AllDescrsIter<'_>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait BoxedStore: Store + Send + Sync + Clone {}
|
||||||
|
@ -65,7 +65,7 @@ struct Store {
|
|||||||
origins: sync::RwLock<collections::HashMap<origin::Descr, sync::Arc<Origin>>>,
|
origins: sync::RwLock<collections::HashMap<origin::Descr, sync::Arc<Origin>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(dir_path: PathBuf) -> io::Result<impl super::Store> {
|
pub fn new(dir_path: PathBuf) -> io::Result<impl super::BoxedStore> {
|
||||||
fs::create_dir_all(&dir_path)?;
|
fs::create_dir_all(&dir_path)?;
|
||||||
Ok(sync::Arc::new(Store {
|
Ok(sync::Arc::new(Store {
|
||||||
dir_path,
|
dir_path,
|
||||||
@ -191,11 +191,13 @@ impl Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl super::BoxedStore for sync::Arc<Store> {}
|
||||||
|
|
||||||
impl super::Store for sync::Arc<Store> {
|
impl super::Store for sync::Arc<Store> {
|
||||||
type Origin<'store> = sync::Arc<Origin>
|
type Origin<'store> = sync::Arc<Origin>
|
||||||
where Self: 'store;
|
where Self: 'store;
|
||||||
|
|
||||||
type AllDescrsIter<'store> = Box<dyn Iterator<Item = store::AllDescrsResult<origin::Descr>> + Send + 'store>
|
type AllDescrsIter<'store> = Box<dyn Iterator<Item = store::AllDescrsResult<origin::Descr>> + 'store>
|
||||||
where Self: 'store;
|
where Self: 'store;
|
||||||
|
|
||||||
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
|
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
|
||||||
|
@ -15,20 +15,26 @@ mod util;
|
|||||||
type SvcResponse = Result<Response<hyper::body::Body>, String>;
|
type SvcResponse = Result<Response<hyper::body::Body>, String>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Service<'svc> {
|
pub struct Service<'svc, DomainManager>
|
||||||
domain_manager: sync::Arc<dyn domain::manager::Manager>,
|
where
|
||||||
|
DomainManager: domain::manager::BoxedManager,
|
||||||
|
{
|
||||||
|
domain_manager: DomainManager,
|
||||||
target_a: net::Ipv4Addr,
|
target_a: net::Ipv4Addr,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
http_domain: String,
|
http_domain: String,
|
||||||
handlebars: handlebars::Handlebars<'svc>,
|
handlebars: handlebars::Handlebars<'svc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<'svc>(
|
pub fn new<'svc, DomainManager>(
|
||||||
domain_manager: sync::Arc<dyn domain::manager::Manager>,
|
domain_manager: DomainManager,
|
||||||
target_a: net::Ipv4Addr,
|
target_a: net::Ipv4Addr,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
http_domain: String,
|
http_domain: String,
|
||||||
) -> Service<'svc> {
|
) -> Service<'svc, DomainManager>
|
||||||
|
where
|
||||||
|
DomainManager: domain::manager::BoxedManager,
|
||||||
|
{
|
||||||
Service {
|
Service {
|
||||||
domain_manager,
|
domain_manager,
|
||||||
target_a,
|
target_a,
|
||||||
@ -60,7 +66,10 @@ struct DomainSyncArgs {
|
|||||||
passphrase: String,
|
passphrase: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'svc> Service<'svc> {
|
impl<'svc, DomainManager> Service<'svc, DomainManager>
|
||||||
|
where
|
||||||
|
DomainManager: domain::manager::BoxedManager,
|
||||||
|
{
|
||||||
fn serve_string(&self, status_code: u16, path: &'_ str, body: Vec<u8>) -> SvcResponse {
|
fn serve_string(&self, status_code: u16, path: &'_ str, body: Vec<u8>) -> SvcResponse {
|
||||||
let content_type = mime_guess::from_path(path)
|
let content_type = mime_guess::from_path(path)
|
||||||
.first_or_octet_stream()
|
.first_or_octet_stream()
|
||||||
@ -280,10 +289,13 @@ impl<'svc> Service<'svc> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_request(
|
pub async fn handle_request<DomainManager>(
|
||||||
svc: sync::Arc<Service<'_>>,
|
svc: sync::Arc<Service<'_, DomainManager>>,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
) -> Result<Response<Body>, Infallible> {
|
) -> Result<Response<Body>, Infallible>
|
||||||
|
where
|
||||||
|
DomainManager: domain::manager::BoxedManager,
|
||||||
|
{
|
||||||
match handle_request_inner(svc, req).await {
|
match handle_request_inner(svc, req).await {
|
||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
Err(err) => panic!("unexpected error {err}"),
|
Err(err) => panic!("unexpected error {err}"),
|
||||||
@ -297,7 +309,13 @@ fn strip_port(host: &str) -> &str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_request_inner(svc: sync::Arc<Service<'_>>, req: Request<Body>) -> SvcResponse {
|
pub async fn handle_request_inner<DomainManager>(
|
||||||
|
svc: sync::Arc<Service<'_, DomainManager>>,
|
||||||
|
req: Request<Body>,
|
||||||
|
) -> SvcResponse
|
||||||
|
where
|
||||||
|
DomainManager: domain::manager::BoxedManager,
|
||||||
|
{
|
||||||
let maybe_host = match (
|
let maybe_host = match (
|
||||||
req.headers()
|
req.headers()
|
||||||
.get("Host")
|
.get("Host")
|
||||||
|
Loading…
Reference in New Issue
Block a user