ckb_light_client_protocol_server/
status.rs

1use std::{fmt, time::Duration};
2
3use crate::constant;
4
5/// StatusCodes indicate whether a specific operation has been successfully completed.
6///
7/// The StatusCode element is a 3-digit integer.
8///
9/// The first digest of the StatusCode defines the class of result:
10///   - 1xx: Informational response – the request was received, continuing process.
11///   - 2xx: Success - The action requested by the client was received, understood, and accepted.
12///   - 4xx: Client errors - The error seems to have been caused by the client.
13///   - 5xx: Server errors - The server failed to fulfil a request.
14#[repr(u16)]
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub enum StatusCode {
17    /// OK
18    OK = 200,
19
20    /// Malformed protocol message.
21    MalformedProtocolMessage = 400,
22    /// Unexpected light-client protocol message.
23    UnexpectedProtocolMessage = 401,
24
25    /// The request data is incorrect.
26    InvalidRequest = 410,
27    /// The last block sent from client is invalid.
28    InvalidLastBlock = 411,
29    /// At least one unconfirmed block sent from client is invalid.
30    InvalidUnconfirmedBlock = 412,
31    /// The difficulty boundary is not in the provided block range.
32    InvaildDifficultyBoundary = 413,
33
34    /// Throws an internal error.
35    InternalError = 500,
36    /// Throws an error from the network.
37    Network = 501,
38}
39
40/// Process message status.
41#[derive(Clone, Debug, Eq)]
42pub struct Status {
43    code: StatusCode,
44    context: Option<String>,
45}
46
47impl PartialEq for Status {
48    fn eq(&self, other: &Self) -> bool {
49        self.code == other.code
50    }
51}
52
53impl fmt::Display for Status {
54    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55        match self.context {
56            Some(ref context) => write!(f, "{:?}({}): {}", self.code, self.code as u16, context),
57            None => write!(f, "{:?}({})", self.code, self.code as u16),
58        }
59    }
60}
61
62impl From<StatusCode> for Status {
63    fn from(code: StatusCode) -> Self {
64        Self::new::<&str>(code, None)
65    }
66}
67
68impl StatusCode {
69    /// Convert a status code into a status which has a context.
70    pub fn with_context<S: ToString>(self, context: S) -> Status {
71        Status::new(self, Some(context))
72    }
73}
74
75impl Status {
76    /// Creates a new status.
77    pub fn new<T: ToString>(code: StatusCode, context: Option<T>) -> Self {
78        Self {
79            code,
80            context: context.map(|c| c.to_string()),
81        }
82    }
83
84    /// Returns a `OK` status.
85    pub fn ok() -> Self {
86        Self::new::<&str>(StatusCode::OK, None)
87    }
88
89    /// Whether the code is `OK` or not.
90    pub fn is_ok(&self) -> bool {
91        self.code == StatusCode::OK
92    }
93
94    /// Whether the session should be banned.
95    pub fn should_ban(&self) -> Option<Duration> {
96        let code = self.code as u16;
97        if !(400..500).contains(&code) {
98            None
99        } else {
100            Some(constant::BAD_MESSAGE_BAN_TIME)
101        }
102    }
103
104    /// Whether a warning log should be output.
105    pub fn should_warn(&self) -> bool {
106        let code = self.code as u16;
107        (500..600).contains(&code)
108    }
109
110    /// Returns the status code.
111    pub fn code(&self) -> StatusCode {
112        self.code
113    }
114}