Env config
Some checks failed
CI / Check typos (push) Successful in 1m17s
CI / Check links (push) Failing after 1m15s
CI / Clippy (push) Successful in 2m19s
CI / Build and test (push) Successful in 2m1s
CI / Build container (push) Successful in 2m2s
CI / Deploy on waypoint (push) Successful in 47s
Some checks failed
CI / Check typos (push) Successful in 1m17s
CI / Check links (push) Failing after 1m15s
CI / Clippy (push) Successful in 2m19s
CI / Build and test (push) Successful in 2m1s
CI / Build container (push) Successful in 2m2s
CI / Deploy on waypoint (push) Successful in 47s
This commit is contained in:
@@ -12,7 +12,7 @@ use maud::Markup;
|
||||
use parking_lot::Mutex;
|
||||
use std::{collections::HashMap, num::NonZero, pin::Pin, sync::Arc, time::Instant};
|
||||
use tower_http::compression::{CompressionLayer, DefaultPredicate};
|
||||
use tracing::{trace, warn};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{ClientInfo, RequestContext, page::Page};
|
||||
|
||||
|
||||
@@ -14,12 +14,16 @@ tokio = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
num = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
envy = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
|
||||
clap = { workspace = true, optional = true }
|
||||
anstyle = { workspace = true, optional = true }
|
||||
tracing-subscriber = { workspace = true, optional = true }
|
||||
anyhow = { workspace = true, optional = true }
|
||||
|
||||
|
||||
tracing-loki = { workspace = true, optional = true }
|
||||
tokio = { workspace = true, optional = true }
|
||||
url = { workspace = true, optional = true }
|
||||
|
||||
106
crates/lib/toolbox/src/env.rs
Normal file
106
crates/lib/toolbox/src/env.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env::VarError,
|
||||
io::ErrorKind,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
/// An error we might encounter when loading an env
|
||||
#[derive(Debug, Error)]
|
||||
pub enum EnvLoadError {
|
||||
#[error("i/o error")]
|
||||
IOError(#[from] std::io::Error),
|
||||
|
||||
#[error("varerror")]
|
||||
VarError(#[from] VarError),
|
||||
|
||||
#[error("line parse error: `{on_line}` at char {at_char}")]
|
||||
LineParse { on_line: String, at_char: usize },
|
||||
|
||||
#[error("other dotenvy error")]
|
||||
Other(#[from] dotenvy::Error),
|
||||
|
||||
#[error("missing value {0}")]
|
||||
MissingValue(String),
|
||||
|
||||
#[error("parse error: {0}")]
|
||||
OtherParseError(String),
|
||||
}
|
||||
|
||||
pub enum LoadedEnv<T> {
|
||||
/// We loaded config from `.env` and env vars
|
||||
FoundFile { config: T, path: PathBuf },
|
||||
|
||||
/// We could not find `.env` and only loaded env vars
|
||||
OnlyVars(T),
|
||||
}
|
||||
|
||||
impl<T> LoadedEnv<T> {
|
||||
pub fn get_config(&self) -> &T {
|
||||
match self {
|
||||
Self::FoundFile { config, .. } => config,
|
||||
Self::OnlyVars(config) => config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the configuration type `T` from the current environment,
|
||||
/// including the `.env` if it exists.
|
||||
#[expect(clippy::wildcard_enum_match_arm)]
|
||||
pub fn load_env<T: DeserializeOwned>() -> Result<LoadedEnv<T>, EnvLoadError> {
|
||||
let env_path = match dotenvy::dotenv() {
|
||||
Ok(path) => Some(path),
|
||||
|
||||
Err(dotenvy::Error::Io(err)) => match err.kind() {
|
||||
ErrorKind::NotFound => None,
|
||||
_ => return Err(EnvLoadError::IOError(err)),
|
||||
},
|
||||
|
||||
Err(dotenvy::Error::EnvVar(err)) => {
|
||||
return Err(EnvLoadError::VarError(err));
|
||||
}
|
||||
|
||||
Err(dotenvy::Error::LineParse(on_line, at_char)) => {
|
||||
return Err(EnvLoadError::LineParse { on_line, at_char });
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
return Err(EnvLoadError::Other(err));
|
||||
}
|
||||
};
|
||||
|
||||
match envy::from_env::<T>() {
|
||||
Ok(config) => {
|
||||
if let Some(path) = env_path {
|
||||
return Ok(LoadedEnv::FoundFile { path, config });
|
||||
} else {
|
||||
return Ok(LoadedEnv::OnlyVars(config));
|
||||
}
|
||||
}
|
||||
|
||||
Err(envy::Error::MissingValue(value)) => {
|
||||
return Err(EnvLoadError::MissingValue(value.into()));
|
||||
}
|
||||
|
||||
Err(envy::Error::Custom(message)) => {
|
||||
return Err(EnvLoadError::OtherParseError(message));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Load an .env file to a hashmap.
|
||||
///
|
||||
/// This function does not read the current env,
|
||||
/// only parsing vars explicitly declared in the given file.
|
||||
pub fn load_env_dict(p: impl AsRef<Path>) -> Result<HashMap<String, String>, EnvLoadError> {
|
||||
let mut out = HashMap::new();
|
||||
|
||||
for item in dotenvy::from_filename_iter(p)? {
|
||||
let (key, val) = item?;
|
||||
out.insert(key, val);
|
||||
}
|
||||
|
||||
return Ok(out);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
//! This crate contains various bits of useful code that don't fit anywhere else.
|
||||
|
||||
pub mod env;
|
||||
pub mod mime;
|
||||
pub mod misc;
|
||||
pub mod strings;
|
||||
|
||||
Reference in New Issue
Block a user