From 86d964943e7cdedbc94a534a408b7f57cd148d08 Mon Sep 17 00:00:00 2001 From: Wind-Explorer Date: Thu, 15 Jan 2026 16:17:06 +0800 Subject: [PATCH] chore: refactored lib.rs to move commands into separate folder --- src-tauri/src/app.rs | 3 +- src-tauri/src/commands/app.rs | 14 ++ src-tauri/src/commands/app_data.rs | 18 ++ src-tauri/src/commands/auth.rs | 25 ++ src-tauri/src/commands/config.rs | 31 +++ src-tauri/src/commands/dolls.rs | 135 +++++++++++ src-tauri/src/commands/friends.rs | 78 ++++++ src-tauri/src/commands/interaction.rs | 9 + src-tauri/src/commands/mod.rs | 8 + src-tauri/src/commands/sprite.rs | 15 ++ src-tauri/src/lib.rs | 331 ++------------------------ 11 files changed, 352 insertions(+), 315 deletions(-) create mode 100644 src-tauri/src/commands/app.rs create mode 100644 src-tauri/src/commands/app_data.rs create mode 100644 src-tauri/src/commands/auth.rs create mode 100644 src-tauri/src/commands/config.rs create mode 100644 src-tauri/src/commands/dolls.rs create mode 100644 src-tauri/src/commands/friends.rs create mode 100644 src-tauri/src/commands/interaction.rs create mode 100644 src-tauri/src/commands/mod.rs create mode 100644 src-tauri/src/commands/sprite.rs diff --git a/src-tauri/src/app.rs b/src-tauri/src/app.rs index caa3ddb..c29e0ea 100644 --- a/src-tauri/src/app.rs +++ b/src-tauri/src/app.rs @@ -13,9 +13,8 @@ use crate::{ welcome::open_welcome_window, ws::init_ws_client, }, - state::init_app_data, + state::{init_app_data, FDOLL}, system_tray::{init_system_tray, update_system_tray}, - FDOLL, }; pub async fn start_fdoll() { diff --git a/src-tauri/src/commands/app.rs b/src-tauri/src/commands/app.rs new file mode 100644 index 0000000..30a5c61 --- /dev/null +++ b/src-tauri/src/commands/app.rs @@ -0,0 +1,14 @@ +use crate::get_app_handle; + +#[tauri::command] +pub fn quit_app() -> Result<(), String> { + let app_handle = get_app_handle(); + app_handle.exit(0); + Ok(()) +} + +#[tauri::command] +pub fn restart_app() { + let app_handle = get_app_handle(); + app_handle.restart(); +} diff --git a/src-tauri/src/commands/app_data.rs b/src-tauri/src/commands/app_data.rs new file mode 100644 index 0000000..5f644dd --- /dev/null +++ b/src-tauri/src/commands/app_data.rs @@ -0,0 +1,18 @@ +use crate::{ + lock_r, + models::app_data::AppData, + state::{init_app_data, FDOLL}, +}; + +#[tauri::command] +pub fn get_app_data() -> Result { + let guard = lock_r!(FDOLL); + return Ok(guard.app_data.clone()); +} + +#[tauri::command] +pub async fn refresh_app_data() -> Result { + init_app_data().await; + let guard = lock_r!(FDOLL); + Ok(guard.app_data.clone()) +} diff --git a/src-tauri/src/commands/auth.rs b/src-tauri/src/commands/auth.rs new file mode 100644 index 0000000..c0da5b0 --- /dev/null +++ b/src-tauri/src/commands/auth.rs @@ -0,0 +1,25 @@ +use tauri; +use tracing; + +#[tauri::command] +pub async fn logout_and_restart() -> Result<(), String> { + crate::services::auth::logout_and_restart() + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn start_auth_flow() -> Result<(), String> { + // Cancel any in-flight auth listener/state before starting a new one + crate::services::auth::cancel_auth_flow(); + + crate::services::auth::init_auth_code_retrieval(|| { + tracing::info!("Authentication successful, creating scene..."); + // Close welcome window if it's still open + crate::services::welcome::close_welcome_window(); + tauri::async_runtime::spawn(async { + crate::app::bootstrap().await; + }); + }) + .map_err(|e| e.to_string()) +} \ No newline at end of file diff --git a/src-tauri/src/commands/config.rs b/src-tauri/src/commands/config.rs new file mode 100644 index 0000000..a8f1b12 --- /dev/null +++ b/src-tauri/src/commands/config.rs @@ -0,0 +1,31 @@ +use crate::{ + services::client_config_manager::{ + load_app_config, open_config_manager_window, save_app_config, AppConfig, + }, + state::FDOLL, + lock_w, +}; + +#[tauri::command] +pub fn get_client_config() -> AppConfig { + let mut guard = lock_w!(FDOLL); + guard.app_config = load_app_config(); + guard.app_config.clone() +} + +#[tauri::command] +pub fn save_client_config(config: AppConfig) -> Result<(), String> { + match save_app_config(config) { + Ok(saved) => { + let mut guard = lock_w!(FDOLL); + guard.app_config = saved; + Ok(()) + } + Err(e) => Err(e.to_string()), + } +} + +#[tauri::command] +pub async fn open_client_config_manager() -> Result<(), String> { + open_config_manager_window().map_err(|e| e.to_string()) +} \ No newline at end of file diff --git a/src-tauri/src/commands/dolls.rs b/src-tauri/src/commands/dolls.rs new file mode 100644 index 0000000..aae1552 --- /dev/null +++ b/src-tauri/src/commands/dolls.rs @@ -0,0 +1,135 @@ +use crate::{ + remotes::{ + dolls::{CreateDollDto, DollDto, DollsRemote, UpdateDollDto}, + user::UserRemote, + }, + state::{init_app_data_scoped, AppDataRefreshScope, FDOLL}, + lock_r, +}; +use tauri::async_runtime; + +#[tauri::command] +pub async fn get_dolls() -> Result, String> { + DollsRemote::new() + .get_dolls() + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn get_doll(id: String) -> Result { + DollsRemote::new() + .get_doll(&id) + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn create_doll(dto: CreateDollDto) -> Result { + let result = DollsRemote::new() + .create_doll(dto) + .await + .map_err(|e| e.to_string())?; + + // Refresh dolls list in background (deduped inside init_app_data_scoped) + async_runtime::spawn(async { + init_app_data_scoped(AppDataRefreshScope::Dolls).await; + }); + + Ok(result) +} + +#[tauri::command] +pub async fn update_doll(id: String, dto: UpdateDollDto) -> Result { + let result = DollsRemote::new() + .update_doll(&id, dto) + .await + .map_err(|e| e.to_string())?; + + // Check if this was the active doll (after update completes to avoid stale reads) + let is_active_doll = { + let guard = lock_r!(FDOLL); + guard + .app_data + .user + .as_ref() + .and_then(|u| u.active_doll_id.as_ref()) + .map(|active_id| active_id == &id) + .unwrap_or(false) + }; + + // Refresh dolls list + User/Friends if this was the active doll + async_runtime::spawn(async move { + init_app_data_scoped(AppDataRefreshScope::Dolls).await; + if is_active_doll { + init_app_data_scoped(AppDataRefreshScope::User).await; + init_app_data_scoped(AppDataRefreshScope::Friends).await; + } + }); + + Ok(result) +} + +#[tauri::command] +pub async fn delete_doll(id: String) -> Result<(), String> { + DollsRemote::new() + .delete_doll(&id) + .await + .map_err(|e| e.to_string())?; + + // Check if this was the active doll (after delete completes to avoid stale reads) + let is_active_doll = { + let guard = lock_r!(FDOLL); + guard + .app_data + .user + .as_ref() + .and_then(|u| u.active_doll_id.as_ref()) + .map(|active_id| active_id == &id) + .unwrap_or(false) + }; + + // Refresh dolls list + User/Friends if the deleted doll was active + async_runtime::spawn(async move { + init_app_data_scoped(AppDataRefreshScope::Dolls).await; + if is_active_doll { + init_app_data_scoped(AppDataRefreshScope::User).await; + init_app_data_scoped(AppDataRefreshScope::Friends).await; + } + }); + + Ok(()) +} + +#[tauri::command] +pub async fn set_active_doll(doll_id: String) -> Result<(), String> { + UserRemote::new() + .set_active_doll(&doll_id) + .await + .map_err(|e| e.to_string())?; + + // Refresh User (for active_doll_id) + Friends (so friends see your active doll) + // We don't need to refresh Dolls since the doll itself hasn't changed + async_runtime::spawn(async { + init_app_data_scoped(AppDataRefreshScope::User).await; + init_app_data_scoped(AppDataRefreshScope::Friends).await; + }); + + Ok(()) +} + +#[tauri::command] +pub async fn remove_active_doll() -> Result<(), String> { + UserRemote::new() + .remove_active_doll() + .await + .map_err(|e| e.to_string())?; + + // Refresh User (for active_doll_id) + Friends (so friends see your doll is gone) + async_runtime::spawn(async { + init_app_data_scoped(AppDataRefreshScope::User).await; + init_app_data_scoped(AppDataRefreshScope::Friends).await; + }); + + Ok(()) +} \ No newline at end of file diff --git a/src-tauri/src/commands/friends.rs b/src-tauri/src/commands/friends.rs new file mode 100644 index 0000000..b22a0a3 --- /dev/null +++ b/src-tauri/src/commands/friends.rs @@ -0,0 +1,78 @@ +use crate::remotes::friends::{ + FriendRemote, FriendRequestResponseDto, FriendshipResponseDto, SendFriendRequestDto, + UserBasicDto, +}; + +#[tauri::command] +pub async fn list_friends() -> Result, String> { + FriendRemote::new() + .get_friends() + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn search_users(username: Option) -> Result, String> { + tracing::info!( + "Tauri command search_users called with username: {:?}", + username + ); + let remote = FriendRemote::new(); + tracing::info!("FriendRemote instance created for search_users"); + let result = remote.search_users(username.as_deref()).await; + tracing::info!("FriendRemote::search_users result: {:?}", result); + result.map_err(|e| { + tracing::error!("search_users command error: {}", e); + e.to_string() + }) +} + +#[tauri::command] +pub async fn send_friend_request( + request: SendFriendRequestDto, +) -> Result { + FriendRemote::new() + .send_friend_request(request) + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn received_friend_requests() -> Result, String> { + FriendRemote::new() + .get_received_requests() + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn sent_friend_requests() -> Result, String> { + FriendRemote::new() + .get_sent_requests() + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn accept_friend_request(request_id: String) -> Result { + FriendRemote::new() + .accept_friend_request(&request_id) + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn deny_friend_request(request_id: String) -> Result { + FriendRemote::new() + .deny_friend_request(&request_id) + .await + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub async fn unfriend(friend_id: String) -> Result<(), String> { + FriendRemote::new() + .unfriend(&friend_id) + .await + .map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/commands/interaction.rs b/src-tauri/src/commands/interaction.rs new file mode 100644 index 0000000..1529556 --- /dev/null +++ b/src-tauri/src/commands/interaction.rs @@ -0,0 +1,9 @@ +use crate::{ + models::interaction::SendInteractionDto, + services::interaction::send_interaction, +}; + +#[tauri::command] +pub async fn send_interaction_cmd(dto: SendInteractionDto) -> Result<(), String> { + send_interaction(dto).await +} \ No newline at end of file diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs new file mode 100644 index 0000000..51e288b --- /dev/null +++ b/src-tauri/src/commands/mod.rs @@ -0,0 +1,8 @@ +pub mod app; +pub mod app_data; +pub mod auth; +pub mod config; +pub mod dolls; +pub mod friends; +pub mod interaction; +pub mod sprite; diff --git a/src-tauri/src/commands/sprite.rs b/src-tauri/src/commands/sprite.rs new file mode 100644 index 0000000..2c7847d --- /dev/null +++ b/src-tauri/src/commands/sprite.rs @@ -0,0 +1,15 @@ +use crate::services::sprite_recolor; + +#[tauri::command] +pub fn recolor_gif_base64( + white_color_hex: String, + black_color_hex: String, + apply_texture: bool, +) -> Result { + sprite_recolor::recolor_gif_base64( + white_color_hex.as_str(), + black_color_hex.as_str(), + apply_texture, + ) + .map_err(|e: Box| e.to_string()) +} \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index cc3a6b8..eb8cbba 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,25 +1,21 @@ -use crate::{ - models::app_data::AppData, - models::interaction::SendInteractionDto, - remotes::{ - dolls::{CreateDollDto, DollDto, DollsRemote, UpdateDollDto}, - friends::{ - FriendRemote, FriendRequestResponseDto, FriendshipResponseDto, SendFriendRequestDto, - UserBasicDto, - }, - user::UserRemote, - }, - services::{ - client_config_manager::{ - load_app_config, open_config_manager_window, save_app_config, AppConfig, - }, - cursor::start_cursor_tracking, - doll_editor::open_doll_editor_window, - interaction::send_interaction, - scene::{open_splash_window, set_pet_menu_state, set_scene_interactive}, - }, - state::{init_app_data, init_app_data_scoped, AppDataRefreshScope, FDOLL}, +use crate::services::{ + cursor::start_cursor_tracking, + doll_editor::open_doll_editor_window, + scene::{open_splash_window, set_pet_menu_state, set_scene_interactive}, }; +use commands::app::{quit_app, restart_app}; +use commands::app_data::{get_app_data, refresh_app_data}; +use commands::auth::{logout_and_restart, start_auth_flow}; +use commands::config::{get_client_config, open_client_config_manager, save_client_config}; +use commands::dolls::{ + create_doll, delete_doll, get_doll, get_dolls, remove_active_doll, set_active_doll, update_doll, +}; +use commands::friends::{ + accept_friend_request, deny_friend_request, list_friends, received_friend_requests, + search_users, send_friend_request, sent_friend_requests, unfriend, +}; +use commands::interaction::send_interaction_cmd; +use commands::sprite::recolor_gif_base64; use tauri::async_runtime; use tauri::Manager; use tracing_subscriber::{self, util::SubscriberInitExt}; @@ -27,6 +23,7 @@ use tracing_subscriber::{self, util::SubscriberInitExt}; static APP_HANDLE: std::sync::OnceLock> = std::sync::OnceLock::new(); mod app; +mod commands; mod models; mod remotes; mod services; @@ -106,298 +103,6 @@ fn register_app_events(event: tauri::RunEvent) { } } -#[tauri::command] -fn get_app_data() -> Result { - let guard = lock_r!(FDOLL); - return Ok(guard.app_data.clone()); -} - -#[tauri::command] -async fn refresh_app_data() -> Result { - init_app_data().await; - let guard = lock_r!(FDOLL); - Ok(guard.app_data.clone()) -} - -#[tauri::command] -async fn list_friends() -> Result, String> { - FriendRemote::new() - .get_friends() - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn search_users(username: Option) -> Result, String> { - tracing::info!( - "Tauri command search_users called with username: {:?}", - username - ); - let remote = FriendRemote::new(); - tracing::info!("FriendRemote instance created for search_users"); - let result = remote.search_users(username.as_deref()).await; - tracing::info!("FriendRemote::search_users result: {:?}", result); - result.map_err(|e| { - tracing::error!("search_users command error: {}", e); - e.to_string() - }) -} - -#[tauri::command] -async fn send_friend_request( - request: SendFriendRequestDto, -) -> Result { - FriendRemote::new() - .send_friend_request(request) - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn received_friend_requests() -> Result, String> { - FriendRemote::new() - .get_received_requests() - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn sent_friend_requests() -> Result, String> { - FriendRemote::new() - .get_sent_requests() - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn accept_friend_request(request_id: String) -> Result { - FriendRemote::new() - .accept_friend_request(&request_id) - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn deny_friend_request(request_id: String) -> Result { - FriendRemote::new() - .deny_friend_request(&request_id) - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn unfriend(friend_id: String) -> Result<(), String> { - FriendRemote::new() - .unfriend(&friend_id) - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn get_dolls() -> Result, String> { - DollsRemote::new() - .get_dolls() - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn get_doll(id: String) -> Result { - DollsRemote::new() - .get_doll(&id) - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn create_doll(dto: CreateDollDto) -> Result { - let result = DollsRemote::new() - .create_doll(dto) - .await - .map_err(|e| e.to_string())?; - - // Refresh dolls list in background (deduped inside init_app_data_scoped) - async_runtime::spawn(async { - init_app_data_scoped(AppDataRefreshScope::Dolls).await; - }); - - Ok(result) -} - -#[tauri::command] -async fn update_doll(id: String, dto: UpdateDollDto) -> Result { - let result = DollsRemote::new() - .update_doll(&id, dto) - .await - .map_err(|e| e.to_string())?; - - // Check if this was the active doll (after update completes to avoid stale reads) - let is_active_doll = { - let guard = lock_r!(FDOLL); - guard - .app_data - .user - .as_ref() - .and_then(|u| u.active_doll_id.as_ref()) - .map(|active_id| active_id == &id) - .unwrap_or(false) - }; - - // Refresh dolls list + User/Friends if this was the active doll - async_runtime::spawn(async move { - init_app_data_scoped(AppDataRefreshScope::Dolls).await; - if is_active_doll { - init_app_data_scoped(AppDataRefreshScope::User).await; - init_app_data_scoped(AppDataRefreshScope::Friends).await; - } - }); - - Ok(result) -} - -#[tauri::command] -async fn delete_doll(id: String) -> Result<(), String> { - DollsRemote::new() - .delete_doll(&id) - .await - .map_err(|e| e.to_string())?; - - // Check if this was the active doll (after delete completes to avoid stale reads) - let is_active_doll = { - let guard = lock_r!(FDOLL); - guard - .app_data - .user - .as_ref() - .and_then(|u| u.active_doll_id.as_ref()) - .map(|active_id| active_id == &id) - .unwrap_or(false) - }; - - // Refresh dolls list + User/Friends if the deleted doll was active - async_runtime::spawn(async move { - init_app_data_scoped(AppDataRefreshScope::Dolls).await; - if is_active_doll { - init_app_data_scoped(AppDataRefreshScope::User).await; - init_app_data_scoped(AppDataRefreshScope::Friends).await; - } - }); - - Ok(()) -} - -#[tauri::command] -async fn set_active_doll(doll_id: String) -> Result<(), String> { - UserRemote::new() - .set_active_doll(&doll_id) - .await - .map_err(|e| e.to_string())?; - - // Refresh User (for active_doll_id) + Friends (so friends see your active doll) - // We don't need to refresh Dolls since the doll itself hasn't changed - async_runtime::spawn(async { - init_app_data_scoped(AppDataRefreshScope::User).await; - init_app_data_scoped(AppDataRefreshScope::Friends).await; - }); - - Ok(()) -} - -#[tauri::command] -async fn remove_active_doll() -> Result<(), String> { - UserRemote::new() - .remove_active_doll() - .await - .map_err(|e| e.to_string())?; - - // Refresh User (for active_doll_id) + Friends (so friends see your doll is gone) - async_runtime::spawn(async { - init_app_data_scoped(AppDataRefreshScope::User).await; - init_app_data_scoped(AppDataRefreshScope::Friends).await; - }); - - Ok(()) -} - -#[tauri::command] -fn recolor_gif_base64( - white_color_hex: String, - black_color_hex: String, - apply_texture: bool, -) -> Result { - services::sprite_recolor::recolor_gif_base64( - white_color_hex.as_str(), - black_color_hex.as_str(), - apply_texture, - ) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn quit_app() -> Result<(), String> { - let app_handle = get_app_handle(); - app_handle.exit(0); - Ok(()) -} - -#[tauri::command] -fn restart_app() { - let app_handle = get_app_handle(); - app_handle.restart(); -} - -#[tauri::command] -fn get_client_config() -> AppConfig { - let mut guard = lock_w!(FDOLL); - guard.app_config = load_app_config(); - guard.app_config.clone() -} - -#[tauri::command] -fn save_client_config(config: AppConfig) -> Result<(), String> { - match save_app_config(config) { - Ok(saved) => { - let mut guard = lock_w!(FDOLL); - guard.app_config = saved; - Ok(()) - } - Err(e) => Err(e.to_string()), - } -} - -#[tauri::command] -async fn open_client_config_manager() -> Result<(), String> { - open_config_manager_window().map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn logout_and_restart() -> Result<(), String> { - crate::services::auth::logout_and_restart() - .await - .map_err(|e| e.to_string()) -} - -#[tauri::command] -async fn send_interaction_cmd(dto: SendInteractionDto) -> Result<(), String> { - send_interaction(dto).await -} - -#[tauri::command] -fn start_auth_flow() -> Result<(), String> { - // Cancel any in-flight auth listener/state before starting a new one - crate::services::auth::cancel_auth_flow(); - - crate::services::auth::init_auth_code_retrieval(|| { - tracing::info!("Authentication successful, creating scene..."); - // Close welcome window if it's still open - crate::services::welcome::close_welcome_window(); - tauri::async_runtime::spawn(async { - crate::app::bootstrap().await; - }); - }) - .map_err(|e| e.to_string()) -} - #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default()