Skip to main content

sozu_client/
config.rs

1//! # Configuration module
2//!
3//! This module provides helpers to load Sōzu configuration
4
5use std::path::PathBuf;
6
7use config::{ConfigError, File};
8use sozu_command_lib::config::{Config, ConfigBuilder, ConfigError as ConfigBuilderError};
9
10// -----------------------------------------------------------------------------
11// Error
12
13#[derive(thiserror::Error, Debug)]
14pub enum Error {
15    #[error("failed to load configuration from path '{0}', {1}")]
16    Build(String, ConfigError),
17    #[error("failed to deserialize configuration keys-values into internal structure, {0}")]
18    Deserialize(ConfigError),
19    #[error("failed to convert configuration into internal representation structure, {0}")]
20    Convert(ConfigBuilderError),
21    #[error("failed to convert path to utf-8 string, there is incompatibility, {0}")]
22    PathIsInvalid(String),
23    #[error("failed to canonicalize the command socket path, {0}")]
24    Canonicalize(std::io::Error),
25}
26
27// -----------------------------------------------------------------------------
28// helpers
29
30/// Try to load Sōzu configuration from path
31#[tracing::instrument]
32pub fn try_from(path: &PathBuf) -> Result<Config, Error> {
33    let file_config = config::Config::builder()
34        .add_source(File::from(path.as_path()).required(true))
35        .build()
36        .map_err(|err| Error::Build(path.display().to_string(), err))?
37        .try_deserialize()
38        .map_err(Error::Deserialize)?;
39
40    let config_path = path
41        .to_str()
42        .ok_or_else(|| Error::PathIsInvalid(path.display().to_string()))?;
43
44    ConfigBuilder::new(file_config, config_path)
45        .into_config()
46        .map_err(Error::Convert)
47}
48
49/// Canonicalize command socket.
50/// Take the path of the configuration and the configuration to retrieve the
51/// canonical path of the command socket.
52#[tracing::instrument(skip_all)]
53pub fn canonicalize_command_socket(path: &PathBuf, config: &Config) -> Result<PathBuf, Error> {
54    match &config.command_socket {
55        // if the socket path is absolute do nothing.
56        socket if socket.starts_with('/') => Ok(PathBuf::from(socket)),
57        // else canonicalize the socket path
58        socket => {
59            let mut socket_path = PathBuf::from(socket)
60                .parent()
61                .ok_or_else(|| Error::PathIsInvalid(path.display().to_string()))?
62                .to_owned();
63
64            socket_path.push(path);
65            socket_path.canonicalize().map_err(Error::Canonicalize)
66        }
67    }
68}