Compare commits

...

9 Commits

Author SHA1 Message Date
marios 89ecca7c30 Fixed callsign debug bug, Fixed process spawn and termination bug 2022-04-29 21:51:01 +03:00
marios 7d74e98f4f Bug fixes
- Fixed KeyError in execute_in_tab
- Changed the plugin process dispatch method, this *should* fix that annoying server hang issue.
2022-04-29 12:52:24 +03:00
marios fe1f6473e9 method call listener retry bug fix, method call response serializaiton failure fix,
- Added retry logic to the QuickAccess tab fetching in the method call listener.
- Added exception handling, in case a plugin method returns something that can't be serialized as JSON.
- Changed a few log calls from info to debug to prevent spam
- Added a filter for asyncio base_event log records, since they get spamy and don't provide any useful info most of the time. This can be turned off with the LOG_BASE_EVENTS envar.
2022-04-26 23:37:01 +03:00
WerWolv 73559ae8c7 Make sure install scripts don't create folders as root 2022-04-22 21:48:36 +02:00
WerWolv 340ea91d1c Fixed calling backend functions after restarting steam 2022-04-22 18:43:52 +02:00
WerWolv 3f3f6bd475 Allow inject_css_into_tab to create more than just a single css rule 2022-04-22 14:30:58 +02:00
WerWolv 4b2f8cd8f5 Make sure old user plugin loader is being removed 2022-04-21 18:03:05 +02:00
WerWolv 604006a7cb Fixed root check 2022-04-21 17:46:53 +02:00
WerWolv 7aa4e9106a Make release script actually work again 2022-04-21 17:44:12 +02:00
7 changed files with 73 additions and 34 deletions
+2 -2
View File
@@ -8,8 +8,8 @@ HOMEBREW_FOLDER=/home/deck/homebrew
# Create folder structure
rm -rf ${HOMEBREW_FOLDER}/services
mkdir -p ${HOMEBREW_FOLDER}/services
mkdir -p ${HOMEBREW_FOLDER}/plugins
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
# Download latest nightly build and install it
rm -rf /tmp/plugin_loader
+15 -8
View File
@@ -1,13 +1,15 @@
#!/bin/sh
[ "$UID" -eq 0 ] || exec sudo "$0" "$@"
echo "Installing Steam Deck Plugin Loader release..."
HOMEBREW_FOLDER=/home/deck/homebrew
# Create folder structure
rm -rf ${HOMEBREW_FOLDER}/services
mkdir -p ${HOMEBREW_FOLDER}/services
mkdir -p ${HOMEBREW_FOLDER}/plugins
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
# Download latest release and install it
curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output ${HOMEBREW_FOLDER}/services/PluginLoader
@@ -15,18 +17,23 @@ chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader
systemctl --user stop plugin_loader 2> /dev/null
systemctl --user disable plugin_loader 2> /dev/null
rm -f /home/deck/.config/systemd/user/plugin_loader.service
cat > /home/deck/.config/systemd/user/plugin_loader.service <<- EOM
systemctl stop plugin_loader 2> /dev/null
systemctl disable plugin_loader 2> /dev/null
rm -f /etc/systemd/system/plugin_loader.service
cat > /etc/systemd/system/plugin_loader.service <<- EOM
[Unit]
Description=SteamDeck Plugin Loader
[Service]
Type=simple
User=root
Restart=always
ExecStart=/home/deck/homebrew/services/PluginLoader
WorkingDirectory=/home/deck/homebrew/services
Environment=PLUGIN_PATH=/home/deck/homebrew/plugins
[Install]
WantedBy=default.target
WantedBy=multi-user.target
EOM
systemctl --user daemon-reload
systemctl --user start plugin_loader
systemctl --user enable plugin_loader
systemctl daemon-reload
systemctl start plugin_loader
systemctl enable plugin_loader
+6 -4
View File
@@ -3,6 +3,7 @@
from aiohttp import ClientSession
from logging import debug, getLogger
from asyncio import sleep
from traceback import format_exc
BASE_ADDRESS = "http://localhost:8080"
@@ -61,14 +62,15 @@ async def get_tabs():
res = await web.get(f"{BASE_ADDRESS}/json")
break
except:
logger.info("Steam isn't available yet. Wait for a moment...")
logger.debug("Steam isn't available yet. Wait for a moment...")
logger.debug(format_exc())
await sleep(5)
if res.status == 200:
res = await res.json()
return [Tab(i) for i in res]
r = await res.json()
return [Tab(i) for i in r]
else:
raise Exception(f"/json did not return 200. {await res.text()}")
raise Exception(f"/json did not return 200. {await r.text()}")
async def get_tab(tab_name):
tabs = await get_tabs()
+3 -1
View File
@@ -58,6 +58,7 @@ class Loader:
self.logger.info(f"plugin_path: {self.plugin_path}")
self.plugins = {}
self.callsigns = {}
self.callsign_matches = {}
self.import_plugins()
if live_reload:
@@ -85,13 +86,14 @@ class Loader:
else:
self.plugins[plugin.name].stop()
self.plugins.pop(plugin.name, None)
self.callsigns.pop(plugin.callsign, None)
self.callsigns.pop(self.callsign_matches[file], None)
if plugin.passive:
self.logger.info(f"Plugin {plugin.name} is passive")
callsign = str(time())
plugin.callsign = callsign
self.plugins[plugin.name] = plugin.start()
self.callsigns[callsign] = plugin
self.callsign_matches[file] = callsign
self.logger.info(f"Loaded {plugin.name}")
except Exception as e:
self.logger.error(f"Could not load {file}. {e}")
+33 -5
View File
@@ -1,4 +1,4 @@
from logging import getLogger, basicConfig, INFO, DEBUG
from logging import getLogger, basicConfig, INFO, DEBUG, Filter, root
from os import getenv
CONFIG = {
@@ -7,10 +7,18 @@ CONFIG = {
"server_port": int(getenv("SERVER_PORT", "1337")),
"live_reload": getenv("LIVE_RELOAD", "1") == "1",
"log_level": {"CRITICAL": 50, "ERROR": 40, "WARNING":30, "INFO": 20, "DEBUG": 10}[getenv("LOG_LEVEL", "INFO")],
"store_url": getenv("STORE_URL", "https://sdh.tzatzi.me/browse")
"store_url": getenv("STORE_URL", "https://plugins.deckbrew.xyz"),
"log_base_events": getenv("LOG_BASE_EVENTS", "0")=="1"
}
class NoBaseEvents(Filter):
def filter(self, record):
return not "asyncio" in record.name
basicConfig(level=CONFIG["log_level"], format="[%(module)s][%(levelname)s]: %(message)s")
for handler in root.handlers:
if not CONFIG["log_base_events"]:
handler.addFilter(NoBaseEvents())
from aiohttp.web import Application, run_app, static
from aiohttp_jinja2 import setup as jinja_setup
@@ -26,6 +34,7 @@ from utilities import Utilities
from browser import PluginBrowser
logger = getLogger("Main")
from traceback import print_exc
async def chown_plugin_dir(_):
Popen(["chown", "-R", "deck:deck", CONFIG["plugin_path"]])
@@ -54,11 +63,19 @@ class PluginManager:
loop.default_exception_handler(context)
async def loader_reinjector(self):
finished_reinjection = False
logger.info("Plugin loader isn't present in Steam anymore, reinjecting...")
while True:
await sleep(1)
if not await tab_has_element("QuickAccess", "plugin_iframe"):
logger.info("Plugin loader isn't present in Steam anymore, reinjecting...")
logger.debug("Plugin loader isn't present in Steam anymore, reinjecting...")
await self.inject_javascript()
finished_reinjection = True
elif finished_reinjection:
finished_reinjection = False
logger.info("Reinjecting successful!")
self.loop.create_task(self.method_call_listener())
async def inject_javascript(self, request=None):
try:
@@ -69,11 +86,17 @@ class PluginManager:
pass
async def resolve_method_call(self, tab, call_id, response):
try:
r = dumps(response)
except Exception as e:
logger.error(response["result"])
response["result"] = str(response["result"])
r = response
await tab._send_devtools_cmd({
"id": 1,
"method": "Runtime.evaluate",
"params": {
"expression": f"resolveMethodCall({call_id}, {dumps(response)})",
"expression": f"resolveMethodCall({call_id}, {r})",
"userGesture": True
}
}, receive=False)
@@ -99,7 +122,12 @@ class PluginManager:
await self.resolve_method_call(tab, method["id"], res)
async def method_call_listener(self):
tab = await get_tab("QuickAccess")
while True:
try:
tab = await get_tab("QuickAccess")
break
except:
await sleep(1)
await tab.open_websocket()
await tab._send_devtools_cmd({"id": 1, "method": "Runtime.discardConsoleEntries"})
await tab._send_devtools_cmd({"id": 1, "method": "Runtime.enable"})
+6 -5
View File
@@ -2,8 +2,10 @@ from importlib.util import spec_from_file_location, module_from_spec
from asyncio import get_event_loop, new_event_loop, set_event_loop, start_unix_server, open_unix_connection, sleep, Lock
from os import path, setuid
from json import loads, dumps, load
from concurrent.futures import ProcessPoolExecutor
from time import time
from multiprocessing import Process
from signal import signal, SIGINT
from sys import exit
class PluginWrapper:
def __init__(self, file, plugin_directory, plugin_path) -> None:
@@ -25,6 +27,8 @@ class PluginWrapper:
self.passive = not path.isfile(self.file)
def _init(self):
signal(SIGINT, lambda s, f: exit(0))
set_event_loop(new_event_loop())
if self.passive:
return
@@ -73,10 +77,7 @@ class PluginWrapper:
def start(self):
if self.passive:
return self
get_event_loop().run_in_executor(
ProcessPoolExecutor(),
self._init
)
Process(target=self._init).start()
return self
def stop(self):
+8 -9
View File
@@ -19,12 +19,12 @@ class Utilities:
async def http_request(self, method="", url="", **kwargs):
async with ClientSession() as web:
res = await web.request(method, url, **kwargs)
return {
"status": res.status,
"headers": dict(res.headers),
"body": await res.text()
}
async with web.request(method, url, **kwargs) as res:
return {
"status": res.status,
"headers": dict(res.headers),
"body": await res.text()
}
async def ping(self, **kwargs):
return "pong"
@@ -32,7 +32,6 @@ class Utilities:
async def execute_in_tab(self, tab, run_async, code):
try:
result = await inject_to_tab(tab, code, run_async)
if "exceptionDetails" in result["result"]:
return {
"success": False,
@@ -41,7 +40,7 @@ class Utilities:
return {
"success": True,
"result" : result["result"]["result"]["value"]
"result" : result["result"]["result"].get("value")
}
except Exception as e:
return {
@@ -59,7 +58,7 @@ class Utilities:
const style = document.createElement('style');
style.id = "{css_id}";
document.head.append(style);
style.sheet.insertRule(`{style}`);
style.textContent = `{style}`;
}})()
""", False)