summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorAAGaming <aa@mail.catvibers.me>2022-11-15 16:44:24 -0500
committerGitHub <noreply@github.com>2022-11-15 13:44:24 -0800
commit50764600c83b2bdec599a9fd8e27b3c10a2afd96 (patch)
treef802b7c438723846971162d0c845caa237e0cb7d /backend
parentaec70631393ba307f1ca493a4d96f244e1439555 (diff)
downloaddecky-loader-50764600c83b2bdec599a9fd8e27b3c10a2afd96.tar.gz
decky-loader-50764600c83b2bdec599a9fd8e27b3c10a2afd96.zip
Refactoring in preparation for WebSockets (#254)v2.4.1-pre2
* Fix injector race conditions * add some more tasks * hide useless rollup warnings * goodbye to clientsession errors * completely fix desktop mode switch race condition * fix typos and TS warning in plugin error handler * fix chown error * start debugger if needed and not already started * fix get_steam_resource for the like 2 legacy plugins still using it lol * add ClientOSError to get_tabs error handling
Diffstat (limited to 'backend')
-rw-r--r--backend/helpers.py22
-rw-r--r--backend/injector.py263
-rw-r--r--backend/loader.py2
-rw-r--r--backend/main.py82
-rw-r--r--backend/updater.py66
-rw-r--r--backend/utilities.py34
6 files changed, 250 insertions, 219 deletions
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")