1use crate::Server;
2use axum::{
3 extract::{
4 ws::{Message as WsMessage, WebSocket, WebSocketUpgrade},
5 State,
6 },
7 response::Response,
8};
9use futures::{SinkExt, StreamExt};
10use std::sync::Arc;
11use tracing::{debug, error, info, warn};
12
13pub async fn websocket_handler(
15 ws: WebSocketUpgrade,
16 State(server): State<Arc<Server>>,
17) -> Response {
18 ws.on_upgrade(move |socket| handle_socket(socket, server))
19}
20
21async fn handle_socket(socket: WebSocket, _server: Arc<Server>) {
22 let session_id = uuid::Uuid::new_v4().to_string();
23 info!("WebSocket connection established: {}", session_id);
24
25 let (mut sender, mut receiver) = socket.split();
26
27 while let Some(result) = receiver.next().await {
29 match result {
30 Ok(msg) => {
31 match msg {
32 WsMessage::Text(text) => {
33 debug!("Received text message: {}", text);
34
35 error!("WebSocket handler uses legacy Message format which is no longer supported");
39 error!("Only the official Cap'n Web wire protocol (newline-delimited arrays) is supported");
40
41 let error_msg = "WebSocket support requires wire protocol implementation";
43 if let Err(e) = sender
44 .send(WsMessage::Text(error_msg.to_string().into()))
45 .await
46 {
47 error!("Failed to send error response: {}", e);
48 break;
49 }
50 }
51 WsMessage::Binary(data) => {
52 warn!(
53 "Received binary message, Cap'n Web over WebSocket expects text/JSON"
54 );
55 if let Ok(text) = String::from_utf8(data.to_vec()) {
57 debug!("Converted binary to text: {}", text);
58 continue;
60 } else {
61 error!("Binary message is not valid UTF-8");
62 }
63 }
64 WsMessage::Ping(_) => {
65 debug!("Received ping, WebSocket will auto-respond with pong");
66 }
67 WsMessage::Pong(_) => {
68 debug!("Received pong");
69 }
70 WsMessage::Close(frame) => {
71 info!("WebSocket closing: {} (reason: {:?})", session_id, frame);
72 break;
73 }
74 }
75 }
76 Err(e) => {
77 error!("WebSocket error: {}", e);
78 break;
79 }
80 }
81 }
82
83 info!("WebSocket disconnected: {}", session_id);
87}