1use futures::task::SpawnError;
4use std::sync::Arc;
5use std::time::Instant;
6use tor_basic_utils::iter::FilterCount;
7use tor_error::{Bug, ErrorKind, HasKind};
8
9#[derive(Clone, Debug, thiserror::Error)]
11#[non_exhaustive]
12pub enum PickGuardError {
13 #[error(
15 "No usable guards. Rejected {} as down, then {} as pending, then \
16 {} as unsuitable to purpose, then {} with filter.{}",
17 running.display_frac_rejected(),
18 pending.display_frac_rejected(),
19 suitable.display_frac_rejected(),
20 filtered.display_frac_rejected(),
21 if let Some(retry_at) = retry_at {
22 format!(" Retrying in {:?}.", humantime::format_duration(*retry_at - Instant::now()))
23 } else {
24 "".to_string()
25 },
26 )]
27 AllGuardsDown {
28 retry_at: Option<Instant>,
30 running: FilterCount,
32 pending: FilterCount,
34 suitable: FilterCount,
36 filtered: FilterCount,
38 },
39
40 #[error(
42 "No usable fallbacks. Rejected {} as not running, then {} as filtered.",
43 running.display_frac_rejected(),
44 filtered.display_frac_rejected()
45 )]
46 AllFallbacksDown {
47 retry_at: Option<Instant>,
49 running: FilterCount,
52 filtered: FilterCount,
54 },
55
56 #[error("Tried to pick from an empty list")]
58 NoCandidatesAvailable,
59
60 #[error("Internal error")]
62 Internal(#[from] Bug),
63}
64
65impl tor_error::HasKind for PickGuardError {
66 fn kind(&self) -> tor_error::ErrorKind {
67 use PickGuardError as E;
68 use tor_error::ErrorKind as EK;
69 match self {
70 E::AllFallbacksDown { .. } | E::AllGuardsDown { .. } => EK::TorAccessFailed,
71 E::NoCandidatesAvailable => EK::NoPath,
72 E::Internal(_) => EK::Internal,
73 }
74 }
75}
76
77impl tor_error::HasRetryTime for PickGuardError {
78 fn retry_time(&self) -> tor_error::RetryTime {
79 use PickGuardError as E;
80 use tor_error::RetryTime as RT;
81 match self {
82 E::AllGuardsDown {
84 retry_at: Some(when),
85 ..
86 } => RT::At(*when),
87 E::AllFallbacksDown {
88 retry_at: Some(when),
89 ..
90 } => RT::At(*when),
91
92 E::AllGuardsDown { .. } | E::AllFallbacksDown { .. } => RT::AfterWaiting,
95
96 E::NoCandidatesAvailable => RT::Never,
100
101 E::Internal(_) => RT::Never,
103 }
104 }
105}
106#[derive(Clone, Debug, thiserror::Error)]
108#[non_exhaustive]
109pub enum GuardMgrError {
110 #[error("Problem accessing persistent guard state")]
112 State(#[from] tor_persist::Error),
113
114 #[error("Invalid configuration")]
116 InvalidConfig(#[from] GuardMgrConfigError),
117
118 #[error("Unable to spawn {spawning}")]
120 Spawn {
121 spawning: &'static str,
123 #[source]
125 cause: Arc<SpawnError>,
126 },
127}
128
129impl HasKind for GuardMgrError {
130 #[rustfmt::skip] fn kind(&self) -> ErrorKind {
132 use GuardMgrError as G;
133 match self {
134 G::State(e) => e.kind(),
135 G::InvalidConfig(e) => e.kind(),
136 G::Spawn{ cause, .. } => cause.kind(),
137 }
138 }
139}
140
141impl GuardMgrError {
142 pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> GuardMgrError {
144 GuardMgrError::Spawn {
145 spawning,
146 cause: Arc::new(err),
147 }
148 }
149}
150
151#[derive(Clone, Debug, thiserror::Error)]
159#[non_exhaustive]
160pub enum GuardMgrConfigError {
161 #[error(
163 "Configuration requires exclusive access to shared state, but another instance of Arti has the lock: {0}"
164 )]
165 NoLock(String),
166}
167
168impl From<GuardMgrConfigError> for tor_config::ReconfigureError {
169 fn from(g: GuardMgrConfigError) -> tor_config::ReconfigureError {
170 use GuardMgrConfigError as G;
171 use tor_config::ReconfigureError as R;
172 match g {
173 e @ G::NoLock(_) => R::UnsupportedSituation(e.to_string()),
174 }
175 }
176}
177
178impl HasKind for GuardMgrConfigError {
179 fn kind(&self) -> ErrorKind {
180 use ErrorKind as EK;
181 use GuardMgrConfigError as G;
182 match self {
183 G::NoLock(_) => EK::NotImplemented,
188 }
189 }
190}