1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00
actix-extras/src/ws/codec.rs
2018-10-23 21:44:20 -07:00

149 lines
4.5 KiB
Rust

use bytes::BytesMut;
use tokio_codec::{Decoder, Encoder};
use super::frame::Parser;
use super::proto::{CloseReason, OpCode};
use super::ProtocolError;
use body::Binary;
/// `WebSocket` Message
#[derive(Debug, PartialEq)]
pub enum Message {
/// Text message
Text(String),
/// Binary message
Binary(Binary),
/// Ping message
Ping(String),
/// Pong message
Pong(String),
/// Close message with optional reason
Close(Option<CloseReason>),
}
/// `WebSocket` frame
#[derive(Debug, PartialEq)]
pub enum Frame {
/// Text frame, codec does not verify utf8 encoding
Text(Option<BytesMut>),
/// Binary frame
Binary(Option<BytesMut>),
/// Ping message
Ping(String),
/// Pong message
Pong(String),
/// Close message with optional reason
Close(Option<CloseReason>),
}
#[derive(Debug)]
/// WebSockets protocol codec
pub struct Codec {
max_size: usize,
server: bool,
}
impl Codec {
/// Create new websocket frames decoder
pub fn new() -> Codec {
Codec {
max_size: 65_536,
server: true,
}
}
/// Set max frame size
///
/// By default max size is set to 64kb
pub fn max_size(mut self, size: usize) -> Self {
self.max_size = size;
self
}
/// Set decoder to client mode.
///
/// By default decoder works in server mode.
pub fn client_mode(mut self) -> Self {
self.server = false;
self
}
}
impl Encoder for Codec {
type Item = Message;
type Error = ProtocolError;
fn encode(&mut self, item: Message, dst: &mut BytesMut) -> Result<(), Self::Error> {
match item {
Message::Text(txt) => {
Parser::write_message(dst, txt, OpCode::Text, true, !self.server)
}
Message::Binary(bin) => {
Parser::write_message(dst, bin, OpCode::Binary, true, !self.server)
}
Message::Ping(txt) => {
Parser::write_message(dst, txt, OpCode::Ping, true, !self.server)
}
Message::Pong(txt) => {
Parser::write_message(dst, txt, OpCode::Pong, true, !self.server)
}
Message::Close(reason) => Parser::write_close(dst, reason, !self.server),
}
Ok(())
}
}
impl Decoder for Codec {
type Item = Frame;
type Error = ProtocolError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
match Parser::parse(src, self.server, self.max_size) {
Ok(Some((finished, opcode, payload))) => {
// continuation is not supported
if !finished {
return Err(ProtocolError::NoContinuation);
}
match opcode {
OpCode::Continue => Err(ProtocolError::NoContinuation),
OpCode::Bad => Err(ProtocolError::BadOpCode),
OpCode::Close => {
if let Some(ref pl) = payload {
let close_reason = Parser::parse_close_payload(pl);
Ok(Some(Frame::Close(close_reason)))
} else {
Ok(Some(Frame::Close(None)))
}
}
OpCode::Ping => {
if let Some(ref pl) = payload {
Ok(Some(Frame::Ping(String::from_utf8_lossy(pl).into())))
} else {
Ok(Some(Frame::Ping(String::new())))
}
}
OpCode::Pong => {
if let Some(ref pl) = payload {
Ok(Some(Frame::Pong(String::from_utf8_lossy(pl).into())))
} else {
Ok(Some(Frame::Pong(String::new())))
}
}
OpCode::Binary => Ok(Some(Frame::Binary(payload))),
OpCode::Text => {
Ok(Some(Frame::Text(payload)))
//let tmp = Vec::from(payload.as_ref());
//match String::from_utf8(tmp) {
// Ok(s) => Ok(Some(Message::Text(s))),
// Err(_) => Err(ProtocolError::BadEncoding),
//}
}
}
}
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
}