Skip to content

Commit dd9a538

Browse files
committed
fix: resolve 404 error after long-term running by persisting static files and adding SPA fallback
1 parent f684f1e commit dd9a538

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

server/src/server/config.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import sys
2+
import shutil
23
from pathlib import Path
34
from loguru import logger
45

@@ -23,10 +24,24 @@ def get_share_dir() -> Path:
2324

2425

2526
def get_static_dir() -> Path:
26-
# 1. PyInstaller environment: points to sys._MEIPASS/web_dist
27+
# 1. PyInstaller environment
2728
if getattr(sys, "frozen", False):
2829
bundle_dir = Path(sys._MEIPASS)
29-
static_dir = bundle_dir / "web_dist"
30+
source_static = bundle_dir / "web_dist"
31+
32+
# Target: ~/.remote-mouse/web_dist (Persistent storage to avoid /tmp cleanup)
33+
target_static = get_share_dir() / "web_dist"
34+
35+
try:
36+
# Sync files to persistent directory
37+
if target_static.exists():
38+
shutil.rmtree(target_static)
39+
shutil.copytree(source_static, target_static)
40+
logger.info(f"Static files synced to: {target_static}")
41+
return target_static
42+
except Exception as e:
43+
logger.error(f"Failed to sync static files to persistent storage: {e}")
44+
return source_static # Fallback to temporary one
3045
else:
3146
# 2. Dev environment: points to ../../../web-client/dist
3247
# project_root is server/ (where pyproject.toml is)

server/src/server/services/manager.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import threading
2+
import socket
23
import uvicorn
34
from loguru import logger
45

@@ -26,6 +27,15 @@ def set_debug(self, debug: bool):
2627
def start(self):
2728
logger.info(f"Starting services (Debug: {self.debug})...")
2829
try:
30+
# 0. Check if port is already in use
31+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
32+
try:
33+
s.bind(("0.0.0.0", self.port))
34+
except socket.error:
35+
error_msg = f"Port {self.port} is already in use by another process."
36+
logger.error(error_msg)
37+
raise RuntimeError(error_msg)
38+
2939
# 1. Start mDNS
3040
self.mdns = MDNSResponder(port=self.port)
3141
self.mdns.register()

server/src/server/services/web.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
1+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
22
from fastapi.staticfiles import StaticFiles
3+
from fastapi.responses import FileResponse, JSONResponse
4+
from starlette.exceptions import HTTPException as StarletteHTTPException
35
from loguru import logger
46

57
from server.core.protocol import process_binary_command
@@ -26,6 +28,17 @@ async def websocket_endpoint(websocket: WebSocket):
2628
except Exception as e:
2729
logger.error(f"WebSocket error: {e}")
2830

31+
# SPA Fallback for 404 errors
32+
@app.exception_handler(404)
33+
async def not_found_handler(request: Request, exc: StarletteHTTPException):
34+
index_path = static_dir / "index.html"
35+
if index_path.exists():
36+
logger.debug(f"404 for {request.url.path}, falling back to index.html")
37+
return FileResponse(index_path)
38+
39+
logger.warning(f"404 for {request.url.path} and index.html not found in {static_dir}")
40+
return JSONResponse({"detail": "Not Found"}, status_code=404)
41+
2942
# 挂载静态文件(必须放在最后,否则可能覆盖 API 路由)
3043
if static_dir.exists():
3144
app.mount("/", StaticFiles(directory=str(static_dir), html=True), name="static")

0 commit comments

Comments
 (0)