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 )]
22 AllGuardsDown {
23 retry_at: Option<Instant>,
25 running: FilterCount,
27 pending: FilterCount,
29 suitable: FilterCount,
31 filtered: FilterCount,
33 },
34
35 #[error(
37 "No usable fallbacks. Rejected {} as not running, then {} as filtered.",
38 running.display_frac_rejected(),
39 filtered.display_frac_rejected()
40 )]
41 AllFallbacksDown {
42 retry_at: Option<Instant>,
44 running: FilterCount,
47 filtered: FilterCount,
49 },
50
51 #[error("Tried to pick from an empty list")]
53 NoCandidatesAvailable,
54
55 #[error("Internal error")]
57 Internal(#[from] Bug),
58}
59
60impl tor_error::HasKind for PickGuardError {
61 fn kind(&self) -> tor_error::ErrorKind {
62 use tor_error::ErrorKind as EK;
63 use PickGuardError as E;
64 match self {
65 E::AllFallbacksDown { .. } | E::AllGuardsDown { .. } => EK::TorAccessFailed,
66 E::NoCandidatesAvailable => EK::NoPath,
67 E::Internal(_) => EK::Internal,
68 }
69 }
70}
71
72impl tor_error::HasRetryTime for PickGuardError {
73 fn retry_time(&self) -> tor_error::RetryTime {
74 use tor_error::RetryTime as RT;
75 use PickGuardError as E;
76 match self {
77 E::AllGuardsDown {
79 retry_at: Some(when),
80 ..
81 } => RT::At(*when),
82 E::AllFallbacksDown {
83 retry_at: Some(when),
84 ..
85 } => RT::At(*when),
86
87 E::AllGuardsDown { .. } | E::AllFallbacksDown { .. } => RT::AfterWaiting,
90
91 E::NoCandidatesAvailable => RT::Never,
95
96 E::Internal(_) => RT::Never,
98 }
99 }
100}
101#[derive(Clone, Debug, thiserror::Error)]
103#[non_exhaustive]
104pub enum GuardMgrError {
105 #[error("Problem accessing persistent guard state")]
107 State(#[from] tor_persist::Error),
108
109 #[error("Invalid configuration")]
111 InvalidConfig(#[from] GuardMgrConfigError),
112
113 #[error("Unable to spawn {spawning}")]
115 Spawn {
116 spawning: &'static str,
118 #[source]
120 cause: Arc<SpawnError>,
121 },
122}
123
124impl HasKind for GuardMgrError {
125 #[rustfmt::skip] fn kind(&self) -> ErrorKind {
127 use GuardMgrError as G;
128 match self {
129 G::State(e) => e.kind(),
130 G::InvalidConfig(e) => e.kind(),
131 G::Spawn{ cause, .. } => cause.kind(),
132 }
133 }
134}
135
136impl GuardMgrError {
137 pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> GuardMgrError {
139 GuardMgrError::Spawn {
140 spawning,
141 cause: Arc::new(err),
142 }
143 }
144}
145
146#[derive(Clone, Debug, thiserror::Error)]
154#[non_exhaustive]
155pub enum GuardMgrConfigError {
156 #[error("Configuration requires exclusive access to shared state, but another instance of Arti has the lock: {0}")]
158 NoLock(String),
159}
160
161impl From<GuardMgrConfigError> for tor_config::ReconfigureError {
162 fn from(g: GuardMgrConfigError) -> tor_config::ReconfigureError {
163 use tor_config::ReconfigureError as R;
164 use GuardMgrConfigError as G;
165 match g {
166 e @ G::NoLock(_) => R::UnsupportedSituation(e.to_string()),
167 }
168 }
169}
170
171impl HasKind for GuardMgrConfigError {
172 fn kind(&self) -> ErrorKind {
173 use ErrorKind as EK;
174 use GuardMgrConfigError as G;
175 match self {
176 G::NoLock(_) => EK::NotImplemented,
181 }
182 }
183}