oxyde_cloud_common/
config.rs1use leptos_config::errors::LeptosConfigError;
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4use thiserror::Error;
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, default)]
14 pub leptos_config: 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; 38] = [
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 is_valid_slug(slug: impl AsRef<str>) -> bool {
32 slug.as_ref().len() >= Self::MIN_SLUG_LENGTH
33 && slug
34 .as_ref()
35 .chars()
36 .next()
37 .map(|c| c.is_ascii_lowercase())
38 .unwrap_or(false)
39 && slug
40 .as_ref()
41 .chars()
42 .all(|c| Self::ALLOWED_CHARS.contains(&c))
43 }
44}
45
46#[derive(Debug, Error)]
47pub enum Error {
48 #[error("IO error: {0}")]
49 Io(#[from] std::io::Error),
50 #[error("TOML parse error: {0}")]
51 Toml(#[from] toml::de::Error),
52 #[error("Leptos config error: {0}")]
53 Leptos(#[from] LeptosConfigError),
54}
55
56impl CloudConfig {
57 pub async fn load(path: &PathBuf) -> Result<Self, Error> {
58 let contents = std::fs::read_to_string(path)?;
59 let mut config: Self = toml::from_str(&contents)?;
60
61 config.leptos_config = leptos_config::get_configuration(Some("Cargo.toml")).await?;
62
63 Ok(config)
64 }
65
66 pub fn deployed_url(&self) -> String {
67 format!("https://{}.leptos.app", self.app.slug)
68 }
69}