use std::io;
use crate::frame::Frame;
use crate::{error, frame, stream::StreamRef};
#[derive(Debug)]
pub enum Control<E> {
Disconnect(Reason<E>),
Terminated(Terminated),
}
#[derive(Debug)]
pub enum Reason<E> {
Error(Error<E>),
ProtocolError(ConnectionError),
GoAway(GoAway),
PeerGone(PeerGone),
}
#[derive(Clone, Debug)]
pub struct ControlAck {
pub(crate) frame: Option<Frame>,
}
impl<E> Control<E> {
pub(super) fn error(err: E, stream: Option<&StreamRef>) -> Self {
Control::Disconnect(Reason::Error(Error::new(err, stream)))
}
pub(super) fn go_away(frm: frame::GoAway) -> Self {
Control::Disconnect(Reason::GoAway(GoAway(frm)))
}
pub(super) fn peer_gone(err: Option<io::Error>) -> Self {
Control::Disconnect(Reason::PeerGone(PeerGone(err)))
}
pub(super) fn proto_error(err: ntex_error::Error<error::ConnectionError>) -> Self {
Control::Disconnect(Reason::ProtocolError(ConnectionError::new(err)))
}
pub(super) fn terminated() -> Self {
Control::Terminated(Terminated)
}
pub fn ack(self) -> ControlAck {
match self {
Control::Disconnect(item) => item.ack(),
Control::Terminated(item) => item.ack(),
}
}
}
impl<E> Reason<E> {
pub fn ack(self) -> ControlAck {
match self {
Reason::Error(item) => item.ack(),
Reason::ProtocolError(item) => item.ack(),
Reason::GoAway(item) => item.ack(),
Reason::PeerGone(item) => item.ack(),
}
}
}
#[derive(Debug)]
pub struct Error<E> {
err: E,
goaway: frame::GoAway,
}
impl<E> Error<E> {
fn new(err: E, stream: Option<&StreamRef>) -> Self {
let goaway = if let Some(stream) = stream {
frame::GoAway::new(frame::Reason::INTERNAL_ERROR).set_last_stream_id(stream.id())
} else {
frame::GoAway::new(frame::Reason::INTERNAL_ERROR)
};
Self { err, goaway }
}
#[inline]
pub fn get_ref(&self) -> &E {
&self.err
}
#[inline]
#[must_use]
pub fn reason(mut self, reason: frame::Reason) -> Self {
self.goaway = self.goaway.set_reason(reason);
self
}
#[inline]
pub fn ack(self) -> ControlAck {
ControlAck {
frame: Some(self.goaway.into()),
}
}
}
#[derive(Debug)]
pub struct Terminated;
impl Terminated {
#[inline]
pub fn ack(self) -> ControlAck {
ControlAck { frame: None }
}
}
#[derive(Debug)]
pub struct ConnectionError {
err: ntex_error::Error<error::ConnectionError>,
frm: frame::GoAway,
}
impl ConnectionError {
pub fn new(err: ntex_error::Error<error::ConnectionError>) -> Self {
Self {
frm: err.to_goaway(),
err,
}
}
#[inline]
pub fn get_ref(&self) -> &ntex_error::Error<error::ConnectionError> {
&self.err
}
#[inline]
#[must_use]
pub fn reason(mut self, reason: frame::Reason) -> Self {
self.frm = self.frm.set_reason(reason);
self
}
#[inline]
pub fn ack(self) -> ControlAck {
ControlAck {
frame: Some(self.frm.into()),
}
}
}
#[derive(Debug)]
pub struct PeerGone(pub(super) Option<io::Error>);
impl PeerGone {
pub fn err(&self) -> Option<&io::Error> {
self.0.as_ref()
}
pub fn take(&mut self) -> Option<io::Error> {
self.0.take()
}
pub fn ack(self) -> ControlAck {
ControlAck { frame: None }
}
}
#[derive(Debug)]
pub struct GoAway(frame::GoAway);
impl GoAway {
pub fn frame(&self) -> &frame::GoAway {
&self.0
}
pub fn ack(self) -> ControlAck {
ControlAck { frame: None }
}
}