erpc_analysis/config.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
//! Handles application configuration for erpc-analysis.
//!
//! This module defines structures for parsing the `Config.toml` file and for
//! loading sensitive information like Neo4j credentials from environment
//! variables.
use anyhow::{Context, Result};
use log::info;
use serde::Deserialize;
use std::{env, fs, path::Path};
use crate::args::Args;
/// Represents the `[primary]` table within the `Config.toml` file.
/// It extracts settings relevant to `erpc-analysis` from this section.
#[derive(Debug, Deserialize)]
pub struct PrimarySectionConfig {
/// Indicates if Neo4j database interaction is enabled.
pub neo4j_allowed: bool,
}
/// Represents the root structure of the `Config.toml` file.
/// `erpc-analysis` is primarily interested in the settings within the
/// `[primary]` table.
#[derive(Debug, Deserialize)]
pub struct TomlRootConfig {
/// Configuration settings from the `[primary]` table of the TOML file.
pub primary: PrimarySectionConfig,
}
/// Holds Neo4j connection parameters.
/// These are loaded from environment variables if `neo4j_allowed` is true.
#[derive(Debug, Clone)]
pub struct Neo4jConfig {
/// The URI for the Neo4j database (e.g., "bolt://localhost:7687").
pub uri: String,
/// The username for Neo4j authentication.
pub username: String,
/// The password for Neo4j authentication.
pub password: String,
}
/// The fully processed and usable configuration for the `erpc-analysis`
/// application. It combines settings from the TOML file and environment
/// variables.
#[derive(Debug)]
pub struct AnalysisConfig {
/// Optional Neo4j configuration. `Some` if Neo4j is enabled and
/// credentials are loaded, `None` otherwise.
pub neo4j: Option<Neo4jConfig>,
}
impl AnalysisConfig {
/// Loads the application configuration.
///
/// This function performs the following steps:
/// 1. Reads the TOML configuration file specified by `args.config`.
/// 2. Parses the TOML into `TomlRootConfig`.
/// 3. Checks `toml_root.primary.neo4j_allowed`.
/// 4. If Neo4j is allowed, it attempts to load `NEO4J_DB_ADDR`,
/// `NEO4J_DB_USERNAME`, and `NEO4J_DB_PASSWORD` from environment
/// variables (expected to be set via `config/primary/.env`).
/// 5. Constructs and returns the final `AnalysisConfig`.
///
/// # Arguments
/// * `args` - Parsed command-line arguments containing the path to the
/// TOML config file.
///
/// # Errors
/// Returns an error if the TOML file cannot be read or parsed, or if
/// Neo4j is allowed but the required environment variables for
/// credentials are not set.
pub fn load_from_toml_and_env(args: &Args) -> Result<Self> {
let config_path = Path::new(&args.config);
info!("Loading configuration from: {:?}", config_path);
let config_file_contents = fs::read_to_string(config_path)
.with_context(|| {
format!(
"Failed to read configuration file at: {:?}",
config_path
)
})?;
let toml_root: TomlRootConfig = toml::from_str(&config_file_contents)
.with_context(|| {
format!(
"Failed to parse TOML from configuration file at: {:?}. \
Ensure it matches the expected structure.",
config_path
)
})?;
let mut neo4j_details: Option<Neo4jConfig> = None;
if toml_root.primary.neo4j_allowed {
// Attempt to load .env file only if neo4j is allowed.
// The .env file is expected to be at "config/primary/.env"
// relative to workspace root.
let env_path = "config/primary/.env";
match dotenvy::from_path(env_path) {
Ok(_) => {
println!(
"Successfully loaded environment variables from: {}",
env_path
);
}
Err(e) => {
println!(
"Warning: Could not load .env file from {}: {}. \
Neo4j credential loading will rely on globally set \
environment variables.",
env_path, e
);
}
}
info!(
"Attempting to load Neo4j credentials from environment \
variables..."
);
let raw_uri = env::var("NEO4J_DB_ADDR").context(
"NEO4J_DB_ADDR not found. Ensure it is set (e.g., in \
'config/primary/.env' or globally).",
)?;
let uri = format!("bolt://{}", raw_uri);
let username = env::var("NEO4J_DB_USERNAME").context(
"NEO4J_DB_USERNAME not found. Ensure it is set (e.g., in \
'config/primary/.env' or globally).",
)?;
let password = env::var("NEO4J_DB_PASSWORD").context(
"NEO4J_DB_PASSWORD not found. Ensure it is set (e.g., in \
'config/primary/.env' or globally).",
)?;
neo4j_details = Some(Neo4jConfig {
uri,
username,
password,
});
println!("Successfully loaded Neo4j credentials.");
} else {
println!(
"Neo4j is not allowed in the [primary] section of the \
configuration file. Skipping .env loading and credential \
retrieval."
);
}
Ok(AnalysisConfig {
neo4j: neo4j_details,
})
}
}