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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use thiserror::Error;

/// The RPC Error type.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum RpcError {
  /// Error during the parsing of an IP address and port.
  #[error(transparent)]
  AddrParseError(#[from] std::net::AddrParseError),

  /// Error parsing a UUID.
  #[error("Could not parse UUID '{0}': {1}")]
  UuidParseError(String, uuid::Error),

  /// Upstream error from Tonic.
  #[error(transparent)]
  TransportError(#[from] tonic::transport::Error),

  /// Internal Error.
  #[error("Internal Error: {0}")]
  InternalError(String),

  /// No inherent data found in RPC message.
  #[error("No inherent data found in RPC message")]
  NoInherentData,

  /// Conversion error between types.
  #[error("Could not convert type to or from gRPC to wick.")]
  TypeConversion,

  /// Invalid ComponentKind.
  #[error("Invalid component kind {0}")]
  InvalidComponentKind(i32),

  /// Error used by components.
  #[error("{0}")]
  Component(String),

  /// Component did not include a supported feature list.
  #[error("Component did not include a supported feature list.")]
  MissingFeatures,

  /// Error generated by a component's operations.
  #[error("{0}")]
  Operation(String),

  /// Error sending output to channel.
  #[error("Error sending output to channel")]
  SendError,

  /// General Error.
  #[error("General error : {0}")]
  General(String),

  /// Deserialization Failed.
  #[error("Deserialization Failed : {0}")]
  Deserialization(String),

  /// Error caused by an internal inconsistency.
  #[error("Internal Error : {0}")]
  Internal(&'static str),

  /// Configuration for invocation was empty.
  #[error("Configuration for invocation was empty.")]
  ConfigEmpty,

  /// Configuration for invocation was empty.
  #[error("State for invocation was missing.")]
  StateMissing,

  /// Invalid Type Signature.
  #[error("Invalid signature")]
  InvalidSignature,
}

impl RpcError {
  /// Constructor for a [Box<RpcError::General>]
  pub fn boxed<T: std::fmt::Display>(msg: T) -> Box<Self> {
    Box::new(RpcError::General(msg.to_string()))
  }
}

impl From<tokio::task::JoinError> for RpcError {
  fn from(e: tokio::task::JoinError) -> Self {
    RpcError::InternalError(format!("Tokio Error: {}", e))
  }
}

impl From<std::io::Error> for RpcError {
  fn from(e: std::io::Error) -> Self {
    RpcError::InternalError(format!("IO Error: {}", e))
  }
}

impl From<Box<dyn std::error::Error + Send + Sync>> for RpcError {
  fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
    RpcError::Component(e.to_string())
  }
}

impl From<&str> for RpcError {
  fn from(e: &str) -> Self {
    RpcError::General(e.to_owned())
  }
}

impl From<String> for RpcError {
  fn from(e: String) -> Self {
    RpcError::General(e)
  }
}

/// The error type that [crate::RpcClient] methods produce.
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum RpcClientError {
  /// An error originating from a List RPC call.
  #[error("RPC List call failed: {0}")]
  ListCallFailed(tonic::Status),

  /// An error originating from an Invocation RPC call.
  #[error("RPC Invocation failed: {0}")]
  InvocationFailed(tonic::Status),

  /// An error originating from a Stats RPC call.
  #[error("RPC Stats call failed: {0}")]
  StatsCallFailed(tonic::Status),

  /// Invalid response from RPC call.
  #[error("RPC response invalid: {0}")]
  ResponseInvalid(String),

  /// Error converting to or from RPC data types.
  #[error(transparent)]
  ConversionFailed(RpcError),

  /// Conversion error between types.
  #[error("Could not convert type to or from gRPC to wick: {0}")]
  TypeConversion(String),

  /// General IO error
  #[error("I/O error: {0}")]
  IO(std::io::Error),

  /// Error with Tls configuration
  #[error("Tls error: {0}")]
  TlsError(tonic::transport::Error),

  /// Error connecting to service
  #[error("{0}")]
  ConnectionError(String),

  /// Unspecified error connecting to service
  #[error("unspecified connection error")]
  UnspecifiedConnectionError,

  /// Connection failed
  #[error("Connection failed: {0}")]
  ConnectionFailed(String),

  /// General error
  #[error("{0}")]
  Other(String),
}

impl From<std::io::Error> for RpcClientError {
  fn from(e: std::io::Error) -> Self {
    RpcClientError::IO(e)
  }
}

#[cfg(test)]
mod test {

  use super::*;
  const fn sync_send<T>()
  where
    T: Sync + Send,
  {
  }

  #[test]
  const fn test_sync_send() {
    sync_send::<RpcError>();
    sync_send::<RpcClientError>();
  }
}