sos_protocol/error.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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! Error type for the wire protocol.
use crate::{MaybeConflict, SyncStatus};
use http::StatusCode;
use serde_json::Value;
use sos_sdk::time;
use thiserror::Error;
/// Trait for error implementations that
/// support a conflict error.
pub trait AsConflict {
/// Determine if this is a conflict error.
fn is_conflict(&self) -> bool;
/// Determine if this is a hard conflict error.
fn is_hard_conflict(&self) -> bool;
/// Take an underlying conflict error.
fn take_conflict(self) -> Option<ConflictError>;
}
/// Errors generated by the wire protocol.
#[derive(Debug, Error)]
pub enum Error {
/// Reached EOF decoding a relay packet.
#[error("relay packet end of file")]
EndOfFile,
/// Error generated when a conflict is detected.
#[error(transparent)]
Conflict(#[from] ConflictError),
/// Error generated by the IO module.
#[error(transparent)]
Io(#[from] std::io::Error),
/// Error generated converting from a slice.
#[error(transparent)]
TryFromSlice(#[from] std::array::TryFromSliceError),
/// Error generated by the protobuf library when encoding.
#[error(transparent)]
ProtoBufEncode(#[from] prost::EncodeError),
/// Error generated by the protobuf library when decoding.
#[error(transparent)]
ProtoBufDecode(#[from] prost::DecodeError),
/// Error generated by the protobuf library when converting enums.
#[error(transparent)]
ProtoEnum(#[from] prost::UnknownEnumValue),
/// Error generated by the SDK library.
#[error(transparent)]
Sdk(#[from] crate::sdk::Error),
/// Error generated by the merkle tree library.
#[error(transparent)]
Merkle(#[from] rs_merkle::Error),
/// Error generated converting time types.
#[error(transparent)]
Time(#[from] time::error::ComponentRange),
/// Error generated joining a task.
#[error(transparent)]
Join(#[from] tokio::task::JoinError),
/// Error generated parsing URLs.
#[error(transparent)]
UrlParse(#[from] crate::sdk::url::ParseError),
/// Error generated by the HTTP library.
#[error(transparent)]
Http(#[from] http::Error),
/// Error generated by the HTTP library.
#[error(transparent)]
StatusCode(#[from] http::status::InvalidStatusCode),
/// Error generated by the JSON library.
#[error(transparent)]
Json(#[from] serde_json::Error),
/// Error generated by network communication.
#[error(transparent)]
Network(#[from] NetworkError),
}
/// Error created communicating over the network.
#[derive(Debug, Error)]
pub enum NetworkError {
/// Error generated when an unexpected response code is received.
#[error("unexpected response status code {0}")]
ResponseCode(StatusCode),
/// Error generated when an unexpected response code is received.
#[error("unexpected response {1} (code: {0})")]
ResponseJson(StatusCode, Value),
/// Error generated when an unexpected content type is returend.
#[error("unexpected content type {0}, expected: {1}")]
ContentType(String, String),
}
/// Error created whan a conflict is detected.
#[derive(Debug, Error)]
pub enum ConflictError {
/// Error generated when a soft conflict was detected.
///
/// A soft conflict may be resolved by searching for a
/// common ancestor commit and merging changes since
/// the common ancestor commit.
#[error("soft conflict")]
Soft {
/// Conflict information.
conflict: MaybeConflict,
/// Local information sent to the remote.
local: SyncStatus,
/// Remote information in the server reply.
remote: SyncStatus,
},
/// Error generated when a hard conflict was detected.
///
/// A hard conflict is triggered after a soft conflict
/// attempted to scan proofs on a remote and was unable
/// to find a common ancestor commit.
#[error("hard conflict")]
Hard,
}
impl AsConflict for Error {
fn is_conflict(&self) -> bool {
matches!(self, Error::Conflict(_))
}
fn is_hard_conflict(&self) -> bool {
matches!(self, Error::Conflict(ConflictError::Hard))
}
fn take_conflict(self) -> Option<ConflictError> {
match self {
Self::Conflict(err) => Some(err),
_ => None,
}
}
}