From a48e34adc708e6d376262919be57d37906ef4f11 Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Sun, 25 Jan 2026 20:54:56 +0800 Subject: [PATCH] enhanced websocket handling --- src-tauri/src/services/ws/client.rs | 105 ++---------------------- src-tauri/src/services/ws/connection.rs | 45 ++++++++++ src-tauri/src/services/ws/friend.rs | 35 +++----- src-tauri/src/services/ws/handlers.rs | 59 +++++++++++++ src-tauri/src/services/ws/mod.rs | 2 + 5 files changed, 125 insertions(+), 121 deletions(-) create mode 100644 src-tauri/src/services/ws/connection.rs create mode 100644 src-tauri/src/services/ws/handlers.rs diff --git a/src-tauri/src/services/ws/client.rs b/src-tauri/src/services/ws/client.rs index bc256bf..91deb09 100644 --- a/src-tauri/src/services/ws/client.rs +++ b/src-tauri/src/services/ws/client.rs @@ -1,52 +1,14 @@ -use rust_socketio::{ClientBuilder, Event, Payload, RawClient}; -use serde_json::json; +use rust_socketio::ClientBuilder; use tauri::async_runtime; use tracing::{error, info}; use crate::{ lock_r, lock_w, - services::{ - client_config_manager::AppConfig, health_manager::close_health_manager_window, - scene::open_scene_window, - }, + services::client_config_manager::AppConfig, state::FDOLL, }; -use super::WS_EVENT; - -fn emit_initialize(socket: &RawClient) { - if let Err(e) = socket.emit(WS_EVENT::CLIENT_INITIALIZE, json!({})) { - error!("Failed to emit client-initialize: {:?}", e); - } -} - -fn on_connected(_payload: Payload, socket: RawClient) { - info!("WebSocket connected. Sending initialization request."); - emit_initialize(&socket); -} - -fn on_initialized(payload: Payload, _socket: RawClient) { - match payload { - Payload::Text(values) => { - if let Some(first_value) = values.first() { - info!("Received initialized event: {:?}", first_value); - - // Mark WebSocket as initialized and reset backoff timer - let mut guard = lock_w!(FDOLL); - if let Some(clients) = guard.network.clients.as_mut() { - clients.is_ws_initialized = true; - } - - // Connection restored: close health manager and reopen scene - close_health_manager_window(); - open_scene_window(); - } else { - info!("Received initialized event with empty payload"); - } - } - _ => error!("Received unexpected payload format for initialized"), - } -} +use super::handlers; pub async fn init_ws_client() { let app_config = { @@ -89,62 +51,13 @@ pub async fn build_ws_client( .ok_or("Missing API base URL")?; let client_result = async_runtime::spawn_blocking(move || { - ClientBuilder::new(api_base_url) + let builder = ClientBuilder::new(api_base_url) .namespace("/") - .on( - WS_EVENT::FRIEND_REQUEST_RECEIVED, - super::friend::on_friend_request_received, - ) - .on( - WS_EVENT::FRIEND_REQUEST_ACCEPTED, - super::friend::on_friend_request_accepted, - ) - .on( - WS_EVENT::FRIEND_REQUEST_DENIED, - super::friend::on_friend_request_denied, - ) - .on(WS_EVENT::UNFRIENDED, super::friend::on_unfriended) - .on( - WS_EVENT::FRIEND_CURSOR_POSITION, - super::friend::on_friend_cursor_position, - ) - .on( - WS_EVENT::FRIEND_DISCONNECTED, - super::friend::on_friend_disconnected, - ) - .on( - WS_EVENT::FRIEND_DOLL_CREATED, - super::friend::on_friend_doll_created, - ) - .on( - WS_EVENT::FRIEND_DOLL_UPDATED, - super::friend::on_friend_doll_updated, - ) - .on( - WS_EVENT::FRIEND_DOLL_DELETED, - super::friend::on_friend_doll_deleted, - ) - .on( - WS_EVENT::FRIEND_ACTIVE_DOLL_CHANGED, - super::friend::on_friend_active_doll_changed, - ) - .on(WS_EVENT::DOLL_CREATED, super::doll::on_doll_created) - .on(WS_EVENT::DOLL_UPDATED, super::doll::on_doll_updated) - .on(WS_EVENT::DOLL_DELETED, super::doll::on_doll_deleted) - .on(WS_EVENT::INITIALIZED, on_initialized) - .on( - WS_EVENT::INTERACTION_RECEIVED, - super::interaction::on_interaction_received, - ) - .on( - WS_EVENT::INTERACTION_DELIVERY_FAILED, - super::interaction::on_interaction_delivery_failed, - ) - // rust-socketio fires Event::Connect on initial connect AND reconnects - // so we resend initialization there instead of a dedicated reconnect event. - .on(Event::Connect, on_connected) - .auth(json!({ "token": token })) - .connect() + .auth(serde_json::json!({ "token": token })); + + let builder_with_handlers = handlers::register_event_handlers(builder); + + builder_with_handlers.connect() }) .await; diff --git a/src-tauri/src/services/ws/connection.rs b/src-tauri/src/services/ws/connection.rs new file mode 100644 index 0000000..4ff315d --- /dev/null +++ b/src-tauri/src/services/ws/connection.rs @@ -0,0 +1,45 @@ +use rust_socketio::{Payload, RawClient}; +use tracing::info; + +use crate::{ + lock_w, + services::health_manager::close_health_manager_window, + services::scene::open_scene_window, + state::FDOLL, +}; + +use super::WS_EVENT; + +fn emit_initialize(socket: &RawClient) { + if let Err(e) = socket.emit(WS_EVENT::CLIENT_INITIALIZE, serde_json::json!({})) { + tracing::error!("Failed to emit client-initialize: {:?}", e); + } +} + +pub fn on_connected(_payload: Payload, socket: RawClient) { + info!("WebSocket connected. Sending initialization request."); + emit_initialize(&socket); +} + +pub fn on_initialized(payload: Payload, _socket: RawClient) { + match payload { + Payload::Text(values) => { + if let Some(first_value) = values.first() { + info!("Received initialized event: {:?}", first_value); + + // Mark WebSocket as initialized and reset backoff timer + let mut guard = lock_w!(FDOLL); + if let Some(clients) = guard.network.clients.as_mut() { + clients.is_ws_initialized = true; + } + + // Connection restored: close health manager and reopen scene + close_health_manager_window(); + open_scene_window(); + } else { + info!("Received initialized event with empty payload"); + } + } + _ => tracing::error!("Received unexpected payload format for initialized"), + } +} \ No newline at end of file diff --git a/src-tauri/src/services/ws/friend.rs b/src-tauri/src/services/ws/friend.rs index a367033..6dcf324 100644 --- a/src-tauri/src/services/ws/friend.rs +++ b/src-tauri/src/services/ws/friend.rs @@ -123,43 +123,28 @@ pub fn on_friend_disconnected(payload: Payload, _socket: RawClient) { } pub fn on_friend_doll_created(payload: Payload, _socket: RawClient) { - match payload { - Payload::Text(values) => { - // Log raw JSON for now, as requested - if let Some(first_value) = values.first() { - info!("Received friend-doll-created event: {:?}", first_value); - // Future: Trigger re-fetch or emit to frontend - } else { - info!("Received friend-doll-created event with empty payload"); - } - } - _ => error!("Received unexpected payload format for friend-doll-created"), - } + handle_friend_doll_change(WS_EVENT::FRIEND_DOLL_CREATED, payload); } pub fn on_friend_doll_updated(payload: Payload, _socket: RawClient) { - match payload { - Payload::Text(values) => { - if let Some(first_value) = values.first() { - info!("Received friend-doll-updated event: {:?}", first_value); - } else { - info!("Received friend-doll-updated event with empty payload"); - } - } - _ => error!("Received unexpected payload format for friend-doll-updated"), - } + handle_friend_doll_change(WS_EVENT::FRIEND_DOLL_UPDATED, payload); } pub fn on_friend_doll_deleted(payload: Payload, _socket: RawClient) { + handle_friend_doll_change(WS_EVENT::FRIEND_DOLL_DELETED, payload); +} + +fn handle_friend_doll_change(event_name: &str, payload: Payload) { match payload { Payload::Text(values) => { if let Some(first_value) = values.first() { - info!("Received friend-doll-deleted event: {:?}", first_value); + info!("Received {} event: {:?}", event_name, first_value); + // Future: Trigger re-fetch or emit to frontend } else { - info!("Received friend-doll-deleted event with empty payload"); + info!("Received {} event with empty payload", event_name); } } - _ => error!("Received unexpected payload format for friend-doll-deleted"), + _ => error!("Received unexpected payload format for {}", event_name), } } diff --git a/src-tauri/src/services/ws/handlers.rs b/src-tauri/src/services/ws/handlers.rs new file mode 100644 index 0000000..7454d0c --- /dev/null +++ b/src-tauri/src/services/ws/handlers.rs @@ -0,0 +1,59 @@ +use rust_socketio::{ClientBuilder, Event}; + +use crate::services::ws::WS_EVENT; + +pub fn register_event_handlers(builder: ClientBuilder) -> ClientBuilder { + builder + .on( + WS_EVENT::FRIEND_REQUEST_RECEIVED, + super::friend::on_friend_request_received, + ) + .on( + WS_EVENT::FRIEND_REQUEST_ACCEPTED, + super::friend::on_friend_request_accepted, + ) + .on( + WS_EVENT::FRIEND_REQUEST_DENIED, + super::friend::on_friend_request_denied, + ) + .on(WS_EVENT::UNFRIENDED, super::friend::on_unfriended) + .on( + WS_EVENT::FRIEND_CURSOR_POSITION, + super::friend::on_friend_cursor_position, + ) + .on( + WS_EVENT::FRIEND_DISCONNECTED, + super::friend::on_friend_disconnected, + ) + .on( + WS_EVENT::FRIEND_DOLL_CREATED, + super::friend::on_friend_doll_created, + ) + .on( + WS_EVENT::FRIEND_DOLL_UPDATED, + super::friend::on_friend_doll_updated, + ) + .on( + WS_EVENT::FRIEND_DOLL_DELETED, + super::friend::on_friend_doll_deleted, + ) + .on( + WS_EVENT::FRIEND_ACTIVE_DOLL_CHANGED, + super::friend::on_friend_active_doll_changed, + ) + .on(WS_EVENT::DOLL_CREATED, super::doll::on_doll_created) + .on(WS_EVENT::DOLL_UPDATED, super::doll::on_doll_updated) + .on(WS_EVENT::DOLL_DELETED, super::doll::on_doll_deleted) + .on(WS_EVENT::INITIALIZED, super::connection::on_initialized) + .on( + WS_EVENT::INTERACTION_RECEIVED, + super::interaction::on_interaction_received, + ) + .on( + WS_EVENT::INTERACTION_DELIVERY_FAILED, + super::interaction::on_interaction_delivery_failed, + ) + // rust-socketio fires Event::Connect on initial connect AND reconnects + // so we resend initialization there instead of a dedicated reconnect event. + .on(Event::Connect, super::connection::on_connected) +} \ No newline at end of file diff --git a/src-tauri/src/services/ws/mod.rs b/src-tauri/src/services/ws/mod.rs index 65eeac2..a3904bb 100644 --- a/src-tauri/src/services/ws/mod.rs +++ b/src-tauri/src/services/ws/mod.rs @@ -40,9 +40,11 @@ impl WS_EVENT { } mod client; +mod connection; mod cursor; mod doll; mod friend; +mod handlers; mod interaction; pub use client::init_ws_client;