use
{
crate :: { import::*, WsErr, WsErrKind, Connections } ,
futures_01::stream::Stream as _,
futures_01::sink ::Sink as _,
};
type AsyncTokioResult = Result< Async<()> , tokio::io::Error >;
#[derive(Debug, Clone)]
enum ReadState
{
Ready { chunk: Message, chunk_start: usize },
PendingChunk,
Eof,
}
pub struct WsStream<S: AsyncRead01 + AsyncWrite01>
{
stream : SplitStream < WebSocketStream<S> >,
sink : SplitSink < WebSocketStream<S> >,
state : ReadState ,
}
impl WsStream<TcpStream>
{
pub fn listen< T: AsRef<str> >( url: T ) -> Connections
{
let addr = url.as_ref().parse().unwrap();
let socket = TcpListener::bind( &addr ).unwrap();
info!( "Listening on: {}", addr );
Connections::new( socket.incoming().compat() )
}
pub async fn connect< T: AsRef<str> >( url: T ) -> Result< Self, WsErr >
{
let addr = url.as_ref().parse().expect( "parse socketaddress" );
let socket = TcpStream::connect( &addr ).compat().await;
info!( "Connecting to: {}", addr );
let url = "ws://".to_string() + url.as_ref() + "/";
match socket
{
Ok(tcpstream) =>
{
match ok(()).and_then( |_| { client_async( Url::parse( &url ).expect( "parse url" ), tcpstream ) } ).compat().await
{
Ok (ws) => Ok( Self::new( ws.0 ) ),
Err(e ) =>
{
error!( "{}", &e );
Err( WsErrKind::WsHandshake.into() )
},
}
}
Err(_) => Err( WsErrKind::TcpConnection.into() ),
}
}
}
impl<S: AsyncRead01 + AsyncWrite01> WsStream<S>
{
pub fn new( ws: WebSocketStream<S> ) -> Self
{
let (sink, stream) = ws.split();
Self{ stream, sink, state: ReadState::PendingChunk }
}
fn io_read( &mut self, buf: &mut [u8] ) -> io::Result< usize >
{
trace!( "WsStream: read called" );
loop
{
let state = self.state.clone();
match state
{
ReadState::Ready { chunk, mut chunk_start } =>
{
trace!( "io_read: received message" );
let chunk: Vec<u8> = ( chunk ).into();
let len = cmp::min( buf.len(), chunk.len() - chunk_start );
buf[..len].copy_from_slice( &chunk[chunk_start..chunk_start + len] );
chunk_start += len;
if chunk.len() == chunk_start
{
self.state = ReadState::PendingChunk;
}
else
{
self.state = ReadState::Ready{ chunk: Message::Binary( chunk ), chunk_start }
}
return Ok( len );
}
ReadState::PendingChunk =>
{
trace!( "io_read: pending" );
match self.stream.poll()
{
Ok( Async::Ready( Some( chunk ) ) ) =>
{
self.state = ReadState::Ready { chunk, chunk_start: 0 };
continue;
}
Ok( Async::Ready( None ) ) =>
{
trace!( "io_read: stream has ended" );
return Ok( 0 );
}
Ok( Async::NotReady ) =>
{
trace!( "io_read: stream would_block" );
return Err( io::Error::from( WouldBlock ) );
}
Err(err) =>
{
error!( "{}", err );
self.state = ReadState::Eof;
match err
{
tungstenite::error::Error::Io(e) => { return Err( e ) }
_ => { return Ok(0) }
}
}
}
}
ReadState::Eof => { trace!( "io_read: EOF" ); return Ok(0); }
}
}
}
fn io_write( &mut self, buf: &[u8] ) -> io::Result< usize >
{
trace!( "WsStream: io_write called" );
let len = buf.len();
match self.sink.start_send( Message::binary( buf ) )
{
Ok( AsyncSink::Ready ) =>
{
match self.io_flush()
{
Ok ( () ) => return Ok (len),
Err( e ) => { error!( "{}", e ); return Err( e ) },
}
}
Ok( AsyncSink::NotReady(_) ) => { trace!( "io_write: would block" ); return Err( io::Error::from( WouldBlock ) ) }
Err(e) => { error!( "{}", e ); return Err( io::Error::from( io::ErrorKind::Other ) ) }
}
}
fn io_flush( &mut self ) -> io::Result<()>
{
trace!( "flush AsyncWrite" );
match self.sink.poll_complete()
{
Ok ( Async::Ready(_) ) => { return Ok ( () ) }
Ok ( Async::NotReady ) => { trace!( "io_flush: would block" ); return Err( io::Error::from( WouldBlock ) ) }
Err(e) => { error!( "{}", e ); return Err( io::Error::from( io::ErrorKind::Other ) ) }
}
}
fn async_shutdown( &mut self ) -> AsyncTokioResult
{
trace!( "Closing AsyncWrite" );
self.sink.close().expect( "close ws socket" );
Ok(().into())
}
}
impl<S: AsyncRead01 + AsyncWrite01> Drop for WsStream<S>
{
fn drop( &mut self )
{
trace!( "Drop WsStream" );
self.sink.close().expect( "close ws socket" );
}
}
impl<S: AsyncRead01 + AsyncWrite01> io::Read for WsStream<S>
{
fn read( &mut self, buf: &mut [u8] ) -> Result< usize, io::Error >
{
self.io_read( buf )
}
}
impl<S: AsyncRead01 + AsyncWrite01> io::Read for Pin< &mut WsStream<S> >
{
fn read( &mut self, buf: &mut [u8] ) -> Result< usize, io::Error >
{
self.io_read( buf )
}
}
impl<S: AsyncRead01 + AsyncWrite01> io::Write for WsStream<S>
{
fn write( &mut self, buf: &[u8] ) -> io::Result< usize > { self.io_write( buf ) }
fn flush( &mut self ) -> io::Result< () > { self.io_flush( ) }
}
impl<S: AsyncRead01 + AsyncWrite01> io::Write for Pin< &mut WsStream<S> >
{
fn write( &mut self, buf: &[u8] ) -> io::Result< usize > { self.io_write( buf ) }
fn flush( &mut self ) -> io::Result< () > { self.io_flush( ) }
}
impl<S: AsyncRead01 + AsyncWrite01> AsyncRead01 for WsStream<S> {}
impl<S: AsyncRead01 + AsyncWrite01> AsyncRead01 for Pin< &mut WsStream<S> > {}
impl<S: AsyncRead01 + AsyncWrite01> AsyncWrite01 for WsStream<S>
{
fn shutdown( &mut self ) -> AsyncTokioResult
{
self.async_shutdown()
}
}
impl<S: AsyncRead01 + AsyncWrite01> AsyncWrite01 for Pin< &mut WsStream<S> >
{
fn shutdown( &mut self ) -> AsyncTokioResult
{
self.async_shutdown()
}
}
impl<S: AsyncRead01 + AsyncWrite01> AsyncRead for WsStream<S>
{
fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8] ) -> Poll<Result<usize, io::Error>>
{
Pin::new( &mut AsyncRead01CompatExt::compat( self ) ).poll_read( cx, buf )
}
}
impl<S: AsyncRead01 + AsyncWrite01> AsyncWrite for WsStream<S>
{
fn poll_write( self: Pin<&mut Self>, cx: &mut Context, buf: &[u8] ) -> Poll<Result<usize, io::Error>>
{
Pin::new( &mut AsyncWrite01CompatExt::compat( self ) ).poll_write( cx, buf )
}
fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Result<(), io::Error>>
{
match self.io_flush()
{
Ok (()) => { Poll::Ready( Ok(()) ) }
Err( e ) =>
{
match e.kind()
{
io::ErrorKind::WouldBlock => Poll::Pending,
_ => { error!( "{}", &e ); Poll::Ready( Err(e) ) }
}
}
}
}
fn poll_close( mut self: Pin<&mut Self>, _cx: &mut Context ) -> Poll<Result<(), io::Error>>
{
self.async_shutdown().expect( "shutdown sink for wsstream" );
Poll::Ready( Ok(()) )
}
}