diff options
| -rw-r--r-- | .vscode/tasks.json | 39 | ||||
| -rw-r--r-- | backend/helpers.py | 22 | ||||
| -rw-r--r-- | backend/injector.py | 263 | ||||
| -rw-r--r-- | backend/loader.py | 2 | ||||
| -rw-r--r-- | backend/main.py | 82 | ||||
| -rw-r--r-- | backend/updater.py | 66 | ||||
| -rw-r--r-- | backend/utilities.py | 34 | ||||
| -rw-r--r-- | frontend/rollup.config.js | 11 | ||||
| -rw-r--r-- | frontend/src/plugin-loader.tsx | 6 |
9 files changed, 296 insertions, 229 deletions
diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a7062156..152a0051 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,7 +14,9 @@ "label": "localrun", "type": "shell", "group": "none", - "dependsOn" : ["buildall"], + "dependsOn": [ + "buildall" + ], "detail": "Check for local runs, create a plugins folder", "command": "mkdir -p plugins", "problemMatcher": [] @@ -49,14 +51,23 @@ "problemMatcher": [] }, { + "script": "watch", + "type": "npm", + "path": "frontend", + "group": "build", + "problemMatcher": [], + "label": "watchfrontend", + "detail": "rollup -c -w", + "isBackground": true + }, + { "label": "buildfrontend", "type": "npm", "group": "build", "detail": "rollup -c", "script": "build", "path": "frontend", - "problemMatcher": [], - + "problemMatcher": [] }, { "label": "buildall", @@ -95,7 +106,9 @@ "detail": "Run indev PluginLoader on Deck", "type": "shell", "group": "none", - "dependsOn" : ["checkforsettings"], + "dependsOn": [ + "checkforsettings" + ], "command": "ssh deck@${config:deckip} -p ${config:deckport} ${config:deckkey} 'export PLUGIN_PATH=${config:deckdir}/homebrew/dev/plugins; export CHOWN_PLUGIN_PATH=0; export LOG_LEVEL=DEBUG; cd ${config:deckdir}/homebrew/services; echo '${config:deckpass}' | sudo -SE python3 ${config:deckdir}/homebrew/dev/pluginloader/backend/main.py'", "problemMatcher": [] }, @@ -109,13 +122,27 @@ }, // ALL-IN-ONES { + "label": "deployandrun", + "detail": "Deploy and run, skipping JS build. Useful when combined with npm:watch", + "dependsOrder": "sequence", + "group": { + "kind": "build", + "isDefault": true + }, + "dependsOn": [ + "deploy", + "runpydeck" + ], + "problemMatcher": [] + }, + { "label": "updateremote", "detail": "Build and deploy", "dependsOrder": "sequence", "group": "none", "dependsOn": [ "buildall", - "deploy", + "deploy" ], "problemMatcher": [] }, @@ -152,4 +179,4 @@ "problemMatcher": [] } ] -} +}
\ No newline at end of file diff --git a/backend/helpers.py b/backend/helpers.py index 0b6e7746..c12a2fa5 100644 --- a/backend/helpers.py +++ b/backend/helpers.py @@ -94,18 +94,18 @@ async def download_remote_binary_to_path(url, binHash, path) -> bool: if os.access(os.path.dirname(path), os.W_OK): async with ClientSession() as client: res = await client.get(url, ssl=get_ssl_context()) - if res.status == 200: - data = BytesIO(await res.read()) - remoteHash = sha256(data.getbuffer()).hexdigest() - if binHash == remoteHash: - data.seek(0) - with open(path, 'wb') as f: - f.write(data.getbuffer()) - rv = True - else: - raise Exception(f"Fatal Error: Hash Mismatch for remote binary {path}@{url}") + if res.status == 200: + data = BytesIO(await res.read()) + remoteHash = sha256(data.getbuffer()).hexdigest() + if binHash == remoteHash: + data.seek(0) + with open(path, 'wb') as f: + f.write(data.getbuffer()) + rv = True else: - rv = False + raise Exception(f"Fatal Error: Hash Mismatch for remote binary {path}@{url}") + else: + rv = False except: rv = False diff --git a/backend/injector.py b/backend/injector.py index 5112efe1..ec7f0aa9 100644 --- a/backend/injector.py +++ b/backend/injector.py @@ -6,7 +6,7 @@ from traceback import format_exc from typing import List from aiohttp import ClientSession, WSMsgType -from aiohttp.client_exceptions import ClientConnectorError +from aiohttp.client_exceptions import ClientConnectorError, ClientOSError from asyncio.exceptions import TimeoutError import uuid @@ -32,13 +32,16 @@ class Tab: self.websocket = await self.client.ws_connect(self.ws_url) async def close_websocket(self): + await self.websocket.close() await self.client.close() async def listen_for_message(self): async for message in self.websocket: data = message.json() yield data - + logger.warn(f"The Tab {self.title} socket has been disconnected while listening for messages.") + await self.close_websocket() + async def _send_devtools_cmd(self, dc, receive=True): if self.websocket: self.cmd_id += 1 @@ -52,20 +55,22 @@ class Tab: raise RuntimeError("Websocket not opened") async def evaluate_js(self, js, run_async=False, manage_socket=True, get_result=True): - if manage_socket: - await self.open_websocket() - - res = await self._send_devtools_cmd({ - "method": "Runtime.evaluate", - "params": { - "expression": js, - "userGesture": True, - "awaitPromise": run_async - } - }, get_result) + try: + if manage_socket: + await self.open_websocket() - if manage_socket: - await self.close_websocket() + res = await self._send_devtools_cmd({ + "method": "Runtime.evaluate", + "params": { + "expression": js, + "userGesture": True, + "awaitPromise": run_async + } + }, get_result) + + finally: + if manage_socket: + await self.close_websocket() return res async def has_global_var(self, var_name, manage_socket=True): @@ -77,15 +82,17 @@ class Tab: return res["result"]["result"]["value"] async def close(self, manage_socket=True): - if manage_socket: - await self.open_websocket() + try: + if manage_socket: + await self.open_websocket() - res = await self._send_devtools_cmd({ - "method": "Page.close", - }, False) + res = await self._send_devtools_cmd({ + "method": "Page.close", + }, False) - if manage_socket: - await self.close_websocket() + finally: + if manage_socket: + await self.close_websocket() return res async def enable(self): @@ -105,78 +112,82 @@ class Tab: }, False) async def refresh(self): - if manage_socket: - await self.open_websocket() + try: + if manage_socket: + await self.open_websocket() - await self._send_devtools_cmd({ - "method": "Page.reload", - }, False) + await self._send_devtools_cmd({ + "method": "Page.reload", + }, False) - if manage_socket: - await self.close_websocket() + finally: + if manage_socket: + await self.close_websocket() return async def reload_and_evaluate(self, js, manage_socket=True): """ Reloads the current tab, with JS to run on load via debugger """ - if manage_socket: - await self.open_websocket() - - await self._send_devtools_cmd({ - "method": "Debugger.enable" - }, True) - - await self._send_devtools_cmd({ - "method": "Runtime.evaluate", - "params": { - "expression": "location.reload();", - "userGesture": True, - "awaitPromise": False - } - }, False) - - breakpoint_res = await self._send_devtools_cmd({ - "method": "Debugger.setInstrumentationBreakpoint", - "params": { - "instrumentation": "beforeScriptExecution" - } - }, True) + try: + if manage_socket: + await self.open_websocket() - logger.info(breakpoint_res) - - # Page finishes loading when breakpoint hits + await self._send_devtools_cmd({ + "method": "Debugger.enable" + }, True) - for x in range(20): - # this works around 1/5 of the time, so just send it 8 times. - # the js accounts for being injected multiple times allowing only one instance to run at a time anyway await self._send_devtools_cmd({ "method": "Runtime.evaluate", "params": { - "expression": js, + "expression": "location.reload();", "userGesture": True, "awaitPromise": False } }, False) - await self._send_devtools_cmd({ - "method": "Debugger.removeBreakpoint", - "params": { - "breakpointId": breakpoint_res["result"]["breakpointId"] - } - }, False) + breakpoint_res = await self._send_devtools_cmd({ + "method": "Debugger.setInstrumentationBreakpoint", + "params": { + "instrumentation": "beforeScriptExecution" + } + }, True) + + logger.info(breakpoint_res) + + # Page finishes loading when breakpoint hits + + for x in range(20): + # this works around 1/5 of the time, so just send it 8 times. + # the js accounts for being injected multiple times allowing only one instance to run at a time anyway + await self._send_devtools_cmd({ + "method": "Runtime.evaluate", + "params": { + "expression": js, + "userGesture": True, + "awaitPromise": False + } + }, False) - for x in range(4): await self._send_devtools_cmd({ - "method": "Debugger.resume" + "method": "Debugger.removeBreakpoint", + "params": { + "breakpointId": breakpoint_res["result"]["breakpointId"] + } }, False) - await self._send_devtools_cmd({ - "method": "Debugger.disable" - }, True) + for x in range(4): + await self._send_devtools_cmd({ + "method": "Debugger.resume" + }, False) - if manage_socket: - await self.close_websocket() + await self._send_devtools_cmd({ + "method": "Debugger.disable" + }, True) + + finally: + if manage_socket: + await self.close_websocket() return async def add_script_to_evaluate_on_new_document(self, js, add_dom_wrapper=True, manage_socket=True, get_result=True): @@ -212,32 +223,34 @@ class Tab: (see remove_script_to_evaluate_on_new_document below) None is returned if `get_result` is False """ + try: - wrappedjs = """ - function scriptFunc() { - {js} - } - if (document.readyState === 'loading') { - addEventListener('DOMContentLoaded', () => { - scriptFunc(); - }); - } else { - scriptFunc(); - } - """.format(js=js) if add_dom_wrapper else js - - if manage_socket: - await self.open_websocket() - - res = await self._send_devtools_cmd({ - "method": "Page.addScriptToEvaluateOnNewDocument", - "params": { - "source": wrappedjs + wrappedjs = """ + function scriptFunc() { + {js} } - }, get_result) + if (document.readyState === 'loading') { + addEventListener('DOMContentLoaded', () => { + scriptFunc(); + }); + } else { + scriptFunc(); + } + """.format(js=js) if add_dom_wrapper else js + + if manage_socket: + await self.open_websocket() - if manage_socket: - await self.close_websocket() + res = await self._send_devtools_cmd({ + "method": "Page.addScriptToEvaluateOnNewDocument", + "params": { + "source": wrappedjs + } + }, get_result) + + finally: + if manage_socket: + await self.close_websocket() return res async def remove_script_to_evaluate_on_new_document(self, script_id, manage_socket=True): @@ -250,18 +263,20 @@ class Tab: The identifier of the script to remove (returned from `add_script_to_evaluate_on_new_document`) """ - if manage_socket: - await self.open_websocket() + try: + if manage_socket: + await self.open_websocket() - res = await self._send_devtools_cmd({ - "method": "Page.removeScriptToEvaluateOnNewDocument", - "params": { - "identifier": script_id - } - }, False) + res = await self._send_devtools_cmd({ + "method": "Page.removeScriptToEvaluateOnNewDocument", + "params": { + "identifier": script_id + } + }, False) - if manage_socket: - await self.close_websocket() + finally: + if manage_socket: + await self.close_websocket() async def has_element(self, element_name, manage_socket=True): res = await self.evaluate_js(f"document.getElementById('{element_name}') != null", False, manage_socket) @@ -337,28 +352,32 @@ class Tab: async def get_tabs() -> List[Tab]: - async with ClientSession() as web: - res = {} + res = {} - while True: - try: + na = False + while True: + try: + async with ClientSession() as web: res = await web.get(f"{BASE_ADDRESS}/json", timeout=3) - except ClientConnectorError: - logger.debug("ClientConnectorError excepted.") + except ClientConnectorError: + if not na: logger.debug("Steam isn't available yet. Wait for a moment...") - logger.error(format_exc()) - await sleep(5) - except TimeoutError: - logger.warn(f"The request to {BASE_ADDRESS}/json timed out") - await sleep(1) - else: - break - - if res.status == 200: - r = await res.json() - return [Tab(i) for i in r] + na = True + await sleep(5) + except ClientOSError: + logger.warn(f"The request to {BASE_ADDRESS}/json was reset") + await sleep(1) + except TimeoutError: + logger.warn(f"The request to {BASE_ADDRESS}/json timed out") + await sleep(1) else: - raise Exception(f"/json did not return 200. {await res.text()}") + break + + if res.status == 200: + r = await res.json() + return [Tab(i) for i in r] + else: + raise Exception(f"/json did not return 200. {await res.text()}") async def get_tab(tab_name) -> Tab: diff --git a/backend/loader.py b/backend/loader.py index e756ba5e..2eeead36 100644 --- a/backend/loader.py +++ b/backend/loader.py @@ -208,7 +208,7 @@ class Loader: return web.Response(text=ret) async def get_steam_resource(self, request): - tab = await get_tab("QuickAccess") + tab = await get_tab("SP") try: return web.Response(text=await tab.get_steam_resource(f"https://steamloopback.host/{request.match_info['path']}"), content_type="text/html") except Exception as e: diff --git a/backend/main.py b/backend/main.py index 7e3cdd2a..cd73ce26 100644 --- a/backend/main.py +++ b/backend/main.py @@ -4,7 +4,7 @@ from subprocess import call if hasattr(sys, '_MEIPASS'): call(['chmod', '-R', '755', sys._MEIPASS]) # Full imports -from asyncio import get_event_loop, sleep +from asyncio import new_event_loop, set_event_loop, sleep from json import dumps, loads from logging import DEBUG, INFO, basicConfig, getLogger from os import getenv, chmod, path @@ -12,7 +12,7 @@ from traceback import format_exc import aiohttp_cors # Partial imports -from aiohttp import ClientSession, client_exceptions, WSMsgType +from aiohttp import client_exceptions, WSMsgType from aiohttp.web import Application, Response, get, run_app, static from aiohttp_jinja2 import setup as jinja_setup @@ -21,7 +21,7 @@ from browser import PluginBrowser from helpers import (REMOTE_DEBUGGER_UNIT, csrf_middleware, get_csrf_token, get_home_path, get_homebrew_path, get_user, get_user_group, set_user, set_user_group, - stop_systemd_unit) + stop_systemd_unit, start_systemd_unit) from injector import get_gamepadui_tab, Tab, get_tabs from loader import Loader from settings import SettingsManager @@ -56,15 +56,15 @@ basicConfig( logger = getLogger("Main") -async def chown_plugin_dir(_): +async def chown_plugin_dir(): code_chown = call(["chown", "-R", USER+":"+GROUP, CONFIG["plugin_path"]]) code_chmod = call(["chmod", "-R", "555", CONFIG["plugin_path"]]) if code_chown != 0 or code_chmod != 0: logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})") class PluginManager: - def __init__(self) -> None: - self.loop = get_event_loop() + def __init__(self, loop) -> None: + self.loop = loop self.web_app = Application() self.web_app.middlewares.append(csrf_middleware) self.cors = aiohttp_cors.setup(self.web_app, defaults={ @@ -81,12 +81,19 @@ class PluginManager: self.updater = Updater(self) jinja_setup(self.web_app) - if CONFIG["chown_plugin_path"] == True: - self.web_app.on_startup.append(chown_plugin_dir) - self.loop.create_task(self.loader_reinjector()) - self.loop.create_task(self.load_plugins()) - if not self.settings.getSetting("cef_forward", False): - self.loop.create_task(stop_systemd_unit(REMOTE_DEBUGGER_UNIT)) + + async def startup(_): + if self.settings.getSetting("cef_forward", False): + self.loop.create_task(start_systemd_unit(REMOTE_DEBUGGER_UNIT)) + else: + self.loop.create_task(stop_systemd_unit(REMOTE_DEBUGGER_UNIT)) + if CONFIG["chown_plugin_path"] == True: + chown_plugin_dir() + self.loop.create_task(self.loader_reinjector()) + self.loop.create_task(self.load_plugins()) + + self.web_app.on_startup.append(startup) + self.loop.set_exception_handler(self.exception_handler) self.web_app.add_routes([get("/auth/token", self.get_auth_token)]) @@ -103,31 +110,29 @@ class PluginManager: async def get_auth_token(self, request): return Response(text=get_csrf_token()) - async def wait_for_server(self): - async with ClientSession() as web: - while True: - try: - await web.get(f"http://{CONFIG['server_host']}:{CONFIG['server_port']}") - return - except Exception as e: - await sleep(0.1) - async def load_plugins(self): - await self.wait_for_server() + # await self.wait_for_server() + logger.debug("Loading plugins") self.plugin_loader.import_plugins() # await inject_to_tab("SP", "window.syncDeckyPlugins();") async def loader_reinjector(self): while True: tab = None + nf = False + dc = False while not tab: try: tab = await get_gamepadui_tab() except client_exceptions.ClientConnectorError or client_exceptions.ServerDisconnectedError: - logger.debug("Couldn't connect to debugger, waiting 5 seconds.") + if not dc: + logger.debug("Couldn't connect to debugger, waiting...") + dc = True pass except ValueError: - logger.debug("Couldn't find GamepadUI tab, waiting 5 seconds") + if not nf: + logger.debug("Couldn't find GamepadUI tab, waiting...") + nf = True pass if not tab: await sleep(5) @@ -136,15 +141,20 @@ class PluginManager: await self.inject_javascript(tab, True) try: async for msg in tab.listen_for_message(): - logger.debug("Page event: " + str(msg.get("method", None))) - if msg.get("method", None) == "Page.domContentEventFired": - if not await tab.has_global_var("deckyHasLoaded", False): - await self.inject_javascript(tab) - if msg.get("method", None) == "Inspector.detached" or msg.get("type", None) in (WSMsgType.CLOSED, WSMsgType.ERROR): - logger.info("CEF has disconnected...") - logger.debug("Exit message: " + str(msg)) - await tab.close_websocket() - break + # this gets spammed a lot + if msg.get("method", None) != "Page.navigatedWithinDocument": + logger.debug("Page event: " + str(msg.get("method", None))) + if msg.get("method", None) == "Page.domContentEventFired": + if not await tab.has_global_var("deckyHasLoaded", False): + await self.inject_javascript(tab) + if msg.get("method", None) == "Inspector.detached": + logger.info("CEF has requested that we detach.") + await tab.close_websocket() + break + # 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...") + # At this point the loop starts again and we connect to the freshly started Steam client once it is ready. except Exception as e: logger.error("Exception while reading page events " + format_exc()) await tab.close_websocket() @@ -166,7 +176,7 @@ class PluginManager: # logger.debug("Closing tab: " + getattr(t, "title", "Untitled")) # await t.close() # await sleep(0.5) - await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.User.StartRestart(), 100)}else{window.deckyHasLoaded = true;(async()=>{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')})();}}catch(e){console.error(e)}", False, False, False) + await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.User.StartRestart(), 100)}else{window.deckyHasLoaded = true;(async()=>{try{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}", False, False, False) except: logger.info("Failed to inject JavaScript into tab\n" + format_exc()) pass @@ -175,4 +185,6 @@ class PluginManager: return run_app(self.web_app, host=CONFIG["server_host"], port=CONFIG["server_port"], loop=self.loop, access_log=None) if __name__ == "__main__": - PluginManager().run() + loop = new_event_loop() + set_event_loop(loop) + PluginManager(loop).run() diff --git a/backend/updater.py b/backend/updater.py index e20242bc..301ca396 100644 --- a/backend/updater.py +++ b/backend/updater.py @@ -112,20 +112,20 @@ class Updater: async with ClientSession() as web: async with web.request("GET", "https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases", ssl=helpers.get_ssl_context()) as res: remoteVersions = await res.json() - self.allRemoteVers = remoteVersions - logger.debug("determining release type to find, branch is %i" % selectedBranch) - if selectedBranch == 0: - logger.debug("release type: release") - self.remoteVer = next(filter(lambda ver: ver["tag_name"].startswith("v") and not ver["prerelease"] and ver["tag_name"], remoteVersions), None) - elif selectedBranch == 1: - logger.debug("release type: pre-release") - self.remoteVer = next(filter(lambda ver: ver["prerelease"] and ver["tag_name"].startswith("v") and ver["tag_name"].find("-pre"), remoteVersions), None) - else: - logger.error("release type: NOT FOUND") - raise ValueError("no valid branch found") - logger.info("Updated remote version information") - tab = await get_gamepadui_tab() - await tab.evaluate_js(f"window.DeckyPluginLoader.notifyUpdates()", False, True, False) + self.allRemoteVers = remoteVersions + logger.debug("determining release type to find, branch is %i" % selectedBranch) + if selectedBranch == 0: + logger.debug("release type: release") + self.remoteVer = next(filter(lambda ver: ver["tag_name"].startswith("v") and not ver["prerelease"] and ver["tag_name"], remoteVersions), None) + elif selectedBranch == 1: + logger.debug("release type: pre-release") + self.remoteVer = next(filter(lambda ver: ver["prerelease"] and ver["tag_name"].startswith("v") and ver["tag_name"].find("-pre"), remoteVersions), None) + else: + logger.error("release type: NOT FOUND") + raise ValueError("no valid branch found") + logger.info("Updated remote version information") + tab = await get_gamepadui_tab() + await tab.evaluate_js(f"window.DeckyPluginLoader.notifyUpdates()", False, True, False) return await self.get_version() async def version_reloader(self): @@ -152,18 +152,18 @@ class Updater: async with web.request("GET", service_url, ssl=helpers.get_ssl_context(), allow_redirects=True) as res: logger.debug("Downloading service file") data = await res.content.read() - logger.debug(str(data)) - service_file_path = path.join(getcwd(), "plugin_loader.service") - try: - with open(path.join(getcwd(), "plugin_loader.service"), "wb") as out: - out.write(data) - except Exception as e: - logger.error(f"Error at %s", exc_info=e) - with open(path.join(getcwd(), "plugin_loader.service"), 'r') as service_file: - service_data = service_file.read() - service_data = service_data.replace("${HOMEBREW_FOLDER}", "/home/"+helpers.get_user()+"/homebrew") - with open(path.join(getcwd(), "plugin_loader.service"), 'w') as service_file: - service_file.write(service_data) + logger.debug(str(data)) + service_file_path = path.join(getcwd(), "plugin_loader.service") + try: + with open(path.join(getcwd(), "plugin_loader.service"), "wb") as out: + out.write(data) + except Exception as e: + logger.error(f"Error at %s", exc_info=e) + with open(path.join(getcwd(), "plugin_loader.service"), 'r') as service_file: + service_data = service_file.read() + service_data = service_data.replace("${HOMEBREW_FOLDER}", "/home/"+helpers.get_user()+"/homebrew") + with open(path.join(getcwd(), "plugin_loader.service"), 'w') as service_file: + service_file.write(service_data) logger.debug("Saved service file") logger.debug("Copying service file over current file.") @@ -191,14 +191,14 @@ class Updater: self.context.loop.create_task(tab.evaluate_js(f"window.DeckyUpdater.updateProgress({new_progress})", False, False, False)) progress = new_progress - with open(path.join(getcwd(), ".loader.version"), "w") as out: - out.write(version) + with open(path.join(getcwd(), ".loader.version"), "w") as out: + out.write(version) - call(['chmod', '+x', path.join(getcwd(), "PluginLoader")]) - logger.info("Updated loader installation.") - await tab.evaluate_js("window.DeckyUpdater.finish()", False, False) - await self.do_restart() - await tab.client.close() + call(['chmod', '+x', path.join(getcwd(), "PluginLoader")]) + logger.info("Updated loader installation.") + await tab.evaluate_js("window.DeckyUpdater.finish()", False, False) + await self.do_restart() + await tab.close_websocket() async def do_restart(self): call(["systemctl", "daemon-reload"]) diff --git a/backend/utilities.py b/backend/utilities.py index 61e6b523..10651d2f 100644 --- a/backend/utilities.py +++ b/backend/utilities.py @@ -80,12 +80,12 @@ class Utilities: async def http_request(self, method="", url="", **kwargs): async with ClientSession() as web: - async with web.request(method, url, ssl=helpers.get_ssl_context(), **kwargs) as res: - return { - "status": res.status, - "headers": dict(res.headers), - "body": await res.text() - } + res = await web.request(method, url, ssl=helpers.get_ssl_context(), **kwargs) + return { + "status": res.status, + "headers": dict(res.headers), + "body": await res.text() + } async def ping(self, **kwargs): return "pong" @@ -241,17 +241,17 @@ class Utilities: if ip != None: self.logger.info("Connecting to React DevTools at " + ip) async with ClientSession() as web: - async with web.request("GET", "http://" + ip + ":8097", ssl=helpers.get_ssl_context()) as res: - if res.status != 200: - self.logger.error("Failed to connect to React DevTools at " + ip) - return False - self.start_rdt_proxy(ip, 8097) - script = "if(!window.deckyHasConnectedRDT){window.deckyHasConnectedRDT=true;\n" + await res.text() + "\n}" - self.logger.info("Connected to React DevTools, loading script") - tab = await get_gamepadui_tab() - # RDT needs to load before React itself to work. - result = await tab.reload_and_evaluate(script) - self.logger.info(result) + res = await web.request("GET", "http://" + ip + ":8097", ssl=helpers.get_ssl_context()) + if res.status != 200: + self.logger.error("Failed to connect to React DevTools at " + ip) + return False + self.start_rdt_proxy(ip, 8097) + script = "if(!window.deckyHasConnectedRDT){window.deckyHasConnectedRDT=true;\n" + await res.text() + "\n}" + self.logger.info("Connected to React DevTools, loading script") + tab = await get_gamepadui_tab() + # RDT needs to load before React itself to work. + result = await tab.reload_and_evaluate(script) + self.logger.info(result) except Exception: self.logger.error("Failed to connect to React DevTools") diff --git a/frontend/rollup.config.js b/frontend/rollup.config.js index c4bcd0a2..eef52c22 100644 --- a/frontend/rollup.config.js +++ b/frontend/rollup.config.js @@ -5,7 +5,12 @@ import externalGlobals from "rollup-plugin-external-globals"; import del from 'rollup-plugin-delete' import replace from '@rollup/plugin-replace'; import typescript from '@rollup/plugin-typescript'; -import { defineConfig } from 'rollup'; +import { defineConfig, handleWarning } from 'rollup'; + +const hiddenWarnings = [ + "THIS_IS_UNDEFINED", + "EVAL" +]; export default defineConfig({ input: 'src/index.tsx', @@ -35,5 +40,9 @@ export default defineConfig({ chunkFileNames: (chunkInfo) => { return 'chunk-[hash].js' } + }, + onwarn: function ( message ) { + if (hiddenWarnings.some(warning => message.code === warning)) return; + handleWarning(message); } }); diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index 73cfdf9a..381d7954 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -249,11 +249,11 @@ class PluginLoader extends Logger { <> Error:{' '} <pre> - <code>{e instanceof Error ? e.stack : e?.toString()}</code> + <code>{e instanceof Error ? e.stack : JSON.stringify(e)}</code> </pre> <> - Please go to <FaCog style={{ display: 'inline' }} /> in Decky Loader.e settings menu if you need to - uninstall this plugin. + Please go to <FaCog style={{ display: 'inline' }} /> in the Decky menu if you need to uninstall this + plugin. </> </> ); |
