MCPcopy Create free account
hub / github.com/actix/examples / broadcast_ws

Function broadcast_ws

websockets/echo-actorless/src/handler.rs:162–264  ·  view source on GitHub ↗

Broadcast text & binary messages received from a client, respond to ping messages, and monitor connection health to detect network issues and free up resources.

(
    mut session: actix_ws::Session,
    mut msg_stream: actix_ws::MessageStream,
    mut rx: broadcast::Receiver<web::Bytes>,
)

Source from the content-addressed store, hash-verified

160/// Broadcast text & binary messages received from a client, respond to ping messages, and monitor
161/// connection health to detect network issues and free up resources.
162pub async fn broadcast_ws(
163 mut session: actix_ws::Session,
164 mut msg_stream: actix_ws::MessageStream,
165 mut rx: broadcast::Receiver<web::Bytes>,
166) {
167 log::info!("connected");
168
169 let mut last_heartbeat = Instant::now();
170 let mut interval = interval(HEARTBEAT_INTERVAL);
171
172 let reason = loop {
173 // waits for either `msg_stream` to receive a message from the client, the broadcast channel
174 // to send a message, or the heartbeat interval timer to tick, yielding the value of
175 // whichever one is ready first
176 select! {
177 broadcast_msg = rx.recv() => {
178 let msg = match broadcast_msg {
179 Ok(msg) => msg,
180 Err(broadcast::error::RecvError::Closed) => break None,
181 Err(broadcast::error::RecvError::Lagged(_)) => continue,
182 };
183
184 let res = match std::str::from_utf8(&msg) {
185 Ok(val) => session.text(val).await,
186 Err(_) => session.binary(msg).await,
187 };
188
189 if let Err(err) = res {
190 log::error!("{err}");
191 break None;
192 }
193 }
194
195 // heartbeat interval ticked
196 _tick = interval.tick() => {
197 // if no heartbeat ping/pong received recently, close the connection
198 if Instant::now().duration_since(last_heartbeat) > CLIENT_TIMEOUT {
199 log::info!(
200 "client has not sent heartbeat in over {CLIENT_TIMEOUT:?}; disconnecting"
201 );
202
203 break None;
204 }
205
206 // send heartbeat ping
207 let _ = session.ping(b"").await;
208 },
209
210 msg = msg_stream.next() => {
211 let msg = match msg {
212 // received message from WebSocket client
213 Some(Ok(msg)) => msg,
214
215 // client WebSocket stream error
216 Some(Err(err)) => {
217 log::error!("{err}");
218 break None;
219 }

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected