1use std::path::PathBuf;
2
3use dvm_api::{CommandNumber, RunId, RunState, SandboxId};
4
5pub type Result<T, E = Error> = std::result::Result<T, E>;
6
7#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12 #[error("400: {reason}")]
15 InvalidRequest { reason: String },
16 #[error("401: {reason}")]
18 Authentication { reason: String },
19 #[error("404: {reason}")]
22 NotFound { reason: String },
23 #[error("409: {reason}")]
25 Conflict { reason: String },
26 #[error("{status}: {reason}")]
28 Refused { status: u16, reason: String },
29 #[error("sandbox {sandbox} is {}", state.kind())]
32 SandboxEnded { sandbox: SandboxId, state: RunState },
33 #[error("sandbox {sandbox} failed: {reason}")]
36 SandboxFailed { sandbox: SandboxId, reason: String },
37 #[error("command {number} was refused: {reason}")]
40 CommandRefused {
41 number: CommandNumber,
42 reason: String,
43 },
44 #[error("replay {replay} {}{}", state.kind(), failure_of(state))]
47 ReplayEnded { replay: RunId, state: RunState },
48 #[error("no API key for {api_url}: run `dvm-run login`, or set DVM_API_KEY")]
50 NoApiKey { api_url: String },
51 #[error("{}: {problem}", path.display())]
53 Credentials { path: PathBuf, problem: String },
54 #[error("{context}")]
56 Network {
57 context: String,
58 #[source]
59 source: Option<reqwest::Error>,
60 },
61 #[error("{0}")]
63 Unexpected(String),
64}
65
66impl Error {
67 pub(crate) fn refusal(status: u16, reason: String) -> Self {
69 match status {
70 400 => Self::InvalidRequest { reason },
71 401 => Self::Authentication { reason },
72 404 => Self::NotFound { reason },
73 409 => Self::Conflict { reason },
74 status => Self::Refused { status, reason },
75 }
76 }
77
78 pub(crate) fn ended(sandbox: SandboxId, state: RunState) -> Self {
80 match state {
81 RunState::Failed { reason } => Self::SandboxFailed { sandbox, reason },
82 state => Self::SandboxEnded { sandbox, state },
83 }
84 }
85
86 pub(crate) fn network(context: impl Into<String>, source: reqwest::Error) -> Self {
87 Self::Network {
88 context: context.into(),
89 source: Some(source),
90 }
91 }
92}
93
94fn failure_of(state: &RunState) -> String {
95 match state {
96 RunState::Failed { reason } => format!(": {reason}"),
97 _ => String::new(),
98 }
99}