Skip to main content
Glama
config.rs10.3 kB
use std::{ env, net::SocketAddr, path::Path, time::Duration, }; use buck2_resources::Buck2Resources; use derive_builder::Builder; use serde::{ Deserialize, Serialize, }; use si_data_pg::PgPoolConfig; use si_jwt_public_key::JwtAlgo; use si_posthog::PosthogConfig; pub use si_settings::{ StandardConfig, StandardConfigFile, }; use si_std::{ CanonicalFile, CanonicalFileError, }; use si_tls::CertificateSource; use telemetry::prelude::*; use thiserror::Error; use tower::limit::RateLimitLayer; use ulid::Ulid; use crate::s3::S3Config; #[remain::sorted] #[derive(Debug, Error)] pub enum ConfigError { #[error("config builder")] Builder(#[from] ConfigBuilderError), #[error("canonical file error: {0}")] CanonicalFile(#[from] CanonicalFileError), #[error("error configuring for development")] Development(#[source] Box<dyn std::error::Error + 'static + Sync + Send>), #[error("settings error: {0}")] Settings(#[from] si_settings::SettingsError), } impl ConfigError { fn development(err: impl std::error::Error + 'static + Sync + Send) -> Self { Self::Development(Box::new(err)) } } type Result<T> = std::result::Result<T, ConfigError>; fn get_default_socket_addr() -> SocketAddr { SocketAddr::from(([0, 0, 0, 0], 5157)) } fn default_auth_api_url() -> String { auth_api_client::PROD_AUTH_API_ENDPOINT.to_string() } #[derive(Debug, Builder)] pub struct Config { #[builder(default = "get_default_socket_addr()")] socket_addr: SocketAddr, #[builder(default = "PgPoolConfig::default()")] pg_pool: PgPoolConfig, #[builder(default = "random_instance_id()")] instance_id: String, #[builder(default = "default_auth_api_url()")] auth_api_url: String, jwt_signing_public_key_path: CanonicalFile, jwt_signing_public_key_algo: JwtAlgo, #[builder(default)] jwt_secondary_signing_public_key_path: Option<CanonicalFile>, #[builder(default)] jwt_secondary_signing_public_key_algo: Option<JwtAlgo>, #[builder(default = "PosthogConfig::default()")] posthog: PosthogConfig, #[builder(default)] rate_limit: RateLimitConfig, s3: S3Config, } impl StandardConfig for Config { type Builder = ConfigBuilder; } impl Config { /// Gets a reference to the config's pg pool. #[must_use] pub fn pg_pool(&self) -> &PgPoolConfig { &self.pg_pool } /// Gets the socket address pub fn socket_addr(&self) -> &SocketAddr { &self.socket_addr } /// Gets the config's instance ID. pub fn instance_id(&self) -> &str { self.instance_id.as_ref() } /// Gets the auth API URL. pub fn auth_api_url(&self) -> &str { &self.auth_api_url } /// Gets a reference to the config's jwt signing public key path. #[must_use] pub fn jwt_signing_public_key_path(&self) -> &CanonicalFile { &self.jwt_signing_public_key_path } /// Gets a reference to the config's jwt signing public key path. #[must_use] pub fn jwt_signing_public_key_algo(&self) -> JwtAlgo { self.jwt_signing_public_key_algo } /// Gets a reference to the config's jwt secondary signing public key path. #[must_use] pub fn jwt_secondary_signing_public_key_path(&self) -> Option<&CanonicalFile> { self.jwt_secondary_signing_public_key_path.as_ref() } #[must_use] pub fn jwt_secondary_signing_public_key_algo(&self) -> Option<JwtAlgo> { self.jwt_secondary_signing_public_key_algo } /// Gets a reference to the config's posthog config. #[must_use] pub fn posthog(&self) -> &PosthogConfig { &self.posthog } /// Gets a reference to the config's rate limit layer. #[must_use] pub fn rate_limit(&self) -> &RateLimitConfig { &self.rate_limit } /// Gets a config's s3 details #[must_use] pub fn s3(&self) -> &S3Config { &self.s3 } } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ConfigFile { #[serde(default)] pg: PgPoolConfig, #[serde(default = "get_default_socket_addr")] socket_addr: SocketAddr, #[serde(default = "random_instance_id")] instance_id: String, #[serde(default)] auth_api_url: String, #[serde(default = "default_jwt_signing_public_key_path")] pub jwt_signing_public_key_path: String, #[serde(default = "default_jwt_signing_public_key_algo")] pub jwt_signing_public_key_algo: JwtAlgo, #[serde(default)] pub jwt_secondary_signing_public_key_path: Option<String>, #[serde(default)] pub jwt_secondary_signing_public_key_algo: Option<JwtAlgo>, #[serde(default)] pub posthog: PosthogConfig, #[serde(default)] pub rate_limit: RateLimitConfig, #[serde(default)] pub s3: S3Config, } impl Default for ConfigFile { fn default() -> Self { Self { // config from toml file is not working at the moment // so we just override from the base defaults here pg: PgPoolConfig { dbname: "si_module_index".to_owned(), application_name: "si-module-index".to_owned(), ..Default::default() }, socket_addr: get_default_socket_addr(), instance_id: random_instance_id(), auth_api_url: default_auth_api_url(), jwt_signing_public_key_path: default_jwt_signing_public_key_path(), jwt_signing_public_key_algo: default_jwt_signing_public_key_algo(), jwt_secondary_signing_public_key_path: None, jwt_secondary_signing_public_key_algo: None, posthog: Default::default(), rate_limit: Default::default(), s3: Default::default(), } } } impl StandardConfigFile for ConfigFile { type Error = ConfigError; } impl TryFrom<ConfigFile> for Config { type Error = ConfigError; fn try_from(mut value: ConfigFile) -> Result<Self> { detect_and_configure_development(&mut value)?; let mut config = Config::builder(); config.pg_pool(value.pg); config.socket_addr(value.socket_addr); config.instance_id(value.instance_id); config.auth_api_url(value.auth_api_url); config.jwt_signing_public_key_path(value.jwt_signing_public_key_path.try_into()?); config.jwt_signing_public_key_algo(value.jwt_signing_public_key_algo); config.posthog(value.posthog); config.s3(value.s3); config.build().map_err(Into::into) } } fn random_instance_id() -> String { Ulid::new().to_string() } fn default_jwt_signing_public_key_path() -> String { "/run/sdf/jwt_signing_public_key.pem".to_string() } fn default_jwt_signing_public_key_algo() -> JwtAlgo { JwtAlgo::RS256 } #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RateLimitConfig { requests: u64, per_second: Duration, } impl Default for RateLimitConfig { fn default() -> Self { Self { requests: 128, per_second: Duration::from_secs(1), } } } impl From<RateLimitConfig> for RateLimitLayer { fn from(val: RateLimitConfig) -> Self { RateLimitLayer::new(val.requests, val.per_second) } } #[allow(clippy::disallowed_methods)] // Used to determine if running in development pub fn detect_and_configure_development(config: &mut ConfigFile) -> Result<()> { if env::var("BUCK_RUN_BUILD_ID").is_ok() || env::var("BUCK_BUILD_ID").is_ok() { buck2_development(config) } else if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") { cargo_development(dir, config) } else { Ok(()) } } fn buck2_development(config: &mut ConfigFile) -> Result<()> { let resources = Buck2Resources::read().map_err(ConfigError::development)?; #[allow(clippy::disallowed_methods)] // Used in development with a local auth services // Note(victor): If the user has set a custom auth ip url via env variable we assume dev mode let jwt_signing_public_key_path = if env::var("SI_AUTH_API_URL").is_ok() { resources .get_ends_with("dev.jwt_signing_public_key.pem") .map_err(ConfigError::development)? .to_string_lossy() .to_string() } else { resources .get_ends_with("prod.jwt_signing_public_key.pem") .map_err(ConfigError::development)? .to_string_lossy() .to_string() }; let postgres_cert = resources .get_ends_with("dev.postgres.root.crt") .map_err(ConfigError::development)? .to_string_lossy() .to_string(); warn!( jwt_signing_public_key_path = jwt_signing_public_key_path.as_str(), postgres_cert = postgres_cert.as_str(), "detected development run", ); config.jwt_signing_public_key_path = jwt_signing_public_key_path; config.pg.certificate = Some(CertificateSource::Path(postgres_cert.try_into()?)); Ok(()) } fn cargo_development(dir: String, config: &mut ConfigFile) -> Result<()> { #[allow(clippy::disallowed_methods)] // Used in development with a local auth services // Note(victor): If the user has set a custom auth ip url via env variable we assume dev mode let jwt_signing_public_key_path = if env::var("SI_AUTH_API_URL").is_ok() { Path::new(&dir) .join("../../config/keys/dev.jwt_signing_public_key.pem") .to_string_lossy() .to_string() } else { Path::new(&dir) .join("../../config/keys/prod.jwt_signing_public_key.pem") .to_string_lossy() .to_string() }; let postgres_cert = Path::new(&dir) .join("../../config/keys/dev.postgres.root.crt") .to_string_lossy() .to_string(); warn!( jwt_signing_public_key_path = jwt_signing_public_key_path.as_str(), postgres_cert = postgres_cert.as_str(), "detected development run", ); config.jwt_signing_public_key_path = jwt_signing_public_key_path; config.pg.certificate = Some(CertificateSource::Path(postgres_cert.try_into()?)); // todo!(); // config.veritech_encryption_key_path = veritech_encryption_key_path; Ok(()) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server