Skip to content

Commit

Permalink
feat: clean up config
Browse files Browse the repository at this point in the history
  • Loading branch information
TroyKomodo committed Jul 4, 2023
1 parent 1fb973b commit 9a5419f
Show file tree
Hide file tree
Showing 25 changed files with 189 additions and 389 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 1 addition & 105 deletions backend/api/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,111 +1,7 @@
use std::net::SocketAddr;

use anyhow::Result;

#[derive(Debug, Clone, Default, PartialEq, config::Config)]
pub struct TlsConfig {
/// Domain name to use for TLS
/// Only used for gRPC TLS connections
#[config(default)]
pub domain: Option<String>,

/// The path to the TLS certificate
pub cert: String,

/// The path to the TLS private key
pub key: String,

/// The path to the TLS CA certificate
pub ca_cert: String,
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct LoggingConfig {
/// The log level to use, this is a tracing env filter
pub level: String,

/// If we should use JSON logging
pub json: bool,
}

impl Default for LoggingConfig {
fn default() -> Self {
Self {
level: "info".to_string(),
json: false,
}
}
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct RmqConfig {
/// The URI to use for connecting to RabbitMQ
pub uri: String,
}

impl Default for RmqConfig {
fn default() -> Self {
Self {
uri: "amqp://rabbitmq:rabbitmq@localhost:5672/scuffle".to_string(),
}
}
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct RedisConfig {
/// The address of the Redis server
pub addresses: Vec<String>,

/// Number of connections to keep in the pool
pub pool_size: usize,

/// The username to use for authentication
pub username: Option<String>,

/// The password to use for authentication
pub password: Option<String>,

/// The database to use
pub database: u8,

/// The TLS configuration
pub tls: Option<TlsConfig>,

/// To use Redis Sentinel
pub sentinel: Option<RedisSentinelConfig>,
}

impl Default for RedisConfig {
fn default() -> Self {
Self {
addresses: vec!["localhost:6379".to_string()],
pool_size: 10,
username: None,
password: None,
database: 0,
tls: None,
sentinel: None,
}
}
}

#[derive(Debug, Clone, PartialEq, config::Config)]
// #[config(default)]
pub struct RedisSentinelConfig {
/// The master group name
pub service_name: String,
}

impl Default for RedisSentinelConfig {
fn default() -> Self {
Self {
service_name: "myservice".to_string(),
}
}
}
use common::config::{LoggingConfig, RedisConfig, RmqConfig, TlsConfig};

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
Expand Down
2 changes: 1 addition & 1 deletion backend/api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod tests;
#[tokio::main]
async fn main() -> Result<()> {
let config = config::AppConfig::parse()?;
logging::init(&config.logging.level, config.logging.json)?;
logging::init(&config.logging.level, config.logging.mode)?;

if let Some(file) = &config.config_file {
tracing::info!(file = file, "loaded config from file");
Expand Down
7 changes: 3 additions & 4 deletions backend/api/src/tests/global/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{sync::Arc, time::Duration};

use crate::{config::AppConfig, global::GlobalState};
use common::{
config::RedisSentinelConfig,
context::{Context, Handler},
logging,
prelude::FutureTimeout,
Expand All @@ -16,7 +17,7 @@ pub async fn mock_global_state(mut config: AppConfig) -> (Arc<GlobalState>, Hand

dotenvy::dotenv().ok();

logging::init(&config.logging.level, config.logging.json)
logging::init(&config.logging.level, config.logging.mode)
.expect("failed to initialize logging");

let db = Arc::new(
Expand Down Expand Up @@ -53,9 +54,7 @@ pub async fn mock_global_state(mut config: AppConfig) -> (Arc<GlobalState>, Hand
config.redis.password = redis_config.password;
config.redis.username = redis_config.username;
config.redis.sentinel = match redis_config.server {
ServerConfig::Sentinel { service_name, .. } => {
Some(crate::config::RedisSentinelConfig { service_name })
}
ServerConfig::Sentinel { service_name, .. } => Some(RedisSentinelConfig { service_name }),
_ => None,
};

Expand Down
3 changes: 2 additions & 1 deletion backend/api/src/tests/grpc/tls.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use common::config::TlsConfig;
use common::grpc::{make_channel, TlsSettings};
use common::prelude::FutureTimeout;
use std::path::PathBuf;
use std::time::Duration;
use tonic::transport::{Certificate, Identity};

use crate::config::{AppConfig, GrpcConfig, TlsConfig};
use crate::config::{AppConfig, GrpcConfig};
use crate::grpc::run;
use crate::pb;
use crate::tests::global::mock_global_state;
Expand Down
5 changes: 3 additions & 2 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ authors = ["Scuffle <[email protected]>"]
description = "Scuffle Common Library"

[features]
logging = ["dep:log", "dep:tracing", "dep:tracing-log", "dep:tracing-subscriber", "dep:arc-swap", "dep:anyhow", "dep:once_cell"]
logging = ["dep:log", "dep:tracing", "dep:tracing-log", "dep:tracing-subscriber", "dep:arc-swap", "dep:anyhow", "dep:once_cell", "dep:thiserror"]
rmq = ["dep:lapin", "dep:arc-swap", "dep:anyhow", "dep:futures", "dep:tracing", "dep:tokio", "dep:async-stream", "prelude"]
grpc = ["dep:tonic", "dep:anyhow", "dep:async-trait", "dep:futures", "dep:http", "dep:tower", "dep:trust-dns-resolver", "dep:tracing"]
context = ["dep:tokio", "dep:tokio-util"]
prelude = ["dep:tokio"]
signal = []
macros = []
config = ["dep:config"]
config = ["dep:config", "logging"]

default = ["logging", "rmq", "grpc", "context", "prelude", "signal", "macros", "config"]

Expand All @@ -37,6 +37,7 @@ tracing-log = { version = "0", features = ["env_logger"], optional = true, git =
once_cell = { version = "1", optional = true }
trust-dns-resolver = { version = "0", features = ["tokio-runtime"], optional = true }
tracing-subscriber = { version = "0", features = ["fmt", "env-filter", "json"], optional = true }
thiserror = { version = "1", optional = true }

[dev-dependencies]
prost = "0"
Expand Down
108 changes: 108 additions & 0 deletions common/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,113 @@
use anyhow::Result;

use crate::logging;

#[derive(Debug, Clone, Default, PartialEq, config::Config)]
pub struct TlsConfig {
/// Domain name to use for TLS
/// Only used for gRPC TLS connections
#[config(default)]
pub domain: Option<String>,

/// The path to the TLS certificate
pub cert: String,

/// The path to the TLS private key
pub key: String,

/// The path to the TLS CA certificate
pub ca_cert: String,
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct LoggingConfig {
/// The log level to use, this is a tracing env filter
pub level: String,

/// What logging mode we should use
#[config(from_str)]
pub mode: logging::Mode,
}

impl Default for LoggingConfig {
fn default() -> Self {
Self {
level: "info".to_string(),
mode: logging::Mode::Default,
}
}
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct RedisConfig {
/// The address of the Redis server
pub addresses: Vec<String>,

/// Number of connections to keep in the pool
pub pool_size: usize,

/// The username to use for authentication
pub username: Option<String>,

/// The password to use for authentication
pub password: Option<String>,

/// The database to use
pub database: u8,

/// The TLS configuration
pub tls: Option<TlsConfig>,

/// To use Redis Sentinel
pub sentinel: Option<RedisSentinelConfig>,
}

#[derive(Debug, Clone, PartialEq, config::Config)]
// #[config(default)]
pub struct RedisSentinelConfig {
/// The master group name
pub service_name: String,
}

#[derive(Debug, Clone, PartialEq, config::Config)]
#[config(default)]
pub struct RmqConfig {
/// The URI to use for connecting to RabbitMQ
pub uri: String,
}

impl Default for RmqConfig {
fn default() -> Self {
Self {
uri: "amqp://rabbitmq:rabbitmq@localhost:5672/scuffle".to_string(),
}
}
}

impl Default for RedisSentinelConfig {
fn default() -> Self {
Self {
service_name: "myservice".to_string(),
}
}
}

impl Default for RedisConfig {
fn default() -> Self {
Self {
addresses: vec!["localhost:6379".to_string()],
pool_size: 10,
username: None,
password: None,
database: 0,
tls: None,
sentinel: None,
}
}
}

pub fn parse<C: config::Config + 'static>(
enable_cli: bool,
config_file: Option<String>,
Expand Down
44 changes: 38 additions & 6 deletions common/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,43 @@
use std::str::FromStr;

use anyhow::Result;
use once_cell::sync::OnceCell;
use tracing_subscriber::{prelude::*, reload::Handle, EnvFilter};

static RELOAD_HANDLE: OnceCell<Handle<EnvFilter>> = OnceCell::new();

pub fn init(level: &str, json: bool) -> Result<()> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Default,
Json,
Pretty,
Compact,
}

#[derive(Debug, thiserror::Error)]
pub enum LoggingError {
#[error("invalid logging mode: {0}")]
InvalidMode(String),
#[error("failed to init logger: {0}")]
Init(#[from] tracing_subscriber::util::TryInitError),
#[error("failed to reload logger: {0}")]
Reload(#[from] tracing_subscriber::reload::Error),
}

impl FromStr for Mode {
type Err = LoggingError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"" | "default" => Ok(Self::Default),
"json" => Ok(Self::Json),
"pretty" => Ok(Self::Pretty),
"compact" => Ok(Self::Compact),
_ => Err(LoggingError::InvalidMode(s.to_string())),
}
}
}

pub fn init(level: &str, mode: Mode) -> Result<(), LoggingError> {
let reload = RELOAD_HANDLE.get_or_try_init(|| {
let env_filter = EnvFilter::from_str(level).expect("failed to parse log level");

Expand All @@ -18,10 +49,11 @@ pub fn init(level: &str, json: bool) -> Result<()> {

let handle = filter.reload_handle();

if json {
filter.json().finish().try_init()
} else {
filter.pretty().finish().try_init()
match mode {
Mode::Default => filter.finish().try_init(),
Mode::Json => filter.json().finish().try_init(),
Mode::Pretty => filter.pretty().finish().try_init(),
Mode::Compact => filter.compact().finish().try_init(),
}
.map(|_| handle)
})?;
Expand Down
4 changes: 2 additions & 2 deletions common/src/tests/logging.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::logging::init;
use crate::logging::{self, init};

#[test]
fn test_init() {
init("info", false).expect("Failed to init logger");
init("info", logging::Mode::Compact).expect("Failed to init logger");
}
Loading

0 comments on commit 9a5419f

Please sign in to comment.