use crate::{ws::WsCodec, ProtResult};
use algorithm::buf::{Binary, Bt};
use std::{
pin::Pin,
task::{ready, Context, Poll},
};
use tokio::io::{AsyncRead, AsyncWrite};
pub struct WsStateHandshake {
state: WsHandshaking,
is_client: bool,
}
enum WsHandshaking {
Wait,
Flushing(Flush),
Done,
}
struct Flush(Binary);
impl WsStateHandshake {
pub fn new_server() -> WsStateHandshake {
WsStateHandshake {
state: WsHandshaking::Wait,
is_client: false,
}
}
pub fn poll_handle<T>(
&mut self,
cx: &mut Context<'_>,
codec: &mut WsCodec<T>,
) -> Poll<ProtResult<()>>
where
T: AsyncRead + AsyncWrite + Unpin,
{
loop {
match &mut self.state {
WsHandshaking::Wait => {
return Poll::Pending;
}
WsHandshaking::Flushing(flush) => {
match ready!(flush.poll_handle(cx, codec)) {
Ok(_) => {
tracing::trace!(flush.poll = %"Ready");
self.state = WsHandshaking::Done;
continue;
}
Err(e) => return Poll::Ready(Err(e)),
};
}
WsHandshaking::Done => {
return Poll::Ready(Ok(()));
}
}
}
}
pub fn set_handshake_status(&mut self, binary: Binary, is_client: bool) {
self.is_client = is_client;
if binary.is_empty() {
self.state = WsHandshaking::Done;
} else {
self.state = WsHandshaking::Flushing(Flush(binary));
}
}
}
impl Flush {
pub fn poll_handle<T>(
&mut self,
cx: &mut Context<'_>,
codec: &mut WsCodec<T>,
) -> Poll<ProtResult<()>>
where
T: AsyncRead + AsyncWrite + Unpin,
{
if !self.0.has_remaining() {
return Poll::Ready(Ok(()));
}
loop {
match ready!(Pin::new(codec.get_mut()).poll_write(cx, self.0.chunk())) {
Ok(n) => {
self.0.advance(n);
}
Err(e) => return Poll::Ready(Err(e.into())),
}
if !self.0.has_remaining() {
return Poll::Ready(Ok(()));
}
}
}
}
unsafe impl Send for WsStateHandshake {}
unsafe impl Sync for WsStateHandshake {}