1use std::{
4 fmt,
5 future::Future,
6 pin::Pin,
7 task::{Context, Poll},
8};
9
10use futures_util::FutureExt;
11
12#[derive(Debug, Clone)]
14pub struct ClosedReason {
15 pub code: CloseCode,
17 pub reason: String,
20 pub was_clean: bool,
22}
23
24impl fmt::Display for ClosedReason {
25 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
26 if self.reason.is_empty() {
27 write!(f, "{}", self.code)
28 } else {
29 write!(f, "{} ({})", &self.reason, self.code)
30 }
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[repr(u16)]
37pub enum CloseCode {
38 NormalClosure = 1000,
40 GoingAway = 1001,
42 ProtocolError = 1002,
44 UnsupportedData = 1003,
46 NoStatusRcvd = 1005,
48 AbnormalClosure = 1006,
50 InvalidFramePayloadData = 1007,
52 PolicyViolation = 1008,
54 MessageTooBig = 1009,
56 MandatoryExt = 1010,
58 InternalError = 1011,
60 ServiceRestart = 1012,
62 TryAgainLater = 1013,
64 BadGateway = 1014,
66 TlsHandshake = 1015,
68 Other(u16),
70}
71
72impl fmt::Display for CloseCode {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 match self {
75 CloseCode::NormalClosure => write!(f, "normal closure"),
76 CloseCode::GoingAway => write!(f, "going away"),
77 CloseCode::ProtocolError => write!(f, "protocol error"),
78 CloseCode::UnsupportedData => write!(f, "unsupported data"),
79 CloseCode::NoStatusRcvd => write!(f, "no status rcvd"),
80 CloseCode::AbnormalClosure => write!(f, "abnormal closure"),
81 CloseCode::InvalidFramePayloadData => write!(f, "invalid frame payload data"),
82 CloseCode::PolicyViolation => write!(f, "policy violation"),
83 CloseCode::MessageTooBig => write!(f, "message too big"),
84 CloseCode::MandatoryExt => write!(f, "mandatory ext"),
85 CloseCode::InternalError => write!(f, "internal error"),
86 CloseCode::ServiceRestart => write!(f, "service restart"),
87 CloseCode::TryAgainLater => write!(f, "try again later"),
88 CloseCode::BadGateway => write!(f, "bad gateway"),
89 CloseCode::TlsHandshake => write!(f, "TLS handshake"),
90 CloseCode::Other(code) => write!(f, "{code}"),
91 }
92 }
93}
94
95impl From<CloseCode> for u16 {
96 fn from(code: CloseCode) -> Self {
97 match code {
98 CloseCode::NormalClosure => 1000,
99 CloseCode::GoingAway => 1001,
100 CloseCode::ProtocolError => 1002,
101 CloseCode::UnsupportedData => 1003,
102 CloseCode::NoStatusRcvd => 1005,
103 CloseCode::AbnormalClosure => 1006,
104 CloseCode::InvalidFramePayloadData => 1007,
105 CloseCode::PolicyViolation => 1008,
106 CloseCode::MessageTooBig => 1009,
107 CloseCode::MandatoryExt => 1010,
108 CloseCode::InternalError => 1011,
109 CloseCode::ServiceRestart => 1012,
110 CloseCode::TryAgainLater => 1013,
111 CloseCode::BadGateway => 1014,
112 CloseCode::TlsHandshake => 1015,
113 CloseCode::Other(code) => code,
114 }
115 }
116}
117
118impl From<u16> for CloseCode {
119 fn from(value: u16) -> Self {
120 match value {
121 1000 => CloseCode::NormalClosure,
122 1001 => CloseCode::GoingAway,
123 1002 => CloseCode::ProtocolError,
124 1003 => CloseCode::UnsupportedData,
125 1005 => CloseCode::NoStatusRcvd,
126 1006 => CloseCode::AbnormalClosure,
127 1007 => CloseCode::InvalidFramePayloadData,
128 1008 => CloseCode::PolicyViolation,
129 1009 => CloseCode::MessageTooBig,
130 1010 => CloseCode::MandatoryExt,
131 1011 => CloseCode::InternalError,
132 1012 => CloseCode::ServiceRestart,
133 1013 => CloseCode::TryAgainLater,
134 1014 => CloseCode::BadGateway,
135 1015 => CloseCode::TlsHandshake,
136 other => CloseCode::Other(other),
137 }
138 }
139}
140
141impl CloseCode {
142 pub fn is_valid(&self) -> bool {
148 match self {
149 Self::NormalClosure => true,
150 Self::Other(other) if 3000 <= *other && *other < 5000 => true,
151 _ => false,
152 }
153 }
154}
155
156pub struct Closed(pub(crate) Pin<Box<dyn Future<Output = ClosedReason>>>);
158
159impl fmt::Debug for Closed {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 f.debug_tuple("Closed").finish()
162 }
163}
164
165impl Future for Closed {
166 type Output = ClosedReason;
167 fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
168 self.0.poll_unpin(cx)
169 }
170}