server down screen pt 1

This commit is contained in:
2026-01-02 14:56:52 +08:00
parent 24ebfebcfd
commit ce2e0aca4f
7 changed files with 189 additions and 11 deletions

View File

@@ -4,8 +4,10 @@ use tokio::time::{sleep, Instant};
use tracing::info;
use crate::{
remotes::health::HealthRemote,
services::{
auth::{get_access_token, get_tokens},
health_manager::open_health_manager_window,
scene::{close_splash_window, open_scene_window, open_splash_window},
welcome::open_welcome_window,
ws::init_ws_client,
@@ -16,7 +18,7 @@ use crate::{
pub async fn start_fdoll() {
init_system_tray();
bootstrap().await;
init_startup_sequence().await;
}
async fn init_ws_after_auth() {
@@ -65,6 +67,28 @@ pub async fn bootstrap() {
None => {
info!("No active session found - showing welcome first");
open_welcome_window();
close_splash_window();
}
}
}
/// Perform checks for environment, network condition
/// and handle situations where startup would not be appropriate.
async fn init_startup_sequence() {
let health_remote = HealthRemote::new();
let server_health = health_remote.get_health().await;
match server_health {
Ok(response) => {
if response.status == "OK" {
bootstrap().await;
} else {
info!("Server health check failed");
}
}
Err(err) => {
info!("Server health check failed: {}", err);
open_health_manager_window();
close_splash_window();
}
}
}

View File

@@ -1,14 +1,16 @@
use crate::{
models::app_data::AppData,
remotes::dolls::{CreateDollDto, DollDto, DollsRemote, UpdateDollDto},
remotes::friends::{
remotes::{
dolls::{CreateDollDto, DollDto, DollsRemote, UpdateDollDto},
friends::{
FriendRemote, FriendRequestResponseDto, FriendshipResponseDto, SendFriendRequestDto,
UserBasicDto,
},
remotes::user::UserRemote,
user::UserRemote,
},
services::{
cursor::start_cursor_tracking,
doll_editor::open_doll_editor_window,
cursor::start_cursor_tracking, doll_editor::open_doll_editor_window,
scene::open_splash_window,
},
state::{init_app_data, init_app_data_scoped, AppDataRefreshScope, FDOLL},
};
@@ -78,6 +80,8 @@ fn setup_fdoll() -> Result<(), tauri::Error> {
.with(console_layer)
.init();
open_splash_window();
state::init_fdoll_state(Some(_guard));
async_runtime::spawn(async move { app::start_fdoll().await });
Ok(())
@@ -334,7 +338,6 @@ fn quit_app() -> Result<(), String> {
fn restart_app() -> Result<(), String> {
let app_handle = get_app_handle();
app_handle.restart();
Ok(())
}
#[tauri::command]

View File

@@ -0,0 +1,47 @@
use reqwest::{Client, Error};
use serde::{Deserialize, Serialize};
use ts_rs::TS;
use crate::{lock_r, state::FDOLL};
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct HealthResponseDto {
pub status: String,
pub version: String,
pub uptime_secs: u64,
pub db: String,
}
pub struct HealthRemote {
pub base_url: String,
pub client: Client,
}
impl HealthRemote {
pub fn new() -> Self {
let guard = lock_r!(FDOLL);
Self {
base_url: guard
.app_config
.api_base_url
.as_ref()
.expect("App configuration error")
.clone(),
client: guard
.clients
.as_ref()
.expect("App configuration error")
.http_client
.clone(),
}
}
pub async fn get_health(&self) -> Result<HealthResponseDto, Error> {
let url = format!("{}/health", self.base_url);
let resp = self.client.get(url).send().await?;
let health = resp.json().await?;
Ok(health)
}
}

View File

@@ -1,4 +1,5 @@
pub mod dolls;
pub mod friends;
pub mod user;
pub mod health;
pub mod session;
pub mod user;

View File

@@ -0,0 +1,82 @@
use crate::get_app_handle;
use tauri::Manager;
use tauri_plugin_dialog::{DialogExt, MessageDialogBuilder, MessageDialogKind};
use tauri_plugin_positioner::WindowExt;
use tracing::{error, info};
pub static HEALTH_MANAGER_WINDOW_LABEL: &str = "health_manager";
pub fn open_health_manager_window() {
let app_handle = get_app_handle();
let existing_webview_window = app_handle.get_window(HEALTH_MANAGER_WINDOW_LABEL);
if let Some(window) = existing_webview_window {
if let Err(e) = window.show() {
error!("Failed to show existing health manager window: {}", e);
MessageDialogBuilder::new(
app_handle.dialog().clone(),
"Window Error",
"Failed to show the health manager screen. Please restart and try again.",
)
.kind(MessageDialogKind::Error)
.show(|_| {});
}
return;
}
let webview_window = match tauri::WebviewWindowBuilder::new(
app_handle,
HEALTH_MANAGER_WINDOW_LABEL,
tauri::WebviewUrl::App("/health-manager".into()),
)
.title("Health Manager")
.inner_size(420.0, 420.0)
.resizable(false)
.decorations(true)
.transparent(false)
.shadow(true)
.visible(false)
.skip_taskbar(false)
.always_on_top(false)
.visible_on_all_workspaces(false)
.build()
{
Ok(window) => {
info!("{} window builder succeeded", HEALTH_MANAGER_WINDOW_LABEL);
window
}
Err(e) => {
error!(
"Failed to build {} window: {}",
HEALTH_MANAGER_WINDOW_LABEL, e
);
return;
}
};
if let Err(e) = webview_window.move_window(tauri_plugin_positioner::Position::Center) {
error!("Failed to move health manager window to center: {}", e);
}
if let Err(e) = webview_window.show() {
error!("Failed to show health manager window: {}", e);
MessageDialogBuilder::new(
app_handle.dialog().clone(),
"Window Error",
"Failed to show the health manager screen. Please restart and try again.",
)
.kind(MessageDialogKind::Error)
.show(|_| {});
}
}
pub fn close_health_manager_window() {
let app_handle = get_app_handle();
if let Some(window) = app_handle.get_window(HEALTH_MANAGER_WINDOW_LABEL) {
if let Err(e) = window.close() {
error!("Failed to close health manager window: {}", e);
} else {
info!("Health manager window closed");
}
}
}

View File

@@ -2,8 +2,8 @@ pub mod app_menu;
pub mod auth;
pub mod cursor;
pub mod doll_editor;
pub mod health_manager;
pub mod scene;
pub mod sprite_recolor;
pub mod welcome;
pub mod ws;

View File

@@ -0,0 +1,21 @@
<script>
import { invoke } from "@tauri-apps/api/core";
</script>
<div class="size-full p-4">
<div class="flex flex-col gap-4 size-full justify-between">
<div class="flex flex-col gap-2">
<p class="text-md font-light">Something is not right...</p>
<p class="opacity-70 text-3xl font-bold">
Seems like the server is inaccessible. Check your network?
</p>
</div>
<button
class="btn"
onclick={() => {
console.log("Retrying server health detection");
invoke("restart_app");
}}>Try again</button
>
</div>
</div>