pub struct ConfigurationService {
config: Arc<RwLock<PmatConfig>>,
config_path: PathBuf,
metrics: Arc<RwLock<ServiceMetrics>>,
watchers: Arc<RwLock<Vec<Box<dyn ConfigWatcher + Send + Sync>>>>,
}
pub trait ConfigWatcher {
fn on_config_changed(&self, config: &PmatConfig) -> Result<()>;
}
impl ConfigurationService {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn new(config_path: Option<PathBuf>) -> Self {
let default_path = config_path.unwrap_or_else(|| {
std::env::current_dir()
.unwrap_or_default()
.join("pmat.toml")
});
let default_config = Self::default_config();
Self {
config: Arc::new(RwLock::new(default_config)),
config_path: default_path,
metrics: Arc::new(RwLock::new(ServiceMetrics::default())),
watchers: Arc::new(RwLock::new(Vec::new())),
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn load(&self) -> Result<()> {
if self.config_path.exists() {
let content = tokio::fs::read_to_string(&self.config_path).await?;
let config: PmatConfig = toml::from_str(&content)?;
{
let mut config_lock = self
.config
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire config write lock"))?;
*config_lock = config.clone();
}
self.notify_watchers(&config)?;
{
let mut metrics = self
.metrics
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?;
metrics.record_request(std::time::Duration::from_millis(1), true);
}
}
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn save(&self) -> Result<()> {
let config = {
self.config
.read()
.map_err(|_| anyhow::anyhow!("Failed to acquire config read lock"))?
.clone()
};
let content = toml::to_string_pretty(&config)?;
tokio::fs::write(&self.config_path, content).await?;
{
let mut metrics = self
.metrics
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?;
metrics.record_request(std::time::Duration::from_millis(1), true);
}
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_config(&self) -> Result<PmatConfig> {
Ok(self
.config
.read()
.map_err(|_| anyhow::anyhow!("Failed to acquire config read lock"))?
.clone())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn update_config<F>(&self, updater: F) -> Result<()>
where
F: FnOnce(&mut PmatConfig) -> Result<()>,
{
let config_clone = {
let mut config = self
.config
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire config write lock"))?;
updater(&mut config)?;
config.clone()
};
self.save().await?;
self.notify_watchers(&config_clone)?;
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn add_watcher(&self, watcher: Box<dyn ConfigWatcher + Send + Sync>) -> Result<()> {
let mut watchers = self
.watchers
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire watchers lock"))?;
watchers.push(watcher);
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_quality_config(&self) -> Result<QualityConfig> {
Ok(self.get_config()?.quality)
}
pub fn get_analysis_config(&self) -> Result<AnalysisConfig> {
Ok(self.get_config()?.analysis)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_performance_config(&self) -> Result<PerformanceConfig> {
Ok(self.get_config()?.performance)
}
pub fn get_mcp_config(&self) -> Result<McpConfig> {
Ok(self.get_config()?.mcp)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_roadmap_config(&self) -> Result<RoadmapConfig> {
Ok(self.get_config()?.roadmap)
}
pub fn get_telemetry_config(&self) -> Result<TelemetryConfig> {
Ok(self.get_config()?.telemetry)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_semantic_config(&self) -> Result<SemanticConfig> {
Ok(self.get_config()?.semantic)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn get_semantic_config_with_env_fallback(&self) -> Result<SemanticConfig> {
let mut config = self.get_semantic_config()?;
if config.vector_db_path.is_none() {
config.vector_db_path = std::env::var("PMAT_VECTOR_DB_PATH").ok().or_else(|| {
dirs::home_dir().map(|home| {
home.join(".pmat")
.join("embeddings.db")
.to_string_lossy()
.to_string()
})
});
}
if config.workspace_path.is_none() {
config.workspace_path = std::env::var("PMAT_WORKSPACE")
.ok()
.map(PathBuf::from)
.or_else(|| std::env::current_dir().ok());
}
Ok(config)
}
fn notify_watchers(&self, config: &PmatConfig) -> Result<()> {
let watchers = self
.watchers
.read()
.map_err(|_| anyhow::anyhow!("Failed to acquire watchers lock"))?;
for watcher in watchers.iter() {
if let Err(e) = watcher.on_config_changed(config) {
tracing::warn!("Configuration watcher failed: {}", e);
}
}
Ok(())
}
}
impl ConfigurationService {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn start(&self) -> Result<()> {
self.load().await?;
{
let mut metrics = self
.metrics
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?;
metrics.record_request(Duration::from_millis(10), true);
}
tracing::info!(
"Configuration service started with config at: {:?}",
self.config_path
);
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn stop(&self) -> Result<()> {
self.save().await?;
{
let mut metrics = self
.metrics
.write()
.map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?;
metrics.record_request(Duration::from_millis(5), true);
}
tracing::info!("Configuration service stopped");
Ok(())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn status(&self) -> Result<String> {
let config_exists = self.config_path.exists();
let _config = self.get_config()?;
Ok(format!(
"Configuration service: {} (file: {}, sections: {})",
if config_exists { "loaded" } else { "default" },
self.config_path.display(),
8 ))
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn get_metrics(&self) -> Result<ServiceMetrics> {
Ok(self
.metrics
.read()
.map_err(|_| anyhow::anyhow!("Failed to acquire metrics lock"))?
.clone())
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub async fn health_check(&self) -> Result<bool> {
self.get_config().map(|_| true)
}
}
lazy_static::lazy_static! {
static ref CONFIGURATION: Arc<ConfigurationService> = Arc::new(ConfigurationService::new(None));
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn configuration() -> Arc<ConfigurationService> {
CONFIGURATION.clone()
}