use crate::config::{Config, ValidatedConfig};
use crate::doctor::{run_doctor, DoctorReport};
use crate::error::Result;
use crate::observability::{Metrics, MetricsSnapshot};
use crate::runtime::{GovernorConfig, ResourceGovernor};
use crate::support::{build_support_bundle, SupportBundle};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
pub struct AurumEngine {
config: ValidatedConfig,
governor: Arc<ResourceGovernor>,
metrics: Arc<Metrics>,
closed: AtomicBool,
}
impl std::fmt::Debug for AurumEngine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AurumEngine")
.field("config", &self.config)
.field("closed", &self.closed.load(Ordering::SeqCst))
.field("metrics", &self.metrics.snapshot())
.finish_non_exhaustive()
}
}
impl AurumEngine {
pub fn new(config: ValidatedConfig) -> Self {
Self::with_governor(config, GovernorConfig::default())
}
pub fn with_governor(config: ValidatedConfig, gov: GovernorConfig) -> Self {
Self {
config,
governor: Arc::new(ResourceGovernor::new(gov)),
metrics: Arc::new(Metrics::new()),
closed: AtomicBool::new(false),
}
}
pub fn load() -> Result<Self> {
Ok(Self::new(ValidatedConfig::load()?))
}
pub fn load_from_required(path: &std::path::Path) -> Result<Self> {
Ok(Self::new(ValidatedConfig::load_from_required(path)?))
}
pub fn from_config(cfg: Config) -> Result<Self> {
Ok(Self::new(ValidatedConfig::try_from_config(cfg)?))
}
pub fn config(&self) -> &Config {
self.config.as_ref()
}
pub fn validated_config(&self) -> &ValidatedConfig {
&self.config
}
pub fn governor(&self) -> &Arc<ResourceGovernor> {
&self.governor
}
pub fn metrics(&self) -> &Arc<Metrics> {
&self.metrics
}
pub fn is_closed(&self) -> bool {
self.closed.load(Ordering::SeqCst)
}
pub fn shutdown(&self) {
self.closed.store(true, Ordering::SeqCst);
}
pub fn doctor(&self) -> DoctorReport {
run_doctor(self.config.as_ref())
}
pub fn support_bundle(&self, user_notes: Option<String>) -> SupportBundle {
let mut bundle = build_support_bundle(self.config.as_ref(), user_notes);
bundle.metrics = self.metrics.snapshot();
bundle
.redaction_notes
.push("metrics are engine-local (not process-global)".into());
bundle
}
pub fn metrics_snapshot(&self) -> MetricsSnapshot {
self.metrics.snapshot()
}
pub fn cache_dir(&self) -> &std::path::Path {
&self.config.as_ref().cache_dir
}
}
impl Drop for AurumEngine {
fn drop(&mut self) {
self.closed.store(true, Ordering::SeqCst);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn independent_engines_have_independent_metrics() {
let a = AurumEngine::load().unwrap();
let b = AurumEngine::load().unwrap();
a.metrics().record_start();
a.metrics()
.record_complete(std::time::Duration::from_millis(1));
assert_eq!(a.metrics_snapshot().ops_started, 1);
assert_eq!(b.metrics_snapshot().ops_started, 0);
assert!(!std::ptr::eq(
Arc::as_ptr(a.governor()),
Arc::as_ptr(b.governor())
));
}
#[test]
fn shutdown_flags_closed() {
let e = AurumEngine::load().unwrap();
assert!(!e.is_closed());
e.shutdown();
assert!(e.is_closed());
}
#[test]
fn doctor_and_support_bundle_work() {
let e = AurumEngine::load().unwrap();
let d = e.doctor();
assert!(!d.checks.is_empty());
let b = e.support_bundle(None);
assert_eq!(b.schema_version, crate::support::SUPPORT_BUNDLE_VERSION);
let json = b.to_json_pretty().unwrap();
assert!(json.contains("engine-local"));
}
}