diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 8e78a0c3e..d76840f9c 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -9,8 +9,8 @@ - [URL Dispatch](./qs_5.md) - [Request & Response](./qs_7.md) - [Testing](./qs_8.md) -- [WebSockets](./qs_9.md) - [Middlewares](./qs_10.md) - [Static file handling](./qs_12.md) +- [WebSockets](./qs_9.md) - [HTTP/2](./qs_13.md) - [Database integration](./qs_14.md) diff --git a/guide/src/qs_9.md b/guide/src/qs_9.md index cde41c746..4f0b38cc8 100644 --- a/guide/src/qs_9.md +++ b/guide/src/qs_9.md @@ -1,4 +1,49 @@ # WebSockets -[WIP] +Actix supports WebSockets out-of-the-box. It is possible to convert request's `Payload` +to a stream of [*ws::Message*](../actix_web/ws/enum.Message.html) with +a [*ws::WsStream*](../actix_web/ws/struct.WsStream.html) and then use stream +combinators to handle actual messages. But it is simplier to handle websocket communication +with http actor. +```rust +extern crate actix; +extern crate actix_web; + +use actix::*; +use actix_web::*; + +/// Define http actor +struct Ws; + +impl Actor for Ws { + type Context = HttpContext; +} + +/// Define Handler for ws::Message message +# impl StreamHandler for WsRoute {} +impl Handler for WsRoute { + fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext) -> Response + { + match msg { + ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg), + ws::Message::Text(text) => ws::WsWriter::text(ctx, &text), + ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin), + _ => (), + } + Self::empty() + } +} + +fn main() { + Application::new() + .resource("/ws/", |r| r.f(|req| ws::start(req, WS)) // <- register websocket route + .finish(); +} +``` + +Simple websocket echo server example is available in +[examples directory](https://github.com/actix/actix-web/blob/master/examples/websocket.rs). + +Example chat server with ability to chat over websocket connection or tcp connection +is available in [websocket-chat directory](https://github.com/actix/actix-web/tree/master/examples/websocket-chat/) diff --git a/src/test.rs b/src/test.rs index dc834a59e..333f216b9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -11,6 +11,7 @@ use cookie::Cookie; use http::{Uri, Method, Version, HeaderMap, HttpTryFrom}; use http::header::{HeaderName, HeaderValue}; use futures::Future; +use socket2::{Socket, Domain, Type}; use tokio_core::net::TcpListener; use tokio_core::reactor::Core; @@ -137,7 +138,11 @@ impl TestServer { /// Get firat available unused address pub fn unused_addr() -> net::SocketAddr { - let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap(); + let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket.bind(&addr.into()).unwrap(); + socket.set_reuse_address(true).unwrap(); + let tcp = socket.into_tcp_listener(); tcp.local_addr().unwrap() } diff --git a/src/ws.rs b/src/ws.rs index 097ec7997..5832e5c29 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -6,28 +6,26 @@ //! ## Example //! //! ```rust -//! extern crate actix; -//! extern crate actix_web; -//! +//! # extern crate actix; +//! # extern crate actix_web; //! use actix::*; //! use actix_web::*; //! //! // do websocket handshake and start actor //! fn ws_index(req: HttpRequest) -> Result { -//! ws::start(req, WsRoute) +//! ws::start(req, Ws) //! } //! -//! // WebSocket Route -//! struct WsRoute; +//! struct Ws; //! -//! impl Actor for WsRoute { +//! impl Actor for Ws { //! type Context = HttpContext; //! } //! //! // Define Handler for ws::Message message -//! impl StreamHandler for WsRoute {} -//! -//! impl Handler for WsRoute { +//! # impl StreamHandler for Ws {} +//! # +//! impl Handler for Ws { //! fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext) //! -> Response //! { @@ -40,12 +38,12 @@ //! Self::empty() //! } //! } -//! -//! fn main() { -//! Application::new() -//! .resource("/ws/", |r| r.method(Method::GET).f(ws_index)) // <- register websocket route -//! .finish(); -//! } +//! # +//! # fn main() { +//! # Application::new() +//! # .resource("/ws/", |r| r.f(ws_index)) // <- register websocket route +//! # .finish(); +//! # } //! ``` use std::vec::Vec; use http::{Method, StatusCode, header};