use std::str::FromStr;
use config::{Config, File};
use serde::{Deserialize, Serialize};
use crate::error::Error;
#[derive(PartialEq)]
pub enum AppEnv {
Development,
Test,
Production,
}
impl AppEnv {
pub fn as_str(&self) -> &'static str {
match self {
Self::Development => "dev",
Self::Test => "test",
Self::Production => "prod",
}
}
pub fn is_development(&self) -> bool {
*self == Self::Development
}
pub fn is_test(&self) -> bool {
*self == Self::Test
}
pub fn is_production(&self) -> bool {
*self == Self::Production
}
}
impl FromStr for AppEnv {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"development" | "dev" | "develop" => Ok(Self::Development),
"test" => Ok(Self::Test),
"production" | "prod" | "product" => Ok(Self::Production),
_ => Err(Self::Err::Other {
desc: format!("Invalid environment: {s}"),
}),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BotcatCapooConfig {
pub host: String,
pub port: u16,
pub owner: u64,
pub id: u64,
pub database: DatabaseConfig,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NapcatConfig {
pub api_url: String,
pub port: u16,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum DatabaseType {
Postgres,
Sqlite,
MySql,
}
impl FromStr for DatabaseType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"postgres" | "postgresql" | "psql" | "pgsql" | "pg" => Ok(Self::Postgres),
"sqlite" | "sqlite3" => Ok(Self::Sqlite),
"mysql" => Ok(Self::MySql),
_ => Err(Self::Err::Other {
desc: format!("Invalid database type: {s}"),
}),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DatabaseConfig {
pub db_type: String,
pub host: Option<String>,
pub port: Option<u16>,
pub username: Option<String>,
pub password: Option<String>,
pub database: String,
pub max_connections: Option<u32>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SecretConfig {
pub http_client_token: String,
pub http_server_token: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AppConfig {
pub botcat_capoo: BotcatCapooConfig,
pub napcat: NapcatConfig,
pub secret: SecretConfig,
}
impl AppConfig {
pub fn init() -> Result<AppConfig, Error> {
let env = std::env::var("BOTCAT_CAPOO_ENV").unwrap_or_else(|_| "dev".to_string());
let env = AppEnv::from_str(&env)
.unwrap_or(AppEnv::Development)
.as_str();
let settings = Config::builder()
.add_source(File::with_name(&format!("config/{env}")))
.add_source(File::with_name(&format!("secret/{env}")))
.build()?;
settings.try_deserialize::<AppConfig>().map_err(Error::from)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore = "Requires secret files which are not included in the repository"]
fn test_config_initialization() {
let config = AppConfig::init();
assert!(config.is_ok());
}
}