-
Notifications
You must be signed in to change notification settings - Fork 4
/
errors.rs
125 lines (107 loc) · 3.61 KB
/
errors.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::{
collections::BTreeMap,
fmt::{self, Write as _},
};
use axum::response::{IntoResponse, Response};
use itertools::Itertools as _;
use thegraph_core::{BlockNumber, IndexerId};
use crate::graphql;
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// Errors that should only occur in exceptional conditions.
#[error("internal error: {0:#}")]
Internal(anyhow::Error),
/// Failed to authenticate or authorize the client request.
#[error("auth error: {0:#}")]
Auth(anyhow::Error),
/// The requested subgraph or deployment is not found or invalid.
#[error("subgraph not found: {0:#}")]
SubgraphNotFound(anyhow::Error),
/// The GraphQL query is invalid.
#[error("bad query: {0:#}")]
BadQuery(anyhow::Error),
/// There are no indexers allocated to the requested subgraph or deployment.
#[error("no indexers found")]
NoIndexers,
/// Indexers are available, but failed to return a suitable result.
#[error("bad indexers: {0}")]
BadIndexers(IndexerErrors),
}
impl IntoResponse for Error {
fn into_response(self) -> Response {
tracing::info!(response_err = %self);
graphql::error_response(self).into_response()
}
}
#[derive(Debug, Clone, Default)]
pub struct IndexerErrors(pub BTreeMap<IndexerId, IndexerError>);
impl std::ops::Deref for IndexerErrors {
type Target = BTreeMap<IndexerId, IndexerError>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for IndexerErrors {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl fmt::Display for IndexerErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let entries = self.iter().map(|(k, v)| format!("{k:?}: {v}")).join(", ");
write!(f, "{{{}}}", entries)
}
}
#[derive(thiserror::Error, Clone, Debug)]
pub enum IndexerError {
/// The indexer is considered unavailable.
#[error("Unavailable({0})")]
Unavailable(UnavailableReason),
/// The indexer request timed out.
#[error("Timeout")]
Timeout,
/// The indexer’s response is bad.
#[error("BadResponse({0:#})")]
BadResponse(String),
}
#[derive(thiserror::Error, Clone, Debug)]
pub enum UnavailableReason {
/// The indexer is blocked.
#[error("blocked ({0})")]
Blocked(String),
/// The indexer version is not supported (e.g., the indexer service version is below the minimum
/// version required by the gateway, etc.)
#[error("not supported: {0}")]
NotSupported(String),
/// The indexer information resolution failed (e.g. the indexer failed to report the indexer
/// version within the expected time, the indexer failed to report the indexing progress info
/// within the expected time, etc.)
#[error("no status: {0}")]
NoStatus(String),
/// The indexer did not have a block required by the query.
#[error("{}", .0.message())]
MissingBlock(MissingBlockError),
/// The indexer is too far behind chain head for an unconstrained query.
#[error("too far behind")]
TooFarBehind,
/// An internal error occurred.
#[error("internal error: {0}")]
Internal(&'static str),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MissingBlockError {
pub missing: Option<BlockNumber>,
pub latest: Option<BlockNumber>,
}
impl MissingBlockError {
fn message(&self) -> String {
let mut text = "missing block".to_string();
if let Some(n) = self.missing {
write!(&mut text, ": {n}").unwrap();
}
if let Some(n) = self.latest {
write!(&mut text, ", latest: {n}").unwrap();
}
text
}
}