Skip to content

Commit e7228ee

Browse files
committed
Better Connection and Error page for when the server crash
1 parent 9a14eef commit e7228ee

File tree

5 files changed

+105
-10
lines changed

5 files changed

+105
-10
lines changed

gui/public/i18n/en/translation.ftl

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
# translators on what it means
66

77
## Websocket (server) status
8-
websocket-connecting = Connecting to the server
9-
websocket-connection_lost = Connection lost to the server. Trying to reconnect...
8+
websocket-connecting = Loading...
9+
websocket-connection_lost = The server crashed!
10+
websocket-connection_lost-desc = It looks like the SlimeVR server crashed. Check the logs and restart the program
11+
websocket-connection_lost-close = Exit SlimeVR
12+
websocket-connection_lost-logs = Open the logs Folder
1013
1114
## Update notification
1215
version_update-title = New version available: { $version }

gui/src-tauri/src/main.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![cfg_attr(all(not(debug_assertions), windows), windows_subsystem = "windows")]
22
use std::env;
33
use std::panic;
4+
use std::path::Path;
45
use std::sync::atomic::AtomicBool;
56
use std::sync::atomic::Ordering;
67
use std::sync::Arc;
@@ -57,6 +58,20 @@ fn warning(msg: String) {
5758
log::warn!(target: "webview", "{}", msg)
5859
}
5960

61+
#[tauri::command]
62+
fn open_logs_folder(app_handle: tauri::AppHandle) {
63+
let config_dir = app_handle
64+
.path()
65+
.app_config_dir()
66+
.unwrap_or_else(|_| Path::new(".").to_path_buf());
67+
let path = config_dir.join("logs");
68+
let path_str = path.to_string_lossy().into_owned();
69+
70+
if let Err(err) = open::that(path_str) {
71+
eprintln!("Failed to open config folder: {}", err);
72+
}
73+
}
74+
6075
fn main() -> Result<()> {
6176
log_panics::init();
6277
let hook = panic::take_hook();
@@ -231,6 +246,7 @@ fn setup_tauri(
231246
logging,
232247
erroring,
233248
warning,
249+
open_logs_folder,
234250
tray::update_translations,
235251
tray::update_tray_text,
236252
tray::is_tray_available,

gui/src-tauri/src/util.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,16 @@ pub fn get_launch_path(cli: Cli) -> Option<PathBuf> {
7777
Some(PathBuf::from("/usr/share/slimevr/")),
7878
];
7979

80-
paths.into_iter().flatten().find(|x| is_valid_path(x))
80+
for path in paths.into_iter().flatten() {
81+
println!("Checking path: {:?}", path);
82+
if is_valid_path(&path) {
83+
println!("✅ Found valid path: {:?}", path);
84+
return Some(path);
85+
}
86+
}
87+
88+
println!("❌ No valid path found.");
89+
None
8190
}
8291

8392
pub fn spawn_java(java: &OsStr, java_version: &OsStr) -> std::io::Result<Child> {

gui/src/App.tsx

+2-7
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import { ScaledProportionsPage } from './components/onboarding/pages/body-propor
6060
import { EmptyLayout } from './components/EmptyLayout';
6161
import { AdvancedSettings } from './components/settings/pages/AdvancedSettings';
6262
import { FirmwareUpdate } from './components/firmware-update/FirmwareUpdate';
63+
import { ConnectionLost } from './components/onboarding/pages/ConnectionLost';
6364

6465
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
6566
export const VersionContext = createContext('');
@@ -290,13 +291,7 @@ export default function App() {
290291
<div className="h-full w-full text-standard bg-background-80 text-background-10">
291292
<Preload />
292293
{!websocketAPI.isConnected && (
293-
<EmptyLayout>
294-
<div className="flex w-full h-full justify-center items-center p-2">
295-
{websocketAPI.isFirstConnection
296-
? l10n.getString('websocket-connecting')
297-
: l10n.getString('websocket-connection_lost')}
298-
</div>
299-
</EmptyLayout>
294+
<ConnectionLost></ConnectionLost>
300295
)}
301296
{websocketAPI.isConnected && <Layout></Layout>}
302297
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Button } from '@/components/commons/Button';
2+
import { LoaderIcon, SlimeState } from '@/components/commons/icon/LoaderIcon';
3+
import { Typography } from '@/components/commons/Typography';
4+
import { EmptyLayout } from '@/components/EmptyLayout';
5+
import { useConfig } from '@/hooks/config';
6+
import { useWebsocketAPI } from '@/hooks/websocket-api';
7+
import { error } from '@/utils/logging';
8+
import { Localized } from '@fluent/react';
9+
import { invoke } from '@tauri-apps/api/core';
10+
import { getCurrentWindow } from '@tauri-apps/api/window';
11+
12+
export function ConnectionLost() {
13+
const { isFirstConnection } = useWebsocketAPI();
14+
const { saveConfig } = useConfig();
15+
16+
const openLogsFolder = async () => {
17+
try {
18+
await invoke<string | null>('open_logs_folder');
19+
} catch (err) {
20+
error('Failed to open logs folder:', err);
21+
}
22+
};
23+
24+
const closeApp = async () => {
25+
await saveConfig();
26+
await invoke('update_window_state');
27+
await getCurrentWindow().destroy();
28+
};
29+
30+
return (
31+
<EmptyLayout>
32+
<div className="flex w-full h-full justify-center items-center p-4">
33+
<div className="flex flex-col items-center gap-4 -mt-12">
34+
{isFirstConnection && (
35+
<>
36+
<LoaderIcon slimeState={SlimeState.JUMPY} size={200}></LoaderIcon>
37+
<div>
38+
<Localized id="websocket-connecting">
39+
<Typography variant="main-title"></Typography>
40+
</Localized>
41+
</div>
42+
</>
43+
)}
44+
{!isFirstConnection && (
45+
<>
46+
<LoaderIcon slimeState={SlimeState.SAD} size={200}></LoaderIcon>
47+
<div>
48+
<Localized id="websocket-connection_lost">
49+
<Typography variant="main-title"></Typography>
50+
</Localized>
51+
<Localized id="websocket-connection_lost-desc">
52+
<Typography variant="standard"></Typography>
53+
</Localized>
54+
<div className="flex gap-2 justify-center mt-4">
55+
<Localized id="websocket-connection_lost-close">
56+
<Button variant="primary" onClick={closeApp}></Button>
57+
</Localized>
58+
<Localized id="websocket-connection_lost-logs">
59+
<Button
60+
variant="secondary"
61+
onClick={openLogsFolder}
62+
></Button>
63+
</Localized>
64+
</div>
65+
</div>
66+
</>
67+
)}
68+
</div>
69+
</div>
70+
</EmptyLayout>
71+
);
72+
}

0 commit comments

Comments
 (0)