use std::sync::Arc;
use acme_proxy_core::config;
use acme_proxy_core::config::Config;
use acme_proxy_jobs::metrics;
use acme_proxy_jobs::notify;
use acme_proxy_net::egress::Egress;
use acme_proxy_signer as signer;
use acme_proxy_store::db::Database;
pub struct GenerationParts {
pub egress: Arc<Egress>,
pub dispatchers: notify::DispatcherMap,
pub signers: signer::SignerSet,
pub infos: signer::SignerSet<dyn signer::SignerInfo>,
}
pub struct Assembly {
pub database: Arc<Database>,
pub jobs: acme_proxy_jobs::jobs::JobQueue,
pub metrics: Arc<metrics::Metrics>,
pub notifiers: notify::Notifiers,
notifiers_tx: notify::NotifiersSender,
signers: std::sync::Mutex<signer::SignerSet>,
infos: std::sync::Mutex<signer::SignerSet<dyn signer::SignerInfo>>,
roles: super::RoleSet,
}
impl Assembly {
pub fn new(
roles: super::RoleSet,
resolved: &[config::ProfileConfig],
database: Arc<Database>,
jobs: acme_proxy_jobs::jobs::JobQueue,
config: &Config,
) -> anyhow::Result<(Self, GenerationParts)> {
let metrics = Arc::new(metrics::Metrics::new(database.clone()).with_roles(&roles.labels()));
let (notifiers_tx, notifiers) = notify::notifiers_channel(notify::DispatcherMap::new());
let assembly = Self {
database,
jobs,
metrics,
notifiers,
notifiers_tx,
signers: std::sync::Mutex::new(signer::SignerSet::default()),
infos: std::sync::Mutex::new(signer::SignerSet::default()),
roles,
};
let parts = assembly.build_parts(resolved, config)?;
assembly.publish_notifiers(parts.dispatchers.clone());
assembly.publish_signers(parts.signers.clone(), parts.infos.clone());
Ok((assembly, parts))
}
pub fn build_parts(
&self,
resolved: &[config::ProfileConfig],
config: &Config,
) -> anyhow::Result<GenerationParts> {
let egress = Arc::new(Egress::from_config(config)?);
let mut dispatchers = notify::build_registry(resolved, egress.outbound(), &self.jobs)?;
if config.admin.enabled {
dispatchers.insert(
notify::ADMIN_DISPATCHER_KEY.to_string(),
notify::from_config(
notify::ADMIN_DISPATCHER_KEY,
&config.admin.notify,
egress.outbound(),
&self.jobs,
)?,
);
}
let signer_parts = signer::SignerParts {
database: self.database.clone(),
notifiers: self.notifiers.clone(),
metrics: self.metrics.clone(),
egress: egress.clone(),
jobs: self.jobs.clone(),
};
let previous = self
.signers
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone();
let signers = if self.roles.has(super::ProcessRole::Worker) {
signer::build_backends(resolved, &signer_parts, &previous)?
} else {
signer::SignerSet::default()
};
let previous = self
.infos
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone();
let infos = signer::build_infos(resolved, &signer_parts, &previous)?;
Ok(GenerationParts {
egress,
dispatchers,
signers,
infos,
})
}
pub fn publish_notifiers(&self, dispatchers: notify::DispatcherMap) {
self.notifiers_tx.send_replace(Arc::new(dispatchers));
}
pub fn publish_signers(
&self,
signers: signer::SignerSet,
infos: signer::SignerSet<dyn signer::SignerInfo>,
) {
*self
.signers
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = signers;
*self
.infos
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = infos;
}
}