use crate::{WebResult, Buf, http::http2::frame::{Kind, Flag}, Http2Error, Serialize, BufMut, MarkBuf};
use super::{FrameHeader, Frame, StreamIdentifier};
pub type Payload = [u8; 8];
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Ping {
ack: bool,
payload: Payload,
}
const SHUTDOWN_PAYLOAD: Payload = [0x0b, 0x7b, 0xa2, 0xf0, 0x8b, 0x9b, 0xfe, 0x54];
const USER_PAYLOAD: Payload = [0x3b, 0x7c, 0xdb, 0x7a, 0x0b, 0x87, 0x16, 0xb4];
impl Ping {
pub(crate) const SHUTDOWN: Payload = SHUTDOWN_PAYLOAD;
pub(crate) const USER: Payload = USER_PAYLOAD;
pub fn new(payload: Payload) -> Ping {
Ping {
ack: false,
payload,
}
}
pub fn pong(payload: Payload) -> Ping {
Ping { ack: true, payload }
}
pub fn ret_pong(&self) -> Ping {
Ping { ack: true, payload: self.payload }
}
pub fn is_ack(&self) -> bool {
self.ack
}
pub fn payload(&self) -> &Payload {
&self.payload
}
pub fn into_payload(self) -> Payload {
self.payload
}
pub fn parse<B: Buf>(head: FrameHeader, bytes: &mut B) -> WebResult<Ping> {
debug_assert_eq!(head.kind(), &Kind::Ping);
if !head.stream_id().is_zero() {
return Err(Http2Error::InvalidStreamId.into());
}
if bytes.remaining() != 8 {
return Err(Http2Error::BadFrameSize.into());
}
let mut payload = [0; 8];
bytes.copy_to_slice(&mut payload);
let ack = head.flag().contains(Flag::ack());
Ok(Ping { ack, payload })
}
pub(crate) fn head(&self) -> FrameHeader {
let flags = if self.ack { Flag::ack() } else { Flag::zero() };
let mut head = FrameHeader::new(Kind::Ping, flags.into(), StreamIdentifier::zero());
head.length = self.payload.len() as u32;
head
}
pub fn encode<B: Buf+MarkBuf+BufMut>(&self, dst: &mut B) -> WebResult<usize> {
let head = self.head();
println!("encoding Ping; len={}", head.length);
let mut size = 0;
size += head.encode(dst)?;
size += dst.put_slice(&self.payload);
Ok(size)
}
}
impl Serialize for Ping {
fn serialize<B: Buf+BufMut+MarkBuf>(&mut self, buffer: &mut B) -> crate::WebResult<usize> {
let mut size = 0;
size += self.head().encode(buffer)?;
size += buffer.put_slice(&self.payload);
Ok(size)
}
}
impl<T> From<Ping> for Frame<T> {
fn from(src: Ping) -> Frame<T> {
Frame::Ping(src)
}
}