Initial public release

This commit is contained in:
Agent Zero
2026-03-07 13:41:36 -05:00
commit 774982dc5a
22 changed files with 3517 additions and 0 deletions

146
src/config.rs Normal file
View File

@@ -0,0 +1,146 @@
//! Configuration management for OpenBrain MCP
//!
//! Loads configuration from environment variables with sensible defaults.
use anyhow::Result;
use serde::{Deserialize, Deserializer};
/// Main configuration structure
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
pub server: ServerConfig,
pub database: DatabaseConfig,
pub embedding: EmbeddingConfig,
pub auth: AuthConfig,
}
/// Server configuration
#[derive(Debug, Clone, Deserialize)]
pub struct ServerConfig {
#[serde(default = "default_host")]
pub host: String,
#[serde(default = "default_port")]
pub port: u16,
}
/// Database configuration
#[derive(Debug, Clone, Deserialize)]
pub struct DatabaseConfig {
pub host: String,
#[serde(default = "default_db_port")]
pub port: u16,
pub name: String,
pub user: String,
pub password: String,
#[serde(default = "default_pool_size")]
pub pool_size: usize,
}
/// Embedding engine configuration
#[derive(Debug, Clone, Deserialize)]
pub struct EmbeddingConfig {
#[serde(default = "default_model_path")]
pub model_path: String,
#[serde(default = "default_embedding_dim")]
pub dimension: usize,
}
/// Authentication configuration
#[derive(Debug, Clone, Deserialize)]
pub struct AuthConfig {
#[serde(default = "default_auth_enabled")]
pub enabled: bool,
#[serde(default, deserialize_with = "deserialize_api_keys")]
pub api_keys: Vec<String>,
}
/// Deserialize API keys from either a comma-separated string or a Vec<String>
fn deserialize_api_keys<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
D: Deserializer<'de>,
{
// Try to deserialize as a string first, then as a Vec
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrVec {
String(String),
Vec(Vec<String>),
}
match Option::<StringOrVec>::deserialize(deserializer)? {
Some(StringOrVec::String(s)) => {
Ok(s.split(',')
.map(|k| k.trim().to_string())
.filter(|k| !k.is_empty())
.collect())
}
Some(StringOrVec::Vec(v)) => Ok(v),
None => Ok(Vec::new()),
}
}
// Default value functions
fn default_host() -> String { "0.0.0.0".to_string() }
fn default_port() -> u16 { 3100 }
fn default_db_port() -> u16 { 5432 }
fn default_pool_size() -> usize { 10 }
fn default_model_path() -> String { "models/all-MiniLM-L6-v2".to_string() }
fn default_embedding_dim() -> usize { 384 }
fn default_auth_enabled() -> bool { false }
impl Config {
/// Load configuration from environment variables
pub fn load() -> Result<Self> {
// Load .env file if present
dotenvy::dotenv().ok();
let config = config::Config::builder()
// Server settings
.set_default("server.host", default_host())?
.set_default("server.port", default_port() as i64)?
// Database settings
.set_default("database.port", default_db_port() as i64)?
.set_default("database.pool_size", default_pool_size() as i64)?
// Embedding settings
.set_default("embedding.model_path", default_model_path())?
.set_default("embedding.dimension", default_embedding_dim() as i64)?
// Auth settings
.set_default("auth.enabled", default_auth_enabled())?
// Load from environment with OPENBRAIN_ prefix
.add_source(
config::Environment::with_prefix("OPENBRAIN")
.separator("__")
.try_parsing(true),
)
.build()?;
Ok(config.try_deserialize()?)
}
}
impl Default for Config {
fn default() -> Self {
Self {
server: ServerConfig {
host: default_host(),
port: default_port(),
},
database: DatabaseConfig {
host: "localhost".to_string(),
port: default_db_port(),
name: "openbrain".to_string(),
user: "openbrain_svc".to_string(),
password: String::new(),
pool_size: default_pool_size(),
},
embedding: EmbeddingConfig {
model_path: default_model_path(),
dimension: default_embedding_dim(),
},
auth: AuthConfig {
enabled: default_auth_enabled(),
api_keys: Vec::new(),
},
}
}
}