oxyde_cloud_common/
config.rs

1use anyhow::{Context, Result};
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5use toml::Table;
6
7#[derive(Serialize, Deserialize, Debug, Clone)]
8pub struct CloudConfig {
9    pub app: AppConfig,
10
11    pub env: Table,
12
13    #[serde(skip)]
14    pub leptos_config: Option<leptos_config::ConfFile>,
15}
16
17#[derive(Serialize, Deserialize, Debug, Clone)]
18pub struct AppConfig {
19    pub slug: String,
20}
21
22impl AppConfig {
23    pub const ALLOWED_CHARS: [char; 37] = [
24        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
25        's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
26        '-',
27    ];
28
29    pub const MIN_SLUG_LENGTH: usize = 5;
30
31    pub fn slug_requirements() -> String {
32        format!(
33            "[a-z0-9-] App slug must be at least {} characters long, lower case alphanumeric and can contain dashes.",
34            Self::MIN_SLUG_LENGTH
35        )
36    }
37
38    pub fn is_valid_slug(slug: impl AsRef<str>) -> bool {
39        slug.as_ref().len() >= Self::MIN_SLUG_LENGTH
40            && slug
41                .as_ref()
42                .chars()
43                .next()
44                .map(|c| c.is_ascii_lowercase())
45                .unwrap_or(false)
46            && slug
47                .as_ref()
48                .chars()
49                .all(|c| Self::ALLOWED_CHARS.contains(&c))
50    }
51}
52
53// Error type replaced with anyhow::Result for better error handling
54
55impl CloudConfig {
56    pub async fn load(path: &PathBuf) -> Result<Self> {
57        let contents = std::fs::read_to_string(path)
58            .with_context(|| format!("Failed to read config file: {}", path.display()))?;
59
60        let mut config: Self = toml::from_str(&contents)
61            .with_context(|| format!("Failed to parse TOML config file: {}", path.display()))?;
62
63        config.leptos_config = Some(
64            leptos_config::get_configuration(Some("Cargo.toml"))
65                .context("Failed to load Leptos configuration")?,
66        );
67
68        Ok(config)
69    }
70
71    pub fn deployed_url(&self) -> String {
72        format!("https://{}.oxydecloud.com", self.app.slug)
73    }
74}