use std::sync::Arc;
use fs_mistrust::anon_home::PathExt as _;
use tor_error::ErrorKind;
#[derive(Debug, Clone, derive_more::Display)]
pub(crate) enum Resource {
#[display(fmt = "persistent storage manager")]
Manager,
#[display(fmt = "directory {}", "dir.anonymize_home()")]
Directory {
dir: std::path::PathBuf,
},
#[display(fmt = "{} in {}", "file.display()", "container.anonymize_home()")]
File {
container: std::path::PathBuf,
file: std::path::PathBuf,
},
#[cfg(feature = "testing")]
#[display(fmt = "{} in memory-backed store", key)]
Temporary {
key: String,
},
}
#[derive(Debug, Clone, derive_more::Display, Eq, PartialEq)]
pub(crate) enum Action {
#[display(fmt = "loading persistent data")]
Loading,
#[display(fmt = "storing persistent data")]
Storing,
#[display(fmt = "acquiring lock")]
Locking,
#[display(fmt = "releasing lock")]
Unlocking,
#[display(fmt = "constructing storage manager")]
Initializing,
}
#[derive(thiserror::Error, Debug, Clone)]
#[non_exhaustive]
pub enum ErrorSource {
#[error("IO error")]
IoError(#[source] Arc<std::io::Error>),
#[error("Invalid permissions")]
Permissions(#[from] fs_mistrust::Error),
#[error("Storage not locked")]
NoLock,
#[error("JSON error")]
Serde(#[from] Arc<serde_json::Error>),
}
#[derive(Clone, Debug, derive_more::Display)]
#[display(fmt = "{} while {} on {}", source, action, resource)]
pub struct Error {
source: ErrorSource,
action: Action,
resource: Resource,
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.source()
}
}
impl Error {
pub fn source(&self) -> &ErrorSource {
&self.source
}
pub(crate) fn new(err: impl Into<ErrorSource>, action: Action, resource: Resource) -> Self {
Error {
source: err.into(),
action,
resource,
}
}
}
impl tor_error::HasKind for Error {
#[rustfmt::skip] fn kind(&self) -> ErrorKind {
use ErrorSource as E;
use tor_error::ErrorKind as K;
match &self.source {
E::IoError(..) => K::PersistentStateAccessFailed,
E::Permissions(e) => if e.is_bad_permission() {
K::FsPermissions
} else {
K::PersistentStateAccessFailed
}
E::NoLock => K::BadApiUsage,
E::Serde(..) if self.action == Action::Storing => K::Internal,
E::Serde(..) => K::PersistentStateCorrupted,
}
}
}
impl From<std::io::Error> for ErrorSource {
fn from(e: std::io::Error) -> ErrorSource {
ErrorSource::IoError(Arc::new(e))
}
}
impl From<serde_json::Error> for ErrorSource {
fn from(e: serde_json::Error) -> ErrorSource {
ErrorSource::Serde(Arc::new(e))
}
}