Skip to main content

pb_mapper_client/client/
error.rs

1use std::time::Duration;
2
3use snafu::Snafu;
4
5// The `common::error::Error` spellings below are the source type on nearly every
6// variant; aliasing keeps them as they were.
7use pb_mapper_core as common;
8
9#[derive(Debug, Snafu)]
10#[snafu(visibility(pub(super)))]
11pub enum Error {
12    #[snafu(display("bind local listener error"))]
13    BindLocalListener { source: std::io::Error },
14    #[snafu(display("accept local listener error"))]
15    AcceptLocalStream { source: std::io::Error },
16    #[snafu(display("connect remote stream error"))]
17    ConnectRemoteStream { source: std::io::Error },
18    #[snafu(display("encode subcribe request error"))]
19    EncodeSubcribeReq { source: common::error::Error },
20    #[snafu(display("encode status request error"))]
21    EncodeStatusReq { source: common::error::Error },
22    #[snafu(display("write status request error"))]
23    WriteStatusReq { source: common::error::Error },
24    #[snafu(display("decode status response error"))]
25    DecodeStatusResp { source: common::error::Error },
26    #[snafu(display("we expected `PbConnResponse::Status`,but actual response is `{resp}`"))]
27    StatusRespNotMatch {
28        // Structured representation of response
29        resp: String,
30    },
31    /// The relay answered a status request with a structured refusal.
32    ///
33    /// `retryable` is the relay's own verdict and the reason this is a variant of
34    /// its own: a caller that loops on every status failure would spin forever on
35    /// a refusal that reconnecting cannot fix, such as a namespace the credential
36    /// does not own.
37    #[snafu(display("relay refused the status request: {code}: {message}"))]
38    StatusRemoteError {
39        code: String,
40        message: String,
41        retryable: bool,
42    },
43    #[snafu(display("write subcribe request error"))]
44    WriteSubcribeReq { source: common::error::Error },
45    #[snafu(display("decode subcribe response error"))]
46    DecodeSubcribeResp { source: common::error::Error },
47    #[snafu(display("we expected `PbConnResponse::Subcribe`,but actual response is `{resp}`"))]
48    SubcribeRespNotMatch {
49        // Structured representation of response
50        resp: String,
51    },
52    #[snafu(display("relay refused subscription: {code}: {message}"))]
53    SubscribeRemoteError {
54        code: String,
55        message: String,
56        retryable: bool,
57    },
58    #[snafu(display("header msg tool:`{action}` create failed!"))]
59    CreateHeaderTool {
60        // Must be `reader/writer`
61        action: &'static str,
62        source: common::error::Error,
63    },
64    #[snafu(display("control io `{action}` timed out after {timeout:?}"))]
65    ControlIoTimeout {
66        action: &'static str,
67        timeout: Duration,
68    },
69}
70
71impl Error {
72    /// The relay's verdict on whether the same request could ever succeed, or
73    /// `None` when this failure did not come from the relay.
74    ///
75    /// Transport and framing failures are `None`: nothing about a dropped
76    /// connection says the relay's answer is final.
77    pub fn remote_retryable(&self) -> Option<bool> {
78        match self {
79            Self::StatusRemoteError { retryable, .. } => Some(*retryable),
80            _ => None,
81        }
82    }
83}
84
85pub type Result<T, E = Error> = std::result::Result<T, E>;