Skip to main content

quorum_core/utility/
config_schema.rs

1//! Configuration schema definition.
2//!
3//! This file defines the configuration schema in a declarative way using macros.
4//! Every config field is defined here once, and all related code (struct fields, serialization,
5//! parsing, display, defaults, etc.) is generated from this single definition.
6
7#[macro_export]
8macro_rules! define_config_schema {
9    (
10        $($field_name:ident, $field_type:ty, $default_value:expr, $description:expr),* $(,)?
11    ) => {
12        // ===================
13        // structs and types
14        // ===================
15
16        /// config settings loaded from encrypted secrets.enc
17        #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
18        #[serde(default)]
19        pub struct ConfigFields {
20            $(
21                #[doc = $description]
22                pub $field_name: $field_type,
23            )*
24        }
25
26        /// Serializable config for disk storage (encryption/decryption)
27        pub type SerializableConfigFields = ConfigFields;
28
29        // ===================
30        // metadata
31        // ===================
32
33        /// Metadata about a single config field (name, type, default)
34        pub struct ConfigFieldMeta {
35            pub name: &'static str,
36            pub default_str: &'static str,
37            pub description: &'static str,
38        }
39
40        /// All config field metadata
41        pub const CONFIG_SCHEMA: &[ConfigFieldMeta] = &[
42            $(
43                ConfigFieldMeta {
44                    name: stringify!($field_name),
45                    default_str: stringify!($default_value),
46                    description: $description,
47                },
48            )*
49        ];
50
51        // ===================
52        // defaults
53        // ===================
54
55        /// Returns a new ConfigFields with all default values
56        pub fn default_config_fields() -> ConfigFields {
57            ConfigFields {
58                $(
59                    $field_name: $default_value,
60                )*
61            }
62        }
63
64        impl Default for ConfigFields {
65            fn default() -> Self {
66                default_config_fields()
67            }
68        }
69
70        // ===================
71        // parser
72        // ===================
73
74        /// Parses a config key-value pair and updates the fields struct
75        /// Returns Ok(true) if the key was recognized, Ok(false) if unknown, Err on parse failure
76        pub fn parse_config_field(
77            fields: &mut ConfigFields,
78            key: &str,
79            value: &str,
80        ) -> Result<bool, String> {
81            match key {
82                $(
83                    stringify!($field_name) => {
84                        fields.$field_name = value.parse()
85                            .map_err(|_| format!("Failed to parse {} as {}", key, stringify!($field_type)))?;
86                        Ok(true)
87                    }
88                )*
89                _ => Ok(false),
90            }
91        }
92
93        // ===================
94        // Field iterator
95        // ===================
96
97        /// Returns all field names as a slice
98        pub const fn field_names() -> &'static [&'static str] {
99            &[$(stringify!($field_name)),*]
100        }
101    };
102}
103
104#[rustfmt::skip]
105define_config_schema!(
106    // Server
107    server_port, u16, 3000, "HTTP port the server binds to (e.g. 3000)",
108    server_host, String, "127.0.0.1".to_string(), "IP address the server binds to (e.g. 127.0.0.1 or 0.0.0.0)",
109    server_url, String, "http://127.0.0.1:3000".to_string(), "Full server URL including protocol and port",
110
111    // Database
112    surreal_data_path, String, "./data/db".to_string(), "Path to the directory where SurrealDB stores its on-disk data",
113    surreal_ns, String, "quorum".to_string(), "SurrealDB namespace to use",
114    surreal_db, String, "quorum".to_string(), "SurrealDB database name within the namespace",
115
116    // JWT
117    jwt_secret, String, "default-insecure-secret".to_string(), "Secret key used to sign and verify JWT tokens",
118    jwt_access_minutes, i64, 15, "How long an access token remains valid, in minutes",
119    jwt_refresh_days, i64, 7, "How long a refresh token remains valid, in days",
120
121    // testing features
122    enable_testing, bool, false, "Whether to run the test suite on server startup",
123
124    // Rate Limiting
125    default_per_second, u64, 100, "Rate limit: sustained request rate for standard endpoints",
126    default_burst_size, u32, 200, "Rate limit: maximum burst size for standard endpoints",
127    testing_per_second, u64, 1000, "Rate limit: sustained request rate for test/dev endpoints",
128    testing_burst_size, u32, 2000, "Rate limit: maximum burst size for test/dev endpoints"
129);
130
131pub type SerializableConfig = ConfigFields;