mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-12 00:23:48 +03:00
* Import generic watchdog observer over platform specific import * Use os.path rather than genericpath * Split off socket management in plugin.py * Don't specify multiprocessing start type Default on linux is already fork * Move all platform-specific functions to seperate files TODO: make plugin.py platform agnostic * fix import * add backwards compat to helpers.py * add backwards compatibility to helpers.py harder * Testing autobuild for win * Testing autobuild for win, try 2 * Testing autobuild for win, try 3 * Testing autobuild for win, try 4 * Create the plugins folder before attempting to use it * Implement win get_username() * Create win install script * Fix branch guess from version * Create .loader.version in install script * Add .cmd shim to facilitate auto-restarts * Properly fix branch guess from version * Fix updater on windows * Try 2 of fixing updates for windows * Test * pain * Update install script * Powershell doesn't believe in utf8 * Powershell good * add ON_LINUX variable to localplatform * Fix more merge issues * test * Move custom imports to main.py * Move custom imports to after __main__ check Due to windows' default behaviour being spawn, it will spawn a new process and thus import into sys.path multiple times * Log errors in get_system_pythonpaths() and get_loader_version() + split get_system_pythonpaths() on newline * Remove whitespace in result of get_system_pythonpaths() * use python3 on linux and python on windows in get_system_pythonpaths() * Remove fork-specific urls * Fix MIME types not working on Windows
132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
import asyncio, time, random
|
|
from localplatform import ON_WINDOWS
|
|
|
|
BUFFER_LIMIT = 2 ** 20 # 1 MiB
|
|
|
|
class UnixSocket:
|
|
def __init__(self, on_new_message):
|
|
'''
|
|
on_new_message takes 1 string argument.
|
|
It's return value gets used, if not None, to write data to the socket.
|
|
Method should be async
|
|
'''
|
|
self.socket_addr = f"/tmp/plugin_socket_{time.time()}"
|
|
self.on_new_message = on_new_message
|
|
self.socket = None
|
|
self.reader = None
|
|
self.writer = None
|
|
|
|
async def setup_server(self):
|
|
self.socket = await asyncio.start_unix_server(self._listen_for_method_call, path=self.socket_addr, limit=BUFFER_LIMIT)
|
|
|
|
async def _open_socket_if_not_exists(self):
|
|
if not self.reader:
|
|
retries = 0
|
|
while retries < 10:
|
|
try:
|
|
self.reader, self.writer = await asyncio.open_unix_connection(self.socket_addr, limit=BUFFER_LIMIT)
|
|
return True
|
|
except:
|
|
await asyncio.sleep(2)
|
|
retries += 1
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
async def get_socket_connection(self):
|
|
if not await self._open_socket_if_not_exists():
|
|
return None, None
|
|
|
|
return self.reader, self.writer
|
|
|
|
async def close_socket_connection(self):
|
|
if self.writer != None:
|
|
self.writer.close()
|
|
|
|
self.reader = None
|
|
|
|
async def read_single_line(self) -> str|None:
|
|
reader, writer = await self.get_socket_connection()
|
|
|
|
if self.reader == None:
|
|
return None
|
|
|
|
return await self._read_single_line(reader)
|
|
|
|
async def write_single_line(self, message : str):
|
|
reader, writer = await self.get_socket_connection()
|
|
|
|
if self.writer == None:
|
|
return;
|
|
|
|
await self._write_single_line(writer, message)
|
|
|
|
async def _read_single_line(self, reader) -> str:
|
|
line = bytearray()
|
|
while True:
|
|
try:
|
|
line.extend(await reader.readuntil())
|
|
except asyncio.LimitOverrunError:
|
|
line.extend(await reader.read(reader._limit))
|
|
continue
|
|
except asyncio.IncompleteReadError as err:
|
|
line.extend(err.partial)
|
|
break
|
|
else:
|
|
break
|
|
|
|
return line.decode("utf-8")
|
|
|
|
async def _write_single_line(self, writer, message : str):
|
|
if not message.endswith("\n"):
|
|
message += "\n"
|
|
|
|
writer.write(message.encode("utf-8"))
|
|
await writer.drain()
|
|
|
|
async def _listen_for_method_call(self, reader, writer):
|
|
while True:
|
|
line = await self._read_single_line(reader)
|
|
|
|
try:
|
|
res = await self.on_new_message(line)
|
|
except Exception as e:
|
|
return
|
|
|
|
if res != None:
|
|
await self._write_single_line(writer, res)
|
|
|
|
class PortSocket (UnixSocket):
|
|
def __init__(self, on_new_message):
|
|
'''
|
|
on_new_message takes 1 string argument.
|
|
It's return value gets used, if not None, to write data to the socket.
|
|
Method should be async
|
|
'''
|
|
super().__init__(on_new_message)
|
|
self.host = "127.0.0.1"
|
|
self.port = random.sample(range(40000, 60000), 1)[0]
|
|
|
|
async def setup_server(self):
|
|
self.socket = await asyncio.start_server(self._listen_for_method_call, host=self.host, port=self.port, limit=BUFFER_LIMIT)
|
|
|
|
async def _open_socket_if_not_exists(self):
|
|
if not self.reader:
|
|
retries = 0
|
|
while retries < 10:
|
|
try:
|
|
self.reader, self.writer = await asyncio.open_connection(host=self.host, port=self.port, limit=BUFFER_LIMIT)
|
|
return True
|
|
except:
|
|
await asyncio.sleep(2)
|
|
retries += 1
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
if ON_WINDOWS:
|
|
class LocalSocket (PortSocket):
|
|
pass
|
|
else:
|
|
class LocalSocket (UnixSocket):
|
|
pass |