mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 04:05:04 +03:00
handle crashloops and disable decky for the user
This commit is contained in:
@@ -52,6 +52,9 @@ async def csrf_middleware(request: Request, handler: Handler):
|
||||
return await handler(request)
|
||||
return Response(text='Forbidden', status=403)
|
||||
|
||||
def create_inject_script(script: str) -> str:
|
||||
return "try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.Browser.RestartJSContext(), 100)}else{window.deckyHasLoaded = true;(async()=>{try{await import('http://localhost:1337/frontend/%s?v=%s')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}" % (script, get_loader_version(), )
|
||||
|
||||
# Get the default homebrew path unless a home_path is specified. home_path argument is deprecated
|
||||
def get_homebrew_path() -> str:
|
||||
return localplatform.get_unprivileged_path()
|
||||
|
||||
@@ -15,6 +15,7 @@ from asyncio import AbstractEventLoop, CancelledError, Task, all_tasks, current_
|
||||
from logging import basicConfig, getLogger
|
||||
from os import path
|
||||
from traceback import format_exc
|
||||
from time import time
|
||||
import aiohttp_cors # pyright: ignore [reportMissingTypeStubs]
|
||||
|
||||
# Partial imports
|
||||
@@ -25,7 +26,7 @@ from setproctitle import getproctitle, setproctitle, setthreadtitle
|
||||
|
||||
# local modules
|
||||
from .browser import PluginBrowser
|
||||
from .helpers import (REMOTE_DEBUGGER_UNIT, csrf_middleware, get_csrf_token, get_loader_version,
|
||||
from .helpers import (REMOTE_DEBUGGER_UNIT, create_inject_script, csrf_middleware, get_csrf_token, get_loader_version,
|
||||
mkdir_as_user, get_system_pythonpaths, get_effective_user_id)
|
||||
|
||||
from .injector import get_gamepadui_tab, Tab
|
||||
@@ -75,6 +76,9 @@ class PluginManager:
|
||||
self.plugin_browser = PluginBrowser(plugin_path, self.plugin_loader.plugins, self.plugin_loader, self.settings)
|
||||
self.utilities = Utilities(self)
|
||||
self.updater = Updater(self)
|
||||
self.last_webhelper_exit: float = 0
|
||||
self.webhelper_crash_count: int = 0
|
||||
self.inject_fallback: bool = False
|
||||
|
||||
jinja_setup(self.web_app)
|
||||
|
||||
@@ -96,6 +100,21 @@ class PluginManager:
|
||||
self.cors.add(route) # pyright: ignore [reportUnknownMemberType]
|
||||
self.web_app.add_routes([static("/static", path.join(path.dirname(__file__), 'static'))])
|
||||
|
||||
async def handle_crash(self):
|
||||
new_time = time()
|
||||
if (new_time - self.last_webhelper_exit < 60):
|
||||
self.webhelper_crash_count += 1
|
||||
logger.warn(f"webhelper crashed within a minute from last crash! crash count: {self.webhelper_crash_count}")
|
||||
else:
|
||||
self.webhelper_crash_count = 0
|
||||
self.last_webhelper_exit = new_time
|
||||
|
||||
# should never happen
|
||||
if (self.webhelper_crash_count > 4):
|
||||
await self.updater.do_shutdown()
|
||||
# Give up
|
||||
exit(0)
|
||||
|
||||
async def shutdown(self, _: Application):
|
||||
try:
|
||||
logger.info(f"Shutting down...")
|
||||
@@ -187,6 +206,7 @@ class PluginManager:
|
||||
# If this is a forceful disconnect the loop will just stop without any failure message. In this case, injector.py will handle this for us so we don't need to close the socket.
|
||||
# This is because of https://github.com/aio-libs/aiohttp/blob/3ee7091b40a1bc58a8d7846e7878a77640e96996/aiohttp/client_ws.py#L321
|
||||
logger.info("CEF has disconnected...")
|
||||
await self.handle_crash()
|
||||
# At this point the loop starts again and we connect to the freshly started Steam client once it is ready.
|
||||
except Exception:
|
||||
if not self.reinject:
|
||||
@@ -194,6 +214,7 @@ class PluginManager:
|
||||
logger.error("Exception while reading page events " + format_exc())
|
||||
await tab.close_websocket()
|
||||
self.js_ctx_tab = None
|
||||
await self.handle_crash()
|
||||
pass
|
||||
# while True:
|
||||
# await sleep(5)
|
||||
@@ -211,7 +232,11 @@ class PluginManager:
|
||||
await restart_webhelper()
|
||||
await sleep(1) # To give CEF enough time to close down the websocket
|
||||
return # We'll catch the next tab in the main loop
|
||||
await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.Browser.RestartJSContext(), 100)}else{window.deckyHasLoaded = true;(async()=>{try{await import('http://localhost:1337/frontend/index.js?v=%s')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}" % (get_loader_version(), ), False, False, False)
|
||||
await tab.evaluate_js(create_inject_script("index.js" if self.webhelper_crash_count < 3 else "fallback.js"), False, False, False)
|
||||
if self.webhelper_crash_count > 2:
|
||||
self.reinject = False
|
||||
await sleep(1)
|
||||
await self.updater.do_shutdown()
|
||||
except:
|
||||
logger.info("Failed to inject JavaScript into tab\n" + format_exc())
|
||||
pass
|
||||
|
||||
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
||||
from .main import PluginManager
|
||||
from .injector import inject_to_tab, get_gamepadui_tab, close_old_tabs, get_tab
|
||||
from . import helpers
|
||||
from .localplatform.localplatform import ON_WINDOWS, service_stop, service_start, get_home_path, get_username, get_use_cef_close_workaround, close_cef_socket
|
||||
from .localplatform.localplatform import ON_WINDOWS, service_stop, service_start, get_home_path, get_username, get_use_cef_close_workaround, close_cef_socket, restart_webhelper
|
||||
|
||||
class FilePickerObj(TypedDict):
|
||||
file: Path
|
||||
@@ -77,6 +77,7 @@ class Utilities:
|
||||
context.ws.add_route("utilities/get_tab_id", self.get_tab_id)
|
||||
context.ws.add_route("utilities/get_user_info", self.get_user_info)
|
||||
context.ws.add_route("utilities/http_request", self.http_request_legacy)
|
||||
context.ws.add_route("utilities/restart_webhelper", self.restart_webhelper)
|
||||
context.ws.add_route("utilities/close_cef_socket", self.close_cef_socket)
|
||||
context.ws.add_route("utilities/_call_legacy_utility", self._call_legacy_utility)
|
||||
|
||||
@@ -291,6 +292,9 @@ class Utilities:
|
||||
if get_use_cef_close_workaround():
|
||||
await close_cef_socket()
|
||||
|
||||
async def restart_webhelper(self):
|
||||
await restart_webhelper()
|
||||
|
||||
async def filepicker_ls(self,
|
||||
path: str | None = None,
|
||||
include_files: bool = True,
|
||||
|
||||
Reference in New Issue
Block a user