xmtp_proto/
error.rs

1use std::array::TryFromSliceError;
2
3use thiserror::Error;
4use xmtp_common::RetryableError;
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum ApiEndpoint {
8    Publish,
9    SubscribeGroupMessages,
10    SubscribeWelcomes,
11    UploadKeyPackage,
12    FetchKeyPackages,
13    SendGroupMessages,
14    SendWelcomeMessages,
15    QueryGroupMessages,
16    QueryWelcomeMessages,
17    PublishIdentityUpdate,
18    GetInboxIds,
19    GetIdentityUpdatesV2,
20    VerifyScwSignature,
21    QueryV4Envelopes,
22    PublishEnvelopes,
23    PublishCommitLog,
24    QueryCommitLog,
25    HealthCheck,
26    GetNodes,
27    Path(String),
28    GetNewestGroupMessage,
29}
30
31impl std::fmt::Display for ApiEndpoint {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
33        use ApiEndpoint::*;
34        match self {
35            Publish => write!(f, "publish"),
36            SubscribeGroupMessages => write!(f, "subscribe_group_messages"),
37            SubscribeWelcomes => write!(f, "subscribe_welcomes"),
38            UploadKeyPackage => write!(f, "upload_key_package"),
39            FetchKeyPackages => write!(f, "fetch_key_packages"),
40            SendGroupMessages => write!(f, "send_group_messages"),
41            SendWelcomeMessages => write!(f, "send_welcome_messages"),
42            QueryGroupMessages => write!(f, "query_group_messages"),
43            QueryWelcomeMessages => write!(f, "query_welcome_messages"),
44            PublishIdentityUpdate => write!(f, "publish_identity_update"),
45            GetInboxIds => write!(f, "get_inbox_ids"),
46            GetIdentityUpdatesV2 => write!(f, "get_identity_updates_v2"),
47            VerifyScwSignature => write!(f, "verify_scw_signature"),
48            QueryV4Envelopes => write!(f, "query_v4_envelopes"),
49            PublishEnvelopes => write!(f, "publish_envelopes"),
50            PublishCommitLog => write!(f, "publish_commit_log"),
51            QueryCommitLog => write!(f, "query_commit_log"),
52            HealthCheck => write!(f, "health_check"),
53            GetNodes => write!(f, "get_nodes"),
54            Path(s) => write!(f, "{}", s),
55            GetNewestGroupMessage => write!(f, "get_newest_group_message"),
56        }
57    }
58}
59
60/// General Error types for use when converting/deserializing From/To Protos
61/// Loosely Modeled after serdes [error](https://docs.rs/serde/latest/serde/de/value/struct.Error.html) type.
62/// This general error type avoid circular hard-dependencies on crates further up the tree
63/// (xmtp_id/xmtp_mls) if they had defined the error themselves.
64#[derive(thiserror::Error, Debug)]
65pub enum ConversionError {
66    #[error("missing field {} of type {} during conversion from protobuf", .item, .r#type)]
67    Missing {
68        /// the item being converted
69        item: &'static str,
70        /// type of the item being converted
71        r#type: &'static str,
72    },
73    #[error("field {} unspecified", _0)]
74    Unspecified(&'static str),
75    #[error("field {} deprecated", _0)]
76    Deprecated(&'static str),
77    #[error("type {} has invalid length. expected {} got {}", .item, .expected, .got)]
78    InvalidLength {
79        /// the item being converted
80        item: &'static str,
81        /// expected length of the item being converted
82        expected: usize,
83        /// the length of the received item
84        got: usize,
85    },
86    #[error("type {} invalid. expected {}, got {}", .item, .expected, .got)]
87    InvalidValue {
88        /// the item being converted
89        item: &'static str,
90        /// description of the item expected, i.e 'a negative integer'
91        expected: &'static str,
92        /// description of the value received i.e 'a positive integer'
93        got: String,
94    },
95    #[error("decoding proto {0}")]
96    Decode(#[from] prost::DecodeError),
97    #[error("encoding proto {0}")]
98    Encode(#[from] prost::EncodeError),
99    #[error("Unknown enum value {0}")]
100    UnknownEnumValue(#[from] prost::UnknownEnumValue),
101    // we keep Ed signature bytes on ProtoBuf definitions
102    #[error(transparent)]
103    EdSignature(#[from] ed25519_dalek::ed25519::Error),
104
105    #[error("{} is invalid: {:?}", .description, .value)]
106    InvalidPublicKey {
107        // What kind of key is invalid
108        description: &'static str,
109        // What is the value
110        value: Option<String>,
111    },
112    #[error("version not supported")]
113    InvalidVersion,
114    // TODO: Probably should not be apart of conversion,
115    // conversions using openml sshould be put further up the stack
116    #[error(transparent)]
117    OpenMls(#[from] openmls::prelude::Error),
118    #[error(transparent)]
119    Protocol(#[from] openmls::framing::errors::ProtocolMessageError),
120    #[error(transparent)]
121    Builder(#[from] derive_builder::UninitializedFieldError),
122    #[error(transparent)]
123    Slice(#[from] TryFromSliceError),
124}
125
126// Conversion errors themselves not really retryable because the bytes are static,
127// the conversions are done in-memory, so a retrying a conversion should not change the outcome.
128// The API call is what should be retried.
129// If retry on a conversion error is desired a new error enum + custom Retrayble implementation
130// should be preferred.
131impl RetryableError for ConversionError {
132    fn is_retryable(&self) -> bool {
133        false
134    }
135}
136
137/// Error resulting from proto conversions/mutations
138#[derive(Debug, Error)]
139pub enum ProtoError {
140    #[error(transparent)]
141    Hex(#[from] hex::FromHexError),
142    #[error(transparent)]
143    Decode(#[from] prost::DecodeError),
144    #[error(transparent)]
145    Encode(#[from] prost::EncodeError),
146    #[error("Open MLS {0}")]
147    OpenMls(#[from] openmls::prelude::Error),
148    #[error(transparent)]
149    MlsProtocolMessage(#[from] openmls::framing::errors::ProtocolMessageError),
150    #[error(transparent)]
151    KeyPackage(#[from] openmls::prelude::KeyPackageVerifyError),
152    #[error("{0} not found")]
153    NotFound(String),
154}