|
1 | 1 | import asyncio |
| 2 | +import collections |
2 | 3 | import threading |
3 | 4 | from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Request, Query |
4 | 5 | from fastapi.middleware.cors import CORSMiddleware |
|
55 | 56 | # Enable CORS |
56 | 57 | app.add_middleware( |
57 | 58 | CORSMiddleware, |
58 | | - allow_origins=["*"], |
59 | | - allow_credentials=True, |
| 59 | + allow_origin_regex=".*", |
| 60 | + allow_credentials=False, |
60 | 61 | allow_methods=["*"], |
61 | 62 | allow_headers=["*"], |
62 | 63 | ) |
@@ -127,7 +128,7 @@ def __init__(self): |
127 | 128 | self.active_handlers = {} # server_id -> ServerHandler |
128 | 129 |
|
129 | 130 | # App-level log history for Dashboard mini-console |
130 | | - self.app_log_history = [] |
| 131 | + self.app_log_history = collections.deque(maxlen=500) |
131 | 132 |
|
132 | 133 | def start_background_tasks(self): |
133 | 134 | if self._log_broadcaster_task is None: |
@@ -288,8 +289,7 @@ def broadcast_log_sync(self, message, level="normal", server_id=None): |
288 | 289 |
|
289 | 290 | if not is_verbose_installer: |
290 | 291 | self.app_log_history.append(msg_obj) |
291 | | - if len(self.app_log_history) > 500: |
292 | | - self.app_log_history.pop(0) |
| 292 | + # deque auto-evicts oldest when full — no manual pop needed |
293 | 293 |
|
294 | 294 | # Thread-safe enqueue into the asyncio queue (only non-verbose logs) |
295 | 295 | try: |
@@ -1687,12 +1687,14 @@ def watch(): |
1687 | 1687 | raise psutil.NoSuchProcess(parent_pid) |
1688 | 1688 | except (psutil.NoSuchProcess, psutil.AccessDenied): |
1689 | 1689 | logging.warning("Parent process lost. Shutting down backend and servers...") |
1690 | | - # Intentar cerrar servidores limpiamente si es posible |
1691 | | - if state and state.server_handler: |
1692 | | - try: |
1693 | | - state.server_handler.stop(force=True, silent=True) |
1694 | | - except: |
1695 | | - pass |
| 1690 | + # Stop ALL active server handlers, not just the selected one |
| 1691 | + if state and state.active_handlers: |
| 1692 | + for server_id, handler in state.active_handlers.items(): |
| 1693 | + try: |
| 1694 | + if handler.is_running() or handler.is_starting(): |
| 1695 | + handler.stop(force=True, silent=True) |
| 1696 | + except: |
| 1697 | + pass |
1696 | 1698 | os._exit(0) |
1697 | 1699 | time.sleep(2) |
1698 | 1700 |
|
@@ -1908,6 +1910,37 @@ def progress(pct, msg): |
1908 | 1910 | threading.Thread(target=run_plugin_install, daemon=True).start() |
1909 | 1911 | return {"status": "started", "message": "Plugin installation started"} |
1910 | 1912 |
|
| 1913 | +# --- System Info (RAM validation) --- |
| 1914 | + |
| 1915 | +@app.get("/system/info") |
| 1916 | +def get_system_info(): |
| 1917 | + """Returns system information for frontend validation (e.g. RAM limits).""" |
| 1918 | + try: |
| 1919 | + mem = psutil.virtual_memory() |
| 1920 | + total_gb = round(mem.total / (1024 ** 3), 1) |
| 1921 | + available_gb = round(mem.available / (1024 ** 3), 1) |
| 1922 | + return { |
| 1923 | + "total_ram_gb": total_gb, |
| 1924 | + "available_ram_gb": available_gb, |
| 1925 | + "cpu_count": psutil.cpu_count(logical=True), |
| 1926 | + # Recommended max: 80% of total RAM |
| 1927 | + "max_recommended_ram_gb": round(total_gb * 0.8, 1) |
| 1928 | + } |
| 1929 | + except Exception as e: |
| 1930 | + logging.error(f"Error getting system info: {e}") |
| 1931 | + return {"total_ram_gb": 16, "available_ram_gb": 8, "cpu_count": 4, "max_recommended_ram_gb": 12} |
| 1932 | + |
| 1933 | +@app.get("/servers/running") |
| 1934 | +def get_running_servers(): |
| 1935 | + """Returns whether any server is currently running. Used by Electron close handler.""" |
| 1936 | + if not state: |
| 1937 | + return {"any_running": False} |
| 1938 | + for handler in state.active_handlers.values(): |
| 1939 | + if handler.is_running() or handler.is_starting(): |
| 1940 | + return {"any_running": True} |
| 1941 | + return {"any_running": False} |
| 1942 | + |
| 1943 | + |
1911 | 1944 | if __name__ == "__main__": |
1912 | 1945 | import uvicorn |
1913 | 1946 | # Iniciar el watchdog antes de arrancar el servidor |
|
0 commit comments