Skip to main content

propel_core/
config.rs

1use serde::{Deserialize, Serialize};
2
3/// propel.toml configuration
4#[derive(Debug, Clone, Default, Serialize, Deserialize)]
5pub struct PropelConfig {
6    #[serde(default)]
7    pub project: ProjectConfig,
8    #[serde(default)]
9    pub build: BuildConfig,
10    #[serde(default)]
11    pub cloud_run: CloudRunConfig,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ProjectConfig {
16    /// Project name (defaults to Cargo.toml package name)
17    pub name: Option<String>,
18    /// GCP region (defaults to us-central1)
19    #[serde(default = "default_region")]
20    pub region: String,
21    /// GCP project ID
22    pub gcp_project_id: Option<String>,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct BuildConfig {
27    /// Rust builder image
28    #[serde(default = "default_builder_image")]
29    pub base_image: String,
30    /// Runtime base image
31    #[serde(default = "default_runtime_image")]
32    pub runtime_image: String,
33    /// Additional system packages to install via apt-get
34    #[serde(default)]
35    pub extra_packages: Vec<String>,
36    /// Cargo Chef version
37    #[serde(default = "default_cargo_chef_version")]
38    pub cargo_chef_version: String,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct CloudRunConfig {
43    /// Memory allocation
44    #[serde(default = "default_memory")]
45    pub memory: String,
46    /// CPU count
47    #[serde(default = "default_cpu")]
48    pub cpu: u32,
49    /// Minimum instances
50    #[serde(default)]
51    pub min_instances: u32,
52    /// Maximum instances
53    #[serde(default = "default_max_instances")]
54    pub max_instances: u32,
55    /// Max concurrent requests per instance
56    #[serde(default = "default_concurrency")]
57    pub concurrency: u32,
58    /// Port the application listens on
59    #[serde(default = "default_port")]
60    pub port: u16,
61}
62
63impl Default for ProjectConfig {
64    fn default() -> Self {
65        Self {
66            name: None,
67            region: default_region(),
68            gcp_project_id: None,
69        }
70    }
71}
72
73impl Default for BuildConfig {
74    fn default() -> Self {
75        Self {
76            base_image: default_builder_image(),
77            runtime_image: default_runtime_image(),
78            extra_packages: Vec::new(),
79            cargo_chef_version: default_cargo_chef_version(),
80        }
81    }
82}
83
84impl Default for CloudRunConfig {
85    fn default() -> Self {
86        Self {
87            memory: default_memory(),
88            cpu: default_cpu(),
89            min_instances: 0,
90            max_instances: default_max_instances(),
91            concurrency: default_concurrency(),
92            port: default_port(),
93        }
94    }
95}
96
97impl PropelConfig {
98    /// Load from propel.toml at the given path, or return defaults if not found.
99    pub fn load(project_dir: &std::path::Path) -> crate::Result<Self> {
100        let config_path = project_dir.join("propel.toml");
101        if config_path.exists() {
102            let content =
103                std::fs::read_to_string(&config_path).map_err(|e| crate::Error::ConfigLoad {
104                    path: config_path.clone(),
105                    source: e,
106                })?;
107            toml::from_str(&content).map_err(|e| crate::Error::ConfigParse {
108                path: config_path,
109                source: e,
110            })
111        } else {
112            Ok(Self::default())
113        }
114    }
115}
116
117fn default_region() -> String {
118    "us-central1".to_owned()
119}
120
121fn default_builder_image() -> String {
122    "rust:1.84-bookworm".to_owned()
123}
124
125fn default_runtime_image() -> String {
126    "gcr.io/distroless/cc-debian12".to_owned()
127}
128
129fn default_cargo_chef_version() -> String {
130    "0.1.68".to_owned()
131}
132
133fn default_memory() -> String {
134    "512Mi".to_owned()
135}
136
137fn default_cpu() -> u32 {
138    1
139}
140
141fn default_max_instances() -> u32 {
142    10
143}
144
145fn default_concurrency() -> u32 {
146    80
147}
148
149fn default_port() -> u16 {
150    8080
151}