//! Custom error type. use std::io::Error as IoError; use std::str::Utf8Error; use base64::DecodeError; use kuska_handshake::async_std::Error as HandshakeError; use kuska_ssb::api::Error as ApiError; use kuska_ssb::feed::Error as FeedError; use kuska_ssb::rpc::Error as RpcError; use serde_json::Error as JsonError; /// A custom error type encapsulating all possible errors for this library. /// `From` implementations are provided for external error types, allowing /// the `?` operator to be used on functions which return `Result<_, GolgiError>`. #[derive(Debug)] pub enum GolgiError { /// Failed to decode base64. DecodeBase64(DecodeError), /// IO error with context. Io { /// The underlying IO error. source: IoError, /// Description of the error context. context: String, }, /// Scuttlebutt secret handshake error. Handshake(HandshakeError), /// Kuska SSB API error. Api(ApiError), /// Kuska SSB feed error. Feed(FeedError), /// Kuska SSB RPC error. Rpc(RpcError), /// Go-sbot error. Sbot(String), /// SSB sigil-link error. SigilLink(String), /// JSON serialization or deserialization error. SerdeJson(JsonError), /// Error decoding typed SSB message from content. ContentType(String), /// Error decoding UTF8 string from bytes Utf8Parse { /// The underlying parse error. source: Utf8Error, }, } impl std::error::Error for GolgiError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match *self { GolgiError::DecodeBase64(ref err) => Some(err), GolgiError::Io { ref source, .. } => Some(source), GolgiError::Handshake(_) => None, GolgiError::Api(ref err) => Some(err), GolgiError::Feed(ref err) => Some(err), GolgiError::Rpc(ref err) => Some(err), GolgiError::Sbot(_) => None, GolgiError::SigilLink(_) => None, GolgiError::SerdeJson(ref err) => Some(err), GolgiError::ContentType(_) => None, GolgiError::Utf8Parse { ref source } => Some(source), } } } impl std::fmt::Display for GolgiError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { // TODO: add context (what were we trying to decode?) GolgiError::DecodeBase64(_) => write!(f, "Failed to decode base64"), GolgiError::Io { ref context, .. } => write!(f, "IO error: {}", context), GolgiError::Handshake(ref err) => write!(f, "Handshake failure: {}", err), GolgiError::Api(ref err) => write!(f, "SSB API failure: {}", err), GolgiError::Feed(ref err) => write!(f, "SSB feed error: {}", err), // TODO: improve this variant with a context message // then have the core display msg be: "SSB RPC error: {}", context GolgiError::Rpc(ref err) => write!(f, "SSB RPC failure: {}", err), GolgiError::Sbot(ref err) => write!(f, "Sbot encountered an error: {}", err), GolgiError::SigilLink(ref context) => write!(f, "SSB blob ID error: {}", context), GolgiError::SerdeJson(_) => write!(f, "Failed to serialize JSON slice"), //GolgiError::WhoAmI(ref err) => write!(f, "{}", err), GolgiError::ContentType(ref err) => write!( f, "Failed to decode typed message from SSB message content: {}", err ), GolgiError::Utf8Parse { source } => { write!(f, "Failed to deserialize UTF8 from bytes: {}", source) } } } } impl From for GolgiError { fn from(err: DecodeError) -> Self { GolgiError::DecodeBase64(err) } } impl From for GolgiError { fn from(err: HandshakeError) -> Self { GolgiError::Handshake(err) } } impl From for GolgiError { fn from(err: ApiError) -> Self { GolgiError::Api(err) } } impl From for GolgiError { fn from(err: FeedError) -> Self { GolgiError::Feed(err) } } impl From for GolgiError { fn from(err: RpcError) -> Self { GolgiError::Rpc(err) } } impl From for GolgiError { fn from(err: JsonError) -> Self { GolgiError::SerdeJson(err) } } impl From for GolgiError { fn from(err: Utf8Error) -> Self { GolgiError::Utf8Parse { source: err } } }