diff --git a/docs/websockets.md b/docs/websockets.md index f70368e..fd9de89 100644 --- a/docs/websockets.md +++ b/docs/websockets.md @@ -1,22 +1,22 @@ --- -title: Websockets +title: WebSockets --- import CodeBlock from "@site/src/components/code_block"; -# Websockets +# WebSockets -Actix Web supports WebSockets with the `actix-web-actors` crate. It is possible to convert a request's `Payload` to a stream of [_ws::Message_][message] with a [_web::Payload_][payload] and then use stream combinators to handle actual messages, but it is simpler to handle websocket communications with an http actor. +Actix Web supports a high-level WebSocket interface via the `actix-ws` crate. Using this crate, it's possible to convert a request's `Payload` stream into a stream of [_ws::Message_][message]s and then react to them inside a spawned async task. -The following is an example of a simple websocket echo server: +The following is an example of a simple WebSocket echo server: -> A simple websocket echo server example is available in the [examples directory][examples]. +> A simple WebSocket echo server example is available [in the examples repo][echo]. -> An example chat server with the ability to chat over a websocket or TCP connection is available in [websocket-chat directory][chat] +> An example chat server is also available [in the examples directory][chat] -[message]: https://docs.rs/actix-web-actors/2/actix_web_actors/ws/enum.Message.html +[message]: https://docs.rs/actix-ws/0.3/actix_ws/enum.Message.html [payload]: https://docs.rs/actix-web/4/actix_web/web/struct.Payload.html -[examples]: https://github.com/actix/examples/tree/master/websockets -[chat]: https://github.com/actix/examples/tree/master/websockets/chat +[echo]: https://github.com/actix/examples/tree/master/websockets/echo-actorless +[chat]: https://github.com/actix/examples/tree/master/websockets/chat-actorless diff --git a/examples/Cargo.lock b/examples/Cargo.lock index bf39ddb..73a2b79 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -2,31 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" -dependencies = [ - "actix-macros", - "actix-rt", - "actix_derive", - "bitflags 2.5.0", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", -] - [[package]] name = "actix-codec" version = "0.5.2" @@ -260,24 +235,6 @@ dependencies = [ "url", ] -[[package]] -name = "actix-web-actors" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420b001bb709d8510c3e2659dae046e54509ff9528018d09c78381e765a1f9fa" -dependencies = [ - "actix", - "actix-codec", - "actix-http", - "actix-web", - "bytes", - "bytestring", - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - [[package]] name = "actix-web-codegen" version = "4.3.0" @@ -291,14 +248,17 @@ dependencies = [ ] [[package]] -name = "actix_derive" -version = "0.6.1" +name = "actix-ws" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +checksum = "a3a1fb4f9f2794b0aadaf2ba5f14a6f034c7e86957b458c506a8cb75953f2d99" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "actix-codec", + "actix-http", + "actix-web", + "bytestring", + "futures-core", + "tokio", ] [[package]] @@ -3344,9 +3304,9 @@ dependencies = [ name = "websockets" version = "1.0.0" dependencies = [ - "actix", "actix-web", - "actix-web-actors", + "actix-ws", + "futures-util", ] [[package]] diff --git a/examples/websockets/Cargo.toml b/examples/websockets/Cargo.toml index b6d88fa..82200f4 100644 --- a/examples/websockets/Cargo.toml +++ b/examples/websockets/Cargo.toml @@ -5,6 +5,6 @@ publish = false edition.workspace = true [dependencies] -actix = "0.13" actix-web = "4" -actix-web-actors = "4.0.0" +actix-ws = "0.3" +futures-util = { version = "0.3.17", default-features = false, features = ["std"] } diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs index 8a0bff9..228682c 100644 --- a/examples/websockets/src/main.rs +++ b/examples/websockets/src/main.rs @@ -1,36 +1,48 @@ // -use actix::{Actor, StreamHandler}; -use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; -use actix_web_actors::ws; +use actix_web::{rt, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_ws::AggregatedMessage; +use futures_util::StreamExt as _; -/// Define HTTP actor -struct MyWs; +async fn echo(req: HttpRequest, stream: web::Payload) -> Result { + let (res, mut session, stream) = actix_ws::handle(&req, stream)?; -impl Actor for MyWs { - type Context = ws::WebsocketContext; -} + let mut stream = stream + .aggregate_continuations() + // aggregate continuation frames up to 1MiB + .max_continuation_size(2_usize.pow(20)); -/// Handler for ws::Message message -impl StreamHandler> for MyWs { - fn handle(&mut self, msg: Result, ctx: &mut Self::Context) { - match msg { - Ok(ws::Message::Ping(msg)) => ctx.pong(&msg), - Ok(ws::Message::Text(text)) => ctx.text(text), - Ok(ws::Message::Binary(bin)) => ctx.binary(bin), - _ => (), + // start task but don't wait for it + rt::spawn(async move { + // receive messages from websocket + while let Some(msg) = stream.next().await { + match msg { + Ok(AggregatedMessage::Text(text)) => { + // echo text message + session.text(text).await.unwrap(); + } + + Ok(AggregatedMessage::Binary(bin)) => { + // echo binary message + session.binary(bin).await.unwrap(); + } + + Ok(AggregatedMessage::Ping(msg)) => { + // respond to PING frame with PONG frame + session.pong(&msg).await.unwrap(); + } + + _ => {} + } } - } -} + }); -async fn index(req: HttpRequest, stream: web::Payload) -> Result { - let resp = ws::start(MyWs {}, &req, stream); - println!("{:?}", resp); - resp + // respond immediately with response connected to WS session + Ok(res) } #[actix_web::main] async fn main() -> std::io::Result<()> { - HttpServer::new(|| App::new().route("/ws/", web::get().to(index))) + HttpServer::new(|| App::new().route("/echo", web::get().to(echo))) .bind(("127.0.0.1", 8080))? .run() .await