use crate::core::datetime::NominalDateTimeError;
use crate::core::rid::RidConversionError;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum Error {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("could not determine home directory")]
HomeDirNotFound,
#[error("YAML parse error: {0}")]
Yaml(#[from] serde_yaml::Error),
#[error("Conjure error: {details}")]
Conjure {
details: String,
status: Option<u16>,
},
#[error("Workspace not provided, but there is no default workspace for the user.")]
NoDefaultWorkspace,
#[error("RID conversion error: invalid RID '{rid}': {reason}")]
Rid { rid: String, reason: String },
#[error("seconds_since_epoch out of range: {0}")]
TimestampSecondsOutOfRange(i64),
#[error("offset_nanoseconds out of range: {0}")]
TimestampNanosOutOfRange(i64),
#[error("invalid timestamp: seconds={seconds}, nanos={nanos}")]
InvalidTimestamp { seconds: i64, nanos: i64 },
#[error("invalid bearer token: {reason}")]
InvalidBearerToken { reason: String },
#[error("invalid service URL '{url}': {reason}")]
InvalidServiceUrl { url: String, reason: String },
#[error("profile '{name}' not found in config")]
ProfileNotFound { name: String },
#[error(
"no config file found at {path}: create with `nomctl config profile add` or `nomctl config init`"
)]
ConfigNotFound { path: String },
#[error("missing 'version' key in config file: {path}")]
ConfigMissingVersion { path: String },
#[error("unsupported config version: {version} (expected 2)")]
ConfigUnsupportedVersion { version: u32, path: String },
#[error("environment variable '{name}' is not set")]
EnvVarNotSet { name: &'static str },
#[error("resource not found: {resource}")]
NotFound { resource: &'static str },
#[error("channel data type missing from server response for channel '{channel}'")]
MissingChannelDataType { channel: String },
#[error("unsupported channel data type for metadata upsert: {data_type}")]
UnsupportedChannelDataType { data_type: String },
#[error("multipart upload failed: {details}")]
Upload { details: String },
#[error("ingest error: {details}")]
Ingest { details: String },
}
impl From<RidConversionError> for Error {
fn from(value: RidConversionError) -> Self {
Self::Rid {
rid: value.rid().to_string(),
reason: value.reason().to_string(),
}
}
}
impl From<NominalDateTimeError> for Error {
fn from(value: NominalDateTimeError) -> Self {
match value {
NominalDateTimeError::SecondsOutOfRange(v) => Self::TimestampSecondsOutOfRange(v),
NominalDateTimeError::NanosOutOfRange(v) => Self::TimestampNanosOutOfRange(v),
NominalDateTimeError::InvalidTimestamp { seconds, nanos } => {
Self::InvalidTimestamp { seconds, nanos }
}
}
}
}
impl From<conjure_error::Error> for Error {
fn from(value: conjure_error::Error) -> Self {
let status = value
.cause()
.downcast_ref::<conjure_runtime::errors::RemoteError>()
.map(|remote| remote.status().as_u16());
Self::Conjure {
details: format!("{value:?}"),
status,
}
}
}
impl Error {
pub fn http_status(&self) -> Option<u16> {
match self {
Self::Conjure { status, .. } => *status,
_ => None,
}
}
}