Compare commits

..

3 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
5 changed files with 48 additions and 24 deletions
+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}")
+26 -6
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"]])
@@ -55,11 +64,11 @@ class PluginManager:
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:
@@ -77,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)
@@ -107,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):
+7 -8
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 {