darkwing/
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Configuration management for the Darkwing application.
//!
//! This module handles all configuration settings that can be set via
//! environment variables or command line arguments using the `clap` crate. It
//! provides structured access to application settings including:
//!
//! - Environment selection (Development/Test/Production)
//! - Server configuration
//! - Database settings
//! - Redis cache settings
//! - JWT authentication settings
//! - AWS S3 configuration for both primary and backup storage
//! - Encryption keys and security settings
//! - Rate limiting parameters
//! - Monitoring configuration (Sentry)

use std::{str::FromStr, time::Duration};

use anyhow::Context;
use jsonwebtoken::Algorithm;

/// Represents the running environment of the application.
///
/// This enum is used to determine the behavior and settings of the application
/// based on its deployment environment.
#[derive(clap::ValueEnum, Clone, Debug, Copy, Default, PartialEq)]
pub enum CargoEnv {
  /// Development environment for local development and testing
  #[default]
  Development,
  /// Test environment for running automated tests
  Test,
  /// Production environment for deployed applications
  Production,
}

/// Main configuration structure for the Darkwing application.
///
/// This struct is populated using command line arguments or environment
/// variables through the `clap` crate's derive functionality. Each field
/// corresponds to a configurable aspect of the application.
#[derive(clap::Parser, Clone, Debug, Default)]
pub struct DarkwingConfig {
  /// The environment in which the application is running
  #[clap(long, env = "CARGO_ENV", value_enum)]
  pub cargo_env: CargoEnv,

  /// Port number on which the server will listen
  #[clap(long, env = "PORT", default_value = "1337")]
  pub port: u16,

  /// Database connection string
  #[clap(long, env = "DATABASE_URL")]
  pub database_url: String,

  /// Maximum number of connections in the database connection pool
  #[clap(long, env = "DATABASE_CONNECTION_POOL_SIZE", default_value = "5")]
  pub database_connection_pool_size: u32,

  /// Redis server connection string
  #[clap(long, env = "REDIS_URL")]
  pub redis_url: String,

  /// Maximum number of connections in the Redis connection pool
  #[clap(long, env = "REDIS_CONNECTION_POOL_SIZE", default_value = "5")]
  pub redis_connection_pool_size: u32,

  /// Default timeout for Redis operations in seconds
  #[clap(long, env = "REDIS_DEFAULT_TIMEOUT_SECONDS", default_value = "5")]
  pub redis_default_timeout_seconds: u64,

  /// Time-to-live for Redis cache entries in seconds
  #[clap(long, env = "REDIS_EXPIRATION_SECONDS", default_value = "3600")]
  pub redis_expiration_seconds: u64,

  /// Public key used for JWT token verification
  #[clap(long, env = "JWT_TOKEN_PUBLIC_KEY")]
  pub jwt_token_public_key: String,

  /// Algorithm used for JWT token signing/verification (e.g., "RS256")
  #[clap(long, env = "JWT_TOKEN_ALGORITHM", default_value = "RS256")]
  pub jwt_token_algorithm: String,

  /// Key used for encrypting configuration values
  #[clap(long, env = "CONFIG_ENCRYPTION_KEY")]
  pub config_encryption_key: String,

  /// Maximum number of requests allowed per second for rate limiting
  #[clap(long, env = "RATE_LIMIT_PER_SECOND", default_value = "100")]
  pub rate_limit_per_second: u64,

  /// AWS S3 access key ID for primary storage
  #[clap(long, env = "AWS_S3_ACCESS_KEY_ID")]
  pub aws_s3_access_key_id: String,

  /// AWS S3 secret access key for primary storage
  #[clap(long, env = "AWS_S3_SECRET_ACCESS_KEY")]
  pub aws_s3_secret_access_key: String,

  /// AWS S3 endpoint URL for primary storage
  #[clap(long, env = "AWS_S3_ENDPOINT")]
  pub aws_s3_endpoint: String,

  /// AWS S3 bucket name for primary storage
  #[clap(long, env = "AWS_S3_BUCKET")]
  pub aws_s3_bucket: String,

  /// AWS S3 region for primary storage
  #[clap(long, env = "AWS_S3_REGION")]
  pub aws_s3_region: String,

  /// Public URL for accessing S3 objects
  #[clap(long, env = "AWS_S3_PUBLIC_URL")]
  pub aws_s3_public_url: String,

  /// AWS S3 access key ID for backup storage
  #[clap(long, env = "AWS_S3_BACKUP_ACCESS_KEY_ID")]
  pub aws_s3_backup_access_key_id: String,

  /// AWS S3 secret access key for backup storage
  #[clap(long, env = "AWS_S3_BACKUP_SECRET_ACCESS_KEY")]
  pub aws_s3_backup_secret_access_key: String,

  /// AWS S3 endpoint URL for backup storage
  #[clap(long, env = "AWS_S3_BACKUP_ENDPOINT")]
  pub aws_s3_backup_endpoint: String,

  /// AWS S3 bucket name for backup storage
  #[clap(long, env = "AWS_S3_BACKUP_BUCKET")]
  pub aws_s3_backup_bucket: String,

  /// AWS S3 region for backup storage
  #[clap(long, env = "AWS_S3_BACKUP_REGION")]
  pub aws_s3_backup_region: String,

  /// First part of the database encryption key (split for security)
  #[clap(long, env = "DATABASE_ENCRYPTION_KEY_PART_1")]
  pub database_encryption_key_part_1: String,

  /// Second part of the database encryption key (split for security)
  #[clap(long, env = "DATABASE_ENCRYPTION_KEY_PART_2")]
  pub database_encryption_key_part_2: String,

  /// Expiration time in seconds for S3 presigned URLs
  #[clap(
    long,
    env = "AWS_S3_PRESIGNED_URL_EXPIRATION_SECONDS",
    default_value = "300"
  )]
  pub aws_s3_presigned_url_expiration_seconds: u64,

  /// Encryption key for S3 path encryption
  #[clap(long, env = "S3_PATH_ENCRYPTION_KEY")]
  pub s3_path_encryption_key: String,

  /// Optional Sentry DSN for error tracking
  #[clap(long, env = "SENTRY_DSN")]
  pub sentry_dsn: Option<String>,
}

impl DarkwingConfig {
  /// Converts the JWT algorithm string to the corresponding Algorithm enum
  /// value.
  pub fn get_jwt_token_algorithm(&self) -> anyhow::Result<Algorithm> {
    Algorithm::from_str(&self.jwt_token_algorithm)
      .context("Invalid JWT token algorithm in config transform")
  }

  /// Returns the Redis timeout duration.
  pub fn redis_timeout(&self) -> Duration {
    Duration::from_secs(self.redis_default_timeout_seconds)
  }

  /// Returns the expiration duration for presigned URLs.
  pub fn presigned_url_expiration(&self) -> Duration {
    Duration::from_secs(self.aws_s3_presigned_url_expiration_seconds)
  }
}