use crate::{access::AccessError, dto::prelude::*};
use std::fmt::{self, Display};
#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct Error {
pub code: ErrorCode,
pub message: String,
}
impl Error {
#[must_use]
pub const fn new(code: ErrorCode, message: String) -> Self {
Self { code, message }
}
pub fn conflict(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Conflict, message.into())
}
pub fn policy(code: ErrorCode, message: impl Into<String>) -> Self {
Self::new(code, message.into())
}
pub fn forbidden(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Forbidden, message.into())
}
pub fn internal(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Internal, message.into())
}
pub fn invalid(message: impl Into<String>) -> Self {
Self::new(ErrorCode::InvalidInput, message.into())
}
#[must_use]
pub fn operation_id_required() -> Self {
Self::new(
ErrorCode::OperationIdRequired,
"operation_id is required for this command".to_string(),
)
}
pub fn invariant(message: impl Into<String>) -> Self {
Self::new(ErrorCode::InvariantViolation, message.into())
}
pub fn exhausted(message: impl Into<String>) -> Self {
Self::new(ErrorCode::ResourceExhausted, message.into())
}
pub fn not_found(message: impl Into<String>) -> Self {
Self::new(ErrorCode::NotFound, message.into())
}
pub fn unauthorized(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Unauthorized, message.into())
}
pub fn unavailable(message: impl Into<String>) -> Self {
Self::new(ErrorCode::Unavailable, message.into())
}
pub fn auth_token_expired(message: impl Into<String>) -> Self {
Self::new(ErrorCode::AuthTokenExpired, message.into())
}
pub fn auth_proof_pending(message: impl Into<String>) -> Self {
Self::new(ErrorCode::AuthProofPending, message.into())
}
#[must_use]
pub fn root_data_certificate_unavailable() -> Self {
Self::new(
ErrorCode::RootDataCertificateUnavailable,
"root data certificate unavailable for role-attestation proof retrieval".to_string(),
)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{:?}] {}", self.code, self.message)
}
}
impl From<AccessError> for Error {
fn from(err: AccessError) -> Self {
let kind = err.kind();
let message = err.to_string();
match kind {
crate::access::AccessErrorKind::DelegatedAuthCertExpired => {
Self::new(ErrorCode::AuthProofExpired, message)
}
crate::access::AccessErrorKind::DelegatedAuthTokenExpired => {
Self::auth_token_expired(message)
}
crate::access::AccessErrorKind::Denied => Self::unauthorized(message),
}
}
}
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[non_exhaustive]
#[remain::sorted]
pub enum ErrorCode {
AuthMaterialStale,
AuthProofExpired,
AuthProofPending,
AuthTokenExpired,
Conflict,
Forbidden,
Internal,
InternalRpcMalformed,
InvalidInput,
InvariantViolation,
NotFound,
OperationIdRequired,
PolicyInstanceRequiresServiceWithDirectory,
PolicyReplicaRequiresServiceWithScaling,
PolicyRoleAlreadyRegistered,
PolicyShardRequiresServiceWithSharding,
PolicySingletonAlreadyRegisteredUnderParent,
ResourceExhausted,
RootDataCertificateUnavailable,
Unauthorized,
Unavailable,
WasmStoreCapacityExceeded,
WasmStoreChunkMissing,
WasmStoreHashMismatch,
WasmStoreManifestMissing,
}