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