use actix::prelude::*; use actix_web_actors::ws; use log::debug; use serde_json::Value; use crate::{Server, JsonRpcRequest, JsonRpcResponse, JsonRpcError}; impl actix::StreamHandler> for Server { fn handle(&mut self, msg: Result, ctx: &mut Self::Context) { match msg { Ok(ws::Message::Text(text)) => { debug!("WS Text for {}: {}", self.circle_name, text); // Handle plaintext ping messages for keep-alive if text.trim() == "ping" { debug!("Received keep-alive ping from {}, responding with pong", self.circle_name); ctx.text("pong"); return; } match serde_json::from_str::(&text) { Ok(req) => { let client_rpc_id = req.id.clone().unwrap_or(Value::Null); match req.method.as_str() { "fetch_nonce" => { self.handle_fetch_nonce(req.params, client_rpc_id, ctx) } "authenticate" => { self.handle_authenticate(req.params, client_rpc_id, ctx) } "whoami" => { self.handle_whoami(req.params, client_rpc_id, ctx) } "play" => self.handle_play(req.params, client_rpc_id, ctx), _ => { let err_resp = JsonRpcResponse { jsonrpc: "2.0".to_string(), result: None, error: Some(JsonRpcError { code: -32601, message: format!("Method not found: {}", req.method), data: None, }), id: client_rpc_id, }; ctx.text(serde_json::to_string(&err_resp).unwrap()); } } } Err(e) => { log::error!( "WS Error: Failed to parse JSON: {}, original text: '{}'", e, text ); let err_resp = JsonRpcResponse { jsonrpc: "2.0".to_string(), result: None, error: Some(JsonRpcError { code: -32700, message: "Failed to parse JSON request".to_string(), data: Some(Value::String(text.to_string())), }), id: Value::Null, }; ctx.text(serde_json::to_string(&err_resp).unwrap()); } } } Ok(ws::Message::Ping(msg)) => ctx.pong(&msg), Ok(ws::Message::Close(reason)) => { log::info!( "WebSocket connection closing for server {}: {:?}", self.circle_name, reason ); ctx.close(reason); ctx.stop(); } Err(e) => { log::error!( "WebSocket error for server {}: {}", self.circle_name, e ); ctx.stop(); } _ => (), } } }