qcs_api_client_common/configuration/
error.rs

1use std::{error::Error, path::PathBuf};
2
3use super::ClientConfigurationBuilderError;
4
5/// Errors that can occur when loading a configuration.
6#[derive(Debug, thiserror::Error)]
7#[non_exhaustive]
8pub enum LoadError {
9    /// Failed to load config from a file.
10    #[error("Failed to load settings: {0}")]
11    Load(Box<dyn Error + Send + Sync + 'static>),
12    /// Failed to access or parse an environment variable.
13    #[error("Failed to load value from the environment variable {variable_name}: {message}")]
14    EnvVar {
15        /// The name of the environment variable.
16        variable_name: String,
17        /// The error message.
18        message: String,
19    },
20    /// Failed to load a file from a path.
21    #[error("Failed to load file from path {path:?}: {message}")]
22    Path {
23        /// The path that could not be loaded.
24        path: PathBuf,
25        /// The error message.
26        message: String,
27    },
28    /// The file could not be read or written to.
29    #[error(transparent)]
30    Io(#[from] std::io::Error),
31    /// Failed to use the builder to build a configuration.
32    #[error("Failed to build the ClientConfiguration: {0}")]
33    Build(#[from] ClientConfigurationBuilderError),
34    /// Provided profile not found.
35    #[error("Expected profile {0} in settings.profiles but it does not exist")]
36    ProfileNotFound(String),
37    /// Provided authorization server not found.
38    #[error("Expected auth server {0} in settings.auth_servers but it does not exist")]
39    AuthServerNotFound(String),
40    #[cfg(feature = "tracing-config")]
41    /// Failed to parse tracing filter. These should be a comma separated list of URL patterns. See
42    /// <https://wicg.github.io/urlpattern> for reference.
43    #[error("Could not parse tracing filter: {0}")]
44    TracingFilterParseError(#[from] crate::tracing_configuration::TracingFilterError),
45}
46
47impl<E: Error + 'static> From<shellexpand::LookupError<E>> for LoadError {
48    fn from(value: shellexpand::LookupError<E>) -> Self {
49        Self::EnvVar {
50            variable_name: value.var_name,
51            message: value.cause.to_string(),
52        }
53    }
54}
55
56impl From<figment::Error> for LoadError {
57    fn from(value: figment::Error) -> Self {
58        Self::Load(Box::new(value))
59    }
60}
61
62/// Errors that can occur when managing authorization tokens.
63#[derive(Debug, thiserror::Error)]
64pub enum TokenError {
65    /// No QCS API refresh token to use.
66    #[error("No refresh token is configured within the selected QCS credential.")]
67    NoRefreshToken,
68    /// No access token to use.
69    #[error("No access token has been requested.")]
70    NoAccessToken,
71    /// No access token to use.
72    #[error("Requested an access token for a configuration without credentials.")]
73    NoCredentials,
74    /// Access token is invalid.
75    #[error("The access token is invalid: {0}")]
76    InvalidAccessToken(jsonwebtoken::errors::Error),
77    /// No QCS API refresh token to use.
78    #[error("No auth server is configured within the selected QCS credential.")]
79    NoAuthServer,
80    /// Failure fetching a refreshed access token from the QCS API.
81    #[error("Error fetching new token from the QCS API: {0}")]
82    Fetch(#[from] reqwest::Error),
83    /// Catch all for errors returned from an [`super::ExternallyManaged`] refresh function.
84    #[error("Failed to request an externally managed access token: {0}")]
85    ExternallyManaged(String),
86    /// Failure writing the new access token to the secrets file.
87    #[error("Failed to write the new access token to the secrets file: {0}")]
88    Write(#[from] WriteError),
89}
90
91/// Errors that can occur when trying to write or update a configuration file.
92#[derive(Debug, thiserror::Error)]
93pub enum WriteError {
94    /// There was an IO error while updating the secrets file.
95    #[error(transparent)]
96    IoWithPath(#[from] IoErrorWithPath),
97    /// The file's contents are not valid TOML
98    #[error("File could not be read as TOML: {0}")]
99    InvalidToml(#[from] toml_edit::TomlError),
100    /// TOML table could not be found.
101    #[error("The table `{0}` does not exist.")]
102    MissingTable(String),
103    /// There was an error with time formatting
104    #[error("Error formatting time: {0}.")]
105    TimeFormat(#[from] time::error::Format),
106    /// There was an error writing or persisting the temporary secrets file during access token refresh.
107    #[error("Error writing or persisting temporary secrets file during access token refresh: {0}")]
108    TempFile(#[from] async_tempfile::Error),
109}
110
111/// A fallible IO operation that can result in a [`IoErrorWithPath`]
112#[derive(Debug)]
113pub enum IoOperation {
114    Open,
115    Read,
116    Write,
117    Rename { dest: PathBuf },
118    GetMetadata,
119    SetPermissions,
120    Flush,
121}
122
123/// An error wrapping [`std::io::Error`] that includes the path and operation as additional context.
124#[derive(Debug, thiserror::Error)]
125#[error("Io error while error performing {operation:?} on {path}: {error}")]
126pub struct IoErrorWithPath {
127    #[source]
128    pub error: std::io::Error,
129    pub path: PathBuf,
130    pub operation: IoOperation,
131}