summaryrefslogtreecommitdiff
path: root/plugin_loader/injector.py
diff options
context:
space:
mode:
authormarios <marios8543@gmail.com>2022-04-03 23:50:26 +0300
committerGitHub <noreply@github.com>2022-04-03 23:50:26 +0300
commit5e9c12bac838730d4e216b3779227a9a94447e40 (patch)
tree61f50207f0d45f6fdab09c31d2b35778df8aff63 /plugin_loader/injector.py
parentfb6f55a44deef64a0efff9cc645368b946ea897d (diff)
downloaddecky-loader-5e9c12bac838730d4e216b3779227a9a94447e40.tar.gz
decky-loader-5e9c12bac838730d4e216b3779227a9a94447e40.zip
Python rewrite (#6)
* Initial commit. Untested * various fixes Core functionality confirmed working: - Iframe injection into steam client - Plugin fetching from the iframe - Plugin opening * Added function to fetch resources from steam * Improved injector module, added server-js communication - Injector module now has methods for better lower-level manipulation of the tab debug websocket. - Our "front-end" can now communicate with the manager (2-way), completely bypassing the chromium sandbox. This works via a dirty debug console trick, whoever wants to know how it works can take a look at the code. - Added utility methods file, along with an implementation of the aiohttp client that our "front-end" can access, via the system described above. - Added js implementations of the communication system described above, which can be imported by plugins. * Added steam_resource endpoint * Added basic installer script * retry logic bug fix * fixed library injection, event propagation, websocket handling - library is injected directly into the plugins as well as the plugin list - resolveMethodCall is implemented in the plugin_list.js file, which in turns calls window.sendMessage on the iframe to propagate the event - websocket method calls are processed in their own tasks now, so as not to block on long-running calls. Co-authored-by: tza <tza@hidden> Co-authored-by: WerWolv <werwolv98@gmail.com>
Diffstat (limited to 'plugin_loader/injector.py')
-rw-r--r--plugin_loader/injector.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/plugin_loader/injector.py b/plugin_loader/injector.py
new file mode 100644
index 00000000..771d5c51
--- /dev/null
+++ b/plugin_loader/injector.py
@@ -0,0 +1,85 @@
+#Injector code from https://github.com/SteamDeckHomebrew/steamdeck-ui-inject. More info on how it works there.
+
+from aiohttp import ClientSession
+from logging import info
+from asyncio import sleep
+
+BASE_ADDRESS = "http://localhost:8080"
+
+class Tab:
+ def __init__(self, res) -> None:
+ self.title = res["title"]
+ self.id = res["id"]
+ self.ws_url = res["webSocketDebuggerUrl"]
+
+ self.websocket = None
+ self.client = None
+
+ async def open_websocket(self):
+ self.client = ClientSession()
+ self.websocket = await self.client.ws_connect(self.ws_url)
+
+ async def listen_for_message(self):
+ async for message in self.websocket:
+ yield message
+
+ async def _send_devtools_cmd(self, dc, receive=True):
+ if self.websocket:
+ await self.websocket.send_json(dc)
+ return (await self.websocket.receive_json()) if receive else None
+ raise RuntimeError("Websocket not opened")
+
+ async def evaluate_js(self, js):
+ await self.open_websocket()
+ res = await self._send_devtools_cmd({
+ "id": 1,
+ "method": "Runtime.evaluate",
+ "params": {
+ "expression": js,
+ "userGesture": True
+ }
+ })
+ await self.client.close()
+ return res
+
+ async def get_steam_resource(self, url):
+ await self.open_websocket()
+ res = await self._send_devtools_cmd({
+ "id": 1,
+ "method": "Runtime.evaluate",
+ "params": {
+ "expression": f'(async function test() {{ return await (await fetch("{url}")).text() }})()',
+ "userGesture": True,
+ "awaitPromise": True
+ }
+ })
+ await self.client.close()
+ return res["result"]["result"]["value"]
+
+ def __repr__(self):
+ return self.title
+
+async def get_tabs():
+ async with ClientSession() as web:
+ res = {}
+
+ while True:
+ try:
+ res = await web.get("{}/json".format(BASE_ADDRESS))
+ break
+ except:
+ print("Steam isn't available yet. Wait for a moment...")
+ await sleep(5)
+
+ if res.status == 200:
+ res = await res.json()
+ return [Tab(i) for i in res]
+ else:
+ raise Exception("/json did not return 200. {}".format(await res.text()))
+
+async def inject_to_tab(tab_name, js):
+ tabs = await get_tabs()
+ tab = next((i for i in tabs if i.title == tab_name), None)
+ if not tab:
+ raise ValueError("Tab {} not found in running tabs".format(tab_name))
+ info(await tab.evaluate_js(js))