summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorAAGaming <aagaming@riseup.net>2024-07-04 01:27:13 -0400
committerAAGaming <aagaming@riseup.net>2024-07-04 01:27:13 -0400
commita45df8566ed207d126e5992bb7c870acd09a1864 (patch)
tree52f63323244cd72ec9cd774144e131e4ed05fb51 /backend
parent2b2a1d9e39addd03c357a1ba08f6241b980a2759 (diff)
downloaddecky-loader-a45df8566ed207d126e5992bb7c870acd09a1864.tar.gz
decky-loader-a45df8566ed207d126e5992bb7c870acd09a1864.zip
fix plugin uninstalls
Diffstat (limited to 'backend')
-rw-r--r--backend/decky_loader/browser.py5
-rw-r--r--backend/decky_loader/localplatform/localsocket.py2
-rw-r--r--backend/decky_loader/plugin/plugin.py6
-rw-r--r--backend/decky_loader/plugin/sandboxed_plugin.py27
-rw-r--r--backend/decky_loader/wsrouter.py6
5 files changed, 32 insertions, 14 deletions
diff --git a/backend/decky_loader/browser.py b/backend/decky_loader/browser.py
index 28a591a0..af23ed0c 100644
--- a/backend/decky_loader/browser.py
+++ b/backend/decky_loader/browser.py
@@ -147,8 +147,9 @@ class PluginBrowser:
except Exception as e:
logger.error(f"Plugin {name} in {plugin_dir} was not uninstalled")
logger.error(f"Error at {str(e)}", exc_info=e)
- if self.loader.watcher:
- self.loader.watcher.disabled = False
+ finally:
+ if self.loader.watcher:
+ self.loader.watcher.disabled = False
async def _install(self, artifact: str, name: str, version: str, hash: str):
await self.loader.ws.emit("loader/plugin_download_start", name)
diff --git a/backend/decky_loader/localplatform/localsocket.py b/backend/decky_loader/localplatform/localsocket.py
index 96dbbab6..c0b4faa1 100644
--- a/backend/decky_loader/localplatform/localsocket.py
+++ b/backend/decky_loader/localplatform/localsocket.py
@@ -88,6 +88,8 @@ class UnixSocket:
except asyncio.IncompleteReadError as err:
line.extend(err.partial)
break
+ except asyncio.CancelledError:
+ break
else:
break
diff --git a/backend/decky_loader/plugin/plugin.py b/backend/decky_loader/plugin/plugin.py
index f4b01ad3..a9a9ce29 100644
--- a/backend/decky_loader/plugin/plugin.py
+++ b/backend/decky_loader/plugin/plugin.py
@@ -109,7 +109,7 @@ class PluginWrapper:
def start(self):
if self.passive:
return self
- self.proc = Process(target=self.sandboxed_plugin.initialize, args=[self._socket], daemon=True)
+ self.proc = Process(target=self.sandboxed_plugin.initialize, args=[self._socket])
self.proc.start()
self._listener_task = create_task(self._response_listener())
return self
@@ -121,9 +121,11 @@ class PluginWrapper:
if hasattr(self, "_socket"):
await self._socket.write_single_line(dumps({ "stop": True, "uninstall": uninstall }, ensure_ascii=False))
await self._socket.close_socket_connection()
+ if self.proc:
+ self.proc.join()
+ await self.kill_if_still_running()
if hasattr(self, "_listener_task"):
self._listener_task.cancel()
- await self.kill_if_still_running()
async def kill_if_still_running(self):
time = 0
diff --git a/backend/decky_loader/plugin/sandboxed_plugin.py b/backend/decky_loader/plugin/sandboxed_plugin.py
index 07b04e7d..32330a9a 100644
--- a/backend/decky_loader/plugin/sandboxed_plugin.py
+++ b/backend/decky_loader/plugin/sandboxed_plugin.py
@@ -1,12 +1,12 @@
from os import path, environ
-from signal import SIG_IGN, SIGINT, SIGTERM, signal
+from signal import SIG_IGN, SIGINT, SIGTERM, getsignal, signal
from importlib.util import module_from_spec, spec_from_file_location
from json import dumps, loads
from logging import getLogger
from sys import exit, path as syspath, modules as sysmodules
from traceback import format_exc
from asyncio import (get_event_loop, new_event_loop,
- set_event_loop, sleep)
+ set_event_loop)
from setproctitle import setproctitle, setthreadtitle
from .messages import SocketResponseDict, SocketMessageType
@@ -19,6 +19,8 @@ from typing import List, TypeVar, Any
DataType = TypeVar("DataType")
+original_term_handler = getsignal(SIGTERM)
+
class SandboxedPlugin:
def __init__(self,
name: str,
@@ -46,6 +48,8 @@ class SandboxedPlugin:
self._socket = socket
try:
+ # Ignore signals meant for parent Process
+ # TODO SURELY there's a better way to do this.
signal(SIGINT, SIG_IGN)
signal(SIGTERM, SIG_IGN)
@@ -120,7 +124,14 @@ class SandboxedPlugin:
except:
self.log.error("Failed to start " + self.name + "!\n" + format_exc())
exit(0)
- get_event_loop().run_forever()
+ try:
+ get_event_loop().run_forever()
+ except SystemExit:
+ pass
+ except:
+ self.log.error("Loop exited for " + self.name + "!\n" + format_exc())
+ finally:
+ get_event_loop().close()
async def _unload(self):
try:
@@ -156,6 +167,8 @@ class SandboxedPlugin:
data = loads(message)
if "stop" in data:
+ # Incase the loader needs to terminate our process soon
+ signal(SIGTERM, original_term_handler)
self.log.info(f"Calling Loader unload function for {self.name}.")
await self._unload()
@@ -163,10 +176,10 @@ class SandboxedPlugin:
self.log.info("Calling Loader uninstall function.")
await self._uninstall()
- get_event_loop().stop()
- while get_event_loop().is_running():
- await sleep(0.1)
- get_event_loop().close()
+ self.log.debug("Stopping event loop")
+
+ loop = get_event_loop()
+ loop.call_soon_threadsafe(loop.stop)
exit(0)
d: SocketResponseDict = {"type": SocketMessageType.RESPONSE, "res": None, "success": True, "id": data["id"]}
diff --git a/backend/decky_loader/wsrouter.py b/backend/decky_loader/wsrouter.py
index b513723f..8d20a24d 100644
--- a/backend/decky_loader/wsrouter.py
+++ b/backend/decky_loader/wsrouter.py
@@ -1,6 +1,6 @@
from logging import getLogger
-from asyncio import AbstractEventLoop, create_task
+from asyncio import AbstractEventLoop
from aiohttp import WSCloseCode, WSMsgType, WSMessage
from aiohttp.web import Application, WebSocketResponse, Request, Response, get
@@ -114,10 +114,10 @@ class WSRouter:
# do stuff with the message
if data["route"] in self.routes:
self.logger.debug(f'Started PY call {data["route"]} ID {data["id"]}')
- create_task(self._call_route(data["route"], data["args"], data["id"]))
+ self.loop.create_task(self._call_route(data["route"], data["args"], data["id"]))
else:
error = {"error":f'Route {data["route"]} does not exist.', "name": "RouteNotFoundError", "traceback": None}
- create_task(self.write({"type": MessageType.ERROR.value, "id": data["id"], "error": error}))
+ self.loop.create_task(self.write({"type": MessageType.ERROR.value, "id": data["id"], "error": error}))
case _:
self.logger.error("Unknown message type", data)
finally: