use std::net::SocketAddr;
use thiserror::Error;
use super::pds::PdsError;
use super::session::SessionError;
use crate::signing_key::KeyLoadError;
pub mod code {
pub const SUCCESS: i32 = 0;
pub const USAGE: i32 = 2;
pub const SESSION: i32 = 3;
pub const NETWORK: i32 = 4;
pub const AUTH: i32 = 5;
pub const FORBIDDEN: i32 = 6;
pub const SERVER_4XX: i32 = 7;
pub const SERVER_5XX: i32 = 8;
pub const INTERNAL: i32 = 10;
pub const LEASE_CONFLICT: i32 = 11;
}
#[derive(Debug, Error)]
pub enum CliError {
#[error("{0}")]
Session(#[from] SessionError),
#[error("{0}")]
Pds(#[from] PdsError),
#[error("not logged in; run `cairn login --cairn-server ... --pds ... --handle ...`")]
NotLoggedIn,
#[error("network error contacting {url}: {source}")]
Http {
url: String,
#[source]
source: reqwest::Error,
},
#[error("Cairn at {url} returned {status}: {body}")]
CairnStatus {
url: String,
status: u16,
body: String,
},
#[error("could not parse Cairn response from {url}: {source}")]
MalformedResponse {
url: String,
#[source]
source: serde_json::Error,
},
#[error("{0}")]
Config(String),
#[error("signing key load failed: {0}")]
KeyLoad(#[from] KeyLoadError),
#[error("migrations failed: {0}")]
MigrationFailed(String),
#[error("another Cairn instance holds the lease (instance_id={instance_id}, age={age_secs}s)")]
LeaseConflict {
instance_id: String,
age_secs: u64,
},
#[error("could not bind {addr}: {source}")]
BindFailed {
addr: SocketAddr,
#[source]
source: std::io::Error,
},
#[error("startup failure: {0}")]
Startup(String),
}
impl CliError {
pub fn exit_code(&self) -> i32 {
match self {
CliError::Session(SessionError::Io(_)) => code::SESSION,
CliError::Session(_) => code::SESSION,
CliError::NotLoggedIn => code::SESSION,
CliError::Pds(PdsError::Network { .. }) => code::NETWORK,
CliError::Pds(PdsError::Unauthorized { .. }) => code::AUTH,
CliError::Pds(PdsError::InvalidUrl { .. }) => code::USAGE,
CliError::Pds(PdsError::MalformedResponse { .. }) => code::INTERNAL,
CliError::Pds(PdsError::SwapRace { .. }) => code::INTERNAL,
CliError::Pds(PdsError::UnexpectedStatus { status, .. }) => match *status {
401 => code::AUTH,
403 => code::FORBIDDEN,
400..=499 => code::SERVER_4XX,
500..=599 => code::SERVER_5XX,
_ => code::INTERNAL,
},
CliError::Http { .. } => code::NETWORK,
CliError::CairnStatus { status, .. } => match *status {
401 => code::AUTH,
403 => code::FORBIDDEN,
400..=499 => code::SERVER_4XX,
500..=599 => code::SERVER_5XX,
_ => code::INTERNAL,
},
CliError::MalformedResponse { .. } => code::INTERNAL,
CliError::Config(_) => code::USAGE,
CliError::KeyLoad(_) => code::INTERNAL,
CliError::MigrationFailed(_) => code::INTERNAL,
CliError::LeaseConflict { .. } => code::LEASE_CONFLICT,
CliError::BindFailed { .. } => code::NETWORK,
CliError::Startup(_) => code::INTERNAL,
}
}
}