service_skeleton/
config.rs1use secrecy::SecretString;
2use std::{
3 collections::HashMap,
4 fmt::{Debug, Display},
5};
6
7use crate::Error;
8
9pub trait Service {
10 fn from_env_vars(
11 prefix: &str,
12 vars: impl Iterator<Item = (String, String)>,
13 ) -> Result<Self, Error>
14 where
15 Self: Sized;
16}
17
18impl Service for () {
19 fn from_env_vars(
20 _prefix: &str,
21 _vars: impl Iterator<Item = (String, String)>,
22 ) -> Result<Self, Error> {
23 Ok(())
24 }
25}
26
27pub fn determine_value<RT: Debug + Sync + Send, E: Display>(
28 var: &str,
29 parser: impl Fn(&str) -> Result<RT, E>,
30 env_value: Option<&str>,
31 default: Option<&'static str>,
32) -> Result<RT, Error> {
33 let value_to_parse: &str = match (env_value, default) {
34 (None, Some(default_value)) => Ok(default_value),
35 (Some(value), _) => Ok(value),
36 (None, None) => Err(Error::no_config_value(var)),
37 }?;
38
39 parser(value_to_parse).map_err(|e| Error::config_value_parse(var, e))
40}
41
42pub fn determine_optional_value<RT: Debug + Sync + Send, E: Display>(
43 var: &str,
44 parser: impl Fn(&str) -> Result<RT, E>,
45 env_value: Option<&str>,
46 default: Option<&'static str>,
47) -> Result<Option<RT>, Error> {
48 let value_to_parse: &str = match (env_value, default) {
49 (None, Some(default_value)) => Ok::<&str, Error>(default_value),
50 (Some(value), _) => Ok::<&str, Error>(value),
51 (None, None) => return Ok(None),
52 }?;
53
54 parser(value_to_parse)
55 .map_err(|e| Error::config_value_parse(var, e))
56 .map(|v| Some(v))
57}
58
59pub fn fetch_encrypted_field<H1: ::std::hash::BuildHasher, H2: ::std::hash::BuildHasher>(
60 var_map: &HashMap<String, String, H1>,
61 key_map: &mut HashMap<Key, SecretString, H2>,
62 value_field_var: &str,
63 key_spec: &Key,
64) -> Result<Option<String>, Error> {
65 let Some(value) = var_map.get(value_field_var) else {
66 return Ok(None);
67 };
68
69 let key = if let Some(k) = key_map.get(key_spec) {
70 k
71 } else {
72 let k = match key_spec {
73 Key::File(ref file_env) => {
74 let Some(key_file) = var_map.get(file_env) else {
75 return Err(Error::no_config_value(file_env));
76 };
77 std::fs::read_to_string(key_file)
78 .map_err(|e| Error::key_read(key_file, e))?
79 .trim_end()
80 .to_string()
81 }
82 };
83 key_map.insert(key_spec.clone(), k.into());
84 #[allow(clippy::unwrap_used)]
86 key_map.get(key_spec).unwrap()
87 };
88
89 Ok(Some(sscrypt::decrypt(value, value_field_var, key)?))
90}
91
92#[derive(Clone, Debug, PartialEq, Hash, Eq)]
93#[non_exhaustive]
94#[doc(hidden)]
97pub enum Key {
98 File(String),
99}