1use std::fmt;
2
3use bytes::{BufMut, Bytes};
4
5use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
6
7#[derive(Clone, Eq, PartialEq)]
8pub struct GoAway {
9 last_stream_id: StreamId,
10 error_code: Reason,
11 debug_data: Bytes,
12}
13
14impl GoAway {
15 pub fn new(last_stream_id: StreamId, reason: Reason) -> Self {
16 GoAway {
17 last_stream_id,
18 error_code: reason,
19 debug_data: Bytes::new(),
20 }
21 }
22
23 pub fn with_debug_data(last_stream_id: StreamId, reason: Reason, debug_data: Bytes) -> Self {
24 Self {
25 last_stream_id,
26 error_code: reason,
27 debug_data,
28 }
29 }
30
31 pub fn last_stream_id(&self) -> StreamId {
32 self.last_stream_id
33 }
34
35 pub fn reason(&self) -> Reason {
36 self.error_code
37 }
38
39 pub fn debug_data(&self) -> &Bytes {
40 &self.debug_data
41 }
42
43 pub fn load(payload: &[u8]) -> Result<GoAway, Error> {
44 if payload.len() < 8 {
45 return Err(Error::BadFrameSize);
46 }
47
48 let (last_stream_id, _) = StreamId::parse(&payload[..4]);
49 let error_code = unpack_octets_4!(payload, 4, u32);
50 let debug_data = Bytes::copy_from_slice(&payload[8..]);
51
52 Ok(GoAway {
53 last_stream_id,
54 error_code: error_code.into(),
55 debug_data,
56 })
57 }
58
59 pub fn encode<B: BufMut>(&self, dst: &mut B) {
60 tracing::trace!("encoding GO_AWAY; code={:?}", self.error_code);
61 let head = Head::new(Kind::GoAway, 0, StreamId::zero());
62 head.encode(8 + self.debug_data.len(), dst);
63 dst.put_u32(self.last_stream_id.into());
64 dst.put_u32(self.error_code.into());
65 dst.put(self.debug_data.slice(..));
66 }
67}
68
69impl<B> From<GoAway> for frame::Frame<B> {
70 fn from(src: GoAway) -> Self {
71 frame::Frame::GoAway(src)
72 }
73}
74
75impl fmt::Debug for GoAway {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 let mut builder: DebugStruct<'_, '_> = f.debug_struct(name:"GoAway");
78 builder.field(name:"error_code", &self.error_code);
79 builder.field(name:"last_stream_id", &self.last_stream_id);
80
81 if !self.debug_data.is_empty() {
82 builder.field(name:"debug_data", &self.debug_data);
83 }
84
85 builder.finish()
86 }
87}
88