Compare commits
2 Commits
1a1e1e4c5a
...
bd96581c6a
Author | SHA1 | Date | |
---|---|---|---|
|
bd96581c6a | ||
|
0b22801503 |
@ -24,15 +24,16 @@ pub trait Manager: Sync + Send {
|
|||||||
) -> Result<(PrivateKey, Vec<Certificate>), GetCertificateError>;
|
) -> Result<(PrivateKey, Vec<Certificate>), GetCertificateError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ManagerImpl {
|
pub struct ManagerImpl {
|
||||||
store: Box<dyn acme::store::Store>,
|
store: Box<dyn acme::store::Store>,
|
||||||
account: sync::Arc<acme2::Account>,
|
account: sync::Arc<acme2::Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(
|
impl ManagerImpl {
|
||||||
store: Box<dyn acme::store::Store>,
|
pub async fn new<Store: acme::store::Store + 'static>(
|
||||||
|
store: Store,
|
||||||
contact_email: &str,
|
contact_email: &str,
|
||||||
) -> Result<Box<dyn Manager>, unexpected::Error> {
|
) -> Result<Self, unexpected::Error> {
|
||||||
let dir = acme2::DirectoryBuilder::new(LETS_ENCRYPT_URL.to_string())
|
let dir = acme2::DirectoryBuilder::new(LETS_ENCRYPT_URL.to_string())
|
||||||
.build()
|
.build()
|
||||||
.await
|
.await
|
||||||
@ -54,7 +55,9 @@ pub async fn new(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(acme::store::GetAccountKeyError::NotFound) => (),
|
Err(acme::store::GetAccountKeyError::NotFound) => (),
|
||||||
Err(acme::store::GetAccountKeyError::Unexpected(err)) => return Err(err.into_unexpected()),
|
Err(acme::store::GetAccountKeyError::Unexpected(err)) => {
|
||||||
|
return Err(err.into_unexpected())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let account = builder
|
let account = builder
|
||||||
@ -72,7 +75,11 @@ pub async fn new(
|
|||||||
.set_account_key(&account_key)
|
.set_account_key(&account_key)
|
||||||
.or_unexpected_while("storing account key")?;
|
.or_unexpected_while("storing account key")?;
|
||||||
|
|
||||||
Ok(Box::new(ManagerImpl { store, account }))
|
Ok(Self {
|
||||||
|
store: Box::from(store),
|
||||||
|
account,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager for ManagerImpl {
|
impl Manager for ManagerImpl {
|
||||||
|
@ -66,11 +66,12 @@ struct StoredPKeyCert {
|
|||||||
cert: Vec<Certificate>,
|
cert: Vec<Certificate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FSStore {
|
pub struct FSStore {
|
||||||
dir_path: path::PathBuf,
|
dir_path: path::PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(dir_path: &path::Path) -> Result<Box<dyn Store>, unexpected::Error> {
|
impl FSStore {
|
||||||
|
pub fn new(dir_path: &path::Path) -> Result<Self, unexpected::Error> {
|
||||||
vec![
|
vec![
|
||||||
dir_path,
|
dir_path,
|
||||||
dir_path.join("http01_challenge_keys").as_ref(),
|
dir_path.join("http01_challenge_keys").as_ref(),
|
||||||
@ -78,16 +79,16 @@ pub fn new(dir_path: &path::Path) -> Result<Box<dyn Store>, unexpected::Error> {
|
|||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|dir| {
|
.map(|dir| {
|
||||||
fs::create_dir_all(dir).map_unexpected_while(|| format!("creating dir {}", dir.display()))
|
fs::create_dir_all(dir)
|
||||||
|
.map_unexpected_while(|| format!("creating dir {}", dir.display()))
|
||||||
})
|
})
|
||||||
.try_collect()?;
|
.try_collect()?;
|
||||||
|
|
||||||
Ok(Box::new(FSStore {
|
Ok(Self {
|
||||||
dir_path: dir_path.into(),
|
dir_path: dir_path.into(),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FSStore {
|
|
||||||
fn account_key_path(&self) -> path::PathBuf {
|
fn account_key_path(&self) -> path::PathBuf {
|
||||||
self.dir_path.join("account.key")
|
self.dir_path.join("account.key")
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,11 @@ pub struct DNSChecker {
|
|||||||
client: tokio::sync::Mutex<AsyncClient>,
|
client: tokio::sync::Mutex<AsyncClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DNSChecker {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
target_a: net::Ipv4Addr,
|
target_a: net::Ipv4Addr,
|
||||||
resolver_addr: &str,
|
resolver_addr: &str,
|
||||||
) -> Result<DNSChecker, NewDNSCheckerError> {
|
) -> Result<Self, NewDNSCheckerError> {
|
||||||
let resolver_addr = resolver_addr
|
let resolver_addr = resolver_addr
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| NewDNSCheckerError::InvalidResolverAddress)?;
|
.map_err(|_| NewDNSCheckerError::InvalidResolverAddress)?;
|
||||||
@ -50,13 +51,12 @@ pub async fn new(
|
|||||||
|
|
||||||
tokio::spawn(bg);
|
tokio::spawn(bg);
|
||||||
|
|
||||||
Ok(DNSChecker {
|
Ok(Self {
|
||||||
target_a,
|
target_a,
|
||||||
client: tokio::sync::Mutex::new(client),
|
client: tokio::sync::Mutex::new(client),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DNSChecker {
|
|
||||||
pub async fn check_domain(
|
pub async fn check_domain(
|
||||||
&self,
|
&self,
|
||||||
domain: &domain::Name,
|
domain: &domain::Name,
|
||||||
|
@ -45,18 +45,18 @@ pub trait Store: Sync + Send {
|
|||||||
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>;
|
fn all_domains(&self) -> Result<Vec<domain::Name>, unexpected::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FSStore {
|
pub struct FSStore {
|
||||||
dir_path: PathBuf,
|
dir_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(dir_path: &Path) -> io::Result<Box<dyn Store>> {
|
impl FSStore {
|
||||||
|
pub fn new(dir_path: &Path) -> io::Result<Self> {
|
||||||
fs::create_dir_all(dir_path)?;
|
fs::create_dir_all(dir_path)?;
|
||||||
Ok(Box::new(FSStore {
|
Ok(Self {
|
||||||
dir_path: dir_path.into(),
|
dir_path: dir_path.into(),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FSStore {
|
|
||||||
fn config_dir_path(&self, domain: &domain::Name) -> PathBuf {
|
fn config_dir_path(&self, domain: &domain::Name) -> PathBuf {
|
||||||
self.dir_path.join(domain.as_str())
|
self.dir_path.join(domain.as_str())
|
||||||
}
|
}
|
||||||
|
@ -176,18 +176,22 @@ async fn sync_origins(origin_store: &dyn origin::store::Store, canceller: Cancel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new<
|
||||||
|
OriginStore: origin::store::Store + 'static,
|
||||||
|
DomainConfigStore: config::Store + 'static,
|
||||||
|
AcmeManager: acme::manager::Manager + 'static,
|
||||||
|
>(
|
||||||
task_stack: &mut util::TaskStack<unexpected::Error>,
|
task_stack: &mut util::TaskStack<unexpected::Error>,
|
||||||
origin_store: Box<dyn origin::store::Store>,
|
origin_store: OriginStore,
|
||||||
domain_config_store: Box<dyn config::Store>,
|
domain_config_store: DomainConfigStore,
|
||||||
domain_checker: checker::DNSChecker,
|
domain_checker: checker::DNSChecker,
|
||||||
acme_manager: Option<Box<dyn acme::manager::Manager>>,
|
acme_manager: Option<AcmeManager>,
|
||||||
) -> sync::Arc<dyn Manager> {
|
) -> sync::Arc<dyn Manager> {
|
||||||
let manager = sync::Arc::new(ManagerImpl {
|
let manager = sync::Arc::new(ManagerImpl {
|
||||||
origin_store,
|
origin_store: Box::from(origin_store),
|
||||||
domain_config_store,
|
domain_config_store: Box::from(domain_config_store),
|
||||||
domain_checker,
|
domain_checker: domain_checker,
|
||||||
acme_manager,
|
acme_manager: acme_manager.map(|m| Box::new(m) as Box<dyn acme::manager::Manager>),
|
||||||
});
|
});
|
||||||
|
|
||||||
task_stack.push_spawn(|canceller| {
|
task_stack.push_spawn(|canceller| {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
/// Error is a String which implements the Error trait. It is intended to be used in
|
/// Error is a String which implements the Error trait. It is intended to be used in
|
||||||
/// situations where the caller is being given an error they can't really handle, except to pass it
|
/// situations where the caller is being given an error they can't really handle, except to pass it
|
||||||
/// along or log it.
|
/// along or log it.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![feature(result_option_inspect)]
|
#![feature(result_option_inspect)]
|
||||||
#![feature(iterator_try_collect)]
|
#![feature(iterator_try_collect)]
|
||||||
|
#![feature(iter_collect_into)]
|
||||||
|
|
||||||
pub mod domain;
|
pub mod domain;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
15
src/main.rs
15
src/main.rs
@ -73,23 +73,25 @@ async fn main() {
|
|||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let origin_store = domani::origin::store::git::new(config.origin_store_git_dir_path)
|
let origin_store = domani::origin::store::git::FSStore::new(config.origin_store_git_dir_path)
|
||||||
.expect("git origin store initialization failed");
|
.expect("git origin store initialization failed");
|
||||||
|
|
||||||
let domain_checker = domani::domain::checker::new(
|
let domain_checker = domani::domain::checker::DNSChecker::new(
|
||||||
config.domain_checker_target_a,
|
config.domain_checker_target_a,
|
||||||
&config.domain_checker_resolver_addr,
|
&config.domain_checker_resolver_addr,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("domain checker initialization failed");
|
.expect("domain checker initialization failed");
|
||||||
|
|
||||||
let domain_config_store = domani::domain::config::new(&config.domain_config_store_dir_path)
|
let domain_config_store =
|
||||||
|
domani::domain::config::FSStore::new(&config.domain_config_store_dir_path)
|
||||||
.expect("domain config store initialization failed");
|
.expect("domain config store initialization failed");
|
||||||
|
|
||||||
let domain_acme_manager = if config.https_listen_addr.is_some() {
|
let domain_acme_manager = if config.https_listen_addr.is_some() {
|
||||||
let domain_acme_store_dir_path = config.domain_acme_store_dir_path.unwrap();
|
let domain_acme_store_dir_path = config.domain_acme_store_dir_path.unwrap();
|
||||||
|
|
||||||
let domain_acme_store = domani::domain::acme::store::new(&domain_acme_store_dir_path)
|
let domain_acme_store =
|
||||||
|
domani::domain::acme::store::FSStore::new(&domain_acme_store_dir_path)
|
||||||
.expect("domain acme store initialization failed");
|
.expect("domain acme store initialization failed");
|
||||||
|
|
||||||
// if https_listen_addr is set then domain_acme_contact_email is required, see the Cli/clap
|
// if https_listen_addr is set then domain_acme_contact_email is required, see the Cli/clap
|
||||||
@ -97,7 +99,10 @@ async fn main() {
|
|||||||
let domain_acme_contact_email = config.domain_acme_contact_email.unwrap();
|
let domain_acme_contact_email = config.domain_acme_contact_email.unwrap();
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
domani::domain::acme::manager::new(domain_acme_store, &domain_acme_contact_email)
|
domani::domain::acme::manager::ManagerImpl::new(
|
||||||
|
domain_acme_store,
|
||||||
|
&domain_acme_contact_email,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.expect("domain acme manager initialization failed"),
|
.expect("domain acme manager initialization failed"),
|
||||||
)
|
)
|
||||||
|
@ -3,13 +3,14 @@ use crate::origin;
|
|||||||
use std::sync;
|
use std::sync;
|
||||||
|
|
||||||
pub mod git;
|
pub mod git;
|
||||||
|
pub mod mux;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Limits {
|
pub struct Limits {
|
||||||
// TODO storage limits
|
// TODO storage limits
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Clone, Debug, PartialEq)]
|
||||||
pub enum SyncError {
|
pub enum SyncError {
|
||||||
#[error("invalid url")]
|
#[error("invalid url")]
|
||||||
InvalidURL,
|
InvalidURL,
|
||||||
@ -24,7 +25,7 @@ pub enum SyncError {
|
|||||||
Unexpected(#[from] unexpected::Error),
|
Unexpected(#[from] unexpected::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Clone, Debug, PartialEq)]
|
||||||
pub enum GetError {
|
pub enum GetError {
|
||||||
#[error("not found")]
|
#[error("not found")]
|
||||||
NotFound,
|
NotFound,
|
||||||
@ -33,7 +34,7 @@ pub enum GetError {
|
|||||||
Unexpected(#[from] unexpected::Error),
|
Unexpected(#[from] unexpected::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Clone, Debug, PartialEq)]
|
||||||
pub enum AllDescrsError {
|
pub enum AllDescrsError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Unexpected(#[from] unexpected::Error),
|
Unexpected(#[from] unexpected::Error),
|
||||||
|
@ -59,9 +59,9 @@ enum GetOriginError {
|
|||||||
Unexpected(#[from] unexpected::Error),
|
Unexpected(#[from] unexpected::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// git::Store implements the Store trait for any Descr::Git based Origins. If any non-git
|
/// Implements the Store trait for any Descr::Git based Origins, storing the git repos on disk. If
|
||||||
/// Descrs are used then this implementation will panic.
|
/// any non-git Descrs are used then this implementation will panic.
|
||||||
struct Store {
|
pub struct FSStore {
|
||||||
dir_path: PathBuf,
|
dir_path: PathBuf,
|
||||||
|
|
||||||
// to prevent against syncing the same origin more than once at a time, but still allowing
|
// to prevent against syncing the same origin more than once at a time, but still allowing
|
||||||
@ -71,16 +71,16 @@ 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<Box<dyn super::Store>> {
|
impl FSStore {
|
||||||
|
pub fn new(dir_path: PathBuf) -> io::Result<Self> {
|
||||||
fs::create_dir_all(&dir_path)?;
|
fs::create_dir_all(&dir_path)?;
|
||||||
Ok(Box::new(Store {
|
Ok(Self {
|
||||||
dir_path,
|
dir_path,
|
||||||
sync_guard: sync::Mutex::new(collections::HashMap::new()),
|
sync_guard: sync::Mutex::new(collections::HashMap::new()),
|
||||||
origins: sync::RwLock::new(collections::HashMap::new()),
|
origins: sync::RwLock::new(collections::HashMap::new()),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
|
||||||
fn repo_path(&self, descr: &origin::Descr) -> PathBuf {
|
fn repo_path(&self, descr: &origin::Descr) -> PathBuf {
|
||||||
self.dir_path.join(descr.id())
|
self.dir_path.join(descr.id())
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ impl Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::Store for Store {
|
impl super::Store for FSStore {
|
||||||
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
|
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
|
||||||
// attempt to lock this descr for syncing, doing so within a new scope so the mutex
|
// attempt to lock this descr for syncing, doing so within a new scope so the mutex
|
||||||
// isn't actually being held for the whole method duration.
|
// isn't actually being held for the whole method duration.
|
||||||
@ -344,7 +344,7 @@ mod tests {
|
|||||||
|
|
||||||
let limits = store::Limits {};
|
let limits = store::Limits {};
|
||||||
|
|
||||||
let store = super::new(tmp_dir.path().to_path_buf()).expect("store created");
|
let store = super::FSStore::new(tmp_dir.path().to_path_buf()).expect("store created");
|
||||||
|
|
||||||
store
|
store
|
||||||
.sync(descr.clone(), limits)
|
.sync(descr.clone(), limits)
|
||||||
|
98
src/origin/store/mux.rs
Normal file
98
src/origin/store/mux.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use crate::error::unexpected::Mappable;
|
||||||
|
use crate::origin::{self, store};
|
||||||
|
use std::sync;
|
||||||
|
|
||||||
|
pub struct Store<F, S>
|
||||||
|
where
|
||||||
|
S: store::Store + 'static,
|
||||||
|
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
|
||||||
|
{
|
||||||
|
mapping_fn: F,
|
||||||
|
stores: Vec<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, S> Store<F, S>
|
||||||
|
where
|
||||||
|
S: store::Store + 'static,
|
||||||
|
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
|
||||||
|
{
|
||||||
|
pub fn new(mapping_fn: F, stores: Vec<S>) -> Store<F, S> {
|
||||||
|
Store { mapping_fn, stores }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, S> store::Store for Store<F, S>
|
||||||
|
where
|
||||||
|
S: store::Store + 'static,
|
||||||
|
F: Fn(&origin::Descr) -> Option<S> + Sync + Send,
|
||||||
|
{
|
||||||
|
fn sync(&self, descr: origin::Descr, limits: store::Limits) -> Result<(), store::SyncError> {
|
||||||
|
(self.mapping_fn)(&descr)
|
||||||
|
.or_unexpected_while(format!("fetching store for {:?}", &descr))?
|
||||||
|
.sync(descr, limits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, descr: origin::Descr) -> Result<sync::Arc<dyn origin::Origin>, store::GetError> {
|
||||||
|
(self.mapping_fn)(&descr)
|
||||||
|
.or_unexpected_while(format!("fetching store for {:?}", &descr))?
|
||||||
|
.get(descr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_descrs(&self) -> Result<Vec<origin::Descr>, store::AllDescrsError> {
|
||||||
|
let mut res = Vec::<origin::Descr>::new();
|
||||||
|
|
||||||
|
for store in self.stores.iter() {
|
||||||
|
store.all_descrs()?.into_iter().collect_into(&mut res);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::origin::{self, store};
|
||||||
|
use mockall::predicate;
|
||||||
|
use std::{cell, rc};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic() {
|
||||||
|
let descrA = origin::Descr::Git {
|
||||||
|
url: "A".to_string(),
|
||||||
|
branch_name: "A".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
//let descrB = origin::Descr::Git {
|
||||||
|
// url: "B".to_string(),
|
||||||
|
// branch_name: "B".to_string(),
|
||||||
|
//};
|
||||||
|
|
||||||
|
let sA_mock = rc::Rc::new(store::MockStore::new());
|
||||||
|
|
||||||
|
//let mut sB = store::MockStore::new();
|
||||||
|
|
||||||
|
let s = {
|
||||||
|
let sA: rc::Rc<dyn store::Store> = sA_mock.clone();
|
||||||
|
let sA = sA.as_ref();
|
||||||
|
|
||||||
|
super::new(
|
||||||
|
|descr| match descr {
|
||||||
|
&origin::Descr::Git { ref url, .. } if url == "A" => Some(sA),
|
||||||
|
//&origin::Descr::Git { ref url, .. } if url == "B" => Some(sB),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
//vec![sA],
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
sA_mock
|
||||||
|
.expect_sync()
|
||||||
|
.with(predicate::eq(descrA.clone()), predicate::always())
|
||||||
|
.times(1)
|
||||||
|
.return_const(Ok::<(), store::SyncError>(()));
|
||||||
|
|
||||||
|
assert_eq!(Ok(()), s.sync(descrA, store::Limits {}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user