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