mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 13:32:01 +00:00
type hints on main,plugin,updater,utilites.localsocket
This commit is contained in:
+22
-15
@@ -1,10 +1,13 @@
|
|||||||
import asyncio, time, random
|
import asyncio, time
|
||||||
|
from typing import Awaitable, Callable
|
||||||
|
import random
|
||||||
|
|
||||||
from localplatform import ON_WINDOWS
|
from localplatform import ON_WINDOWS
|
||||||
|
|
||||||
BUFFER_LIMIT = 2 ** 20 # 1 MiB
|
BUFFER_LIMIT = 2 ** 20 # 1 MiB
|
||||||
|
|
||||||
class UnixSocket:
|
class UnixSocket:
|
||||||
def __init__(self, on_new_message):
|
def __init__(self, on_new_message: Callable[[str], Awaitable[str|None]]):
|
||||||
'''
|
'''
|
||||||
on_new_message takes 1 string argument.
|
on_new_message takes 1 string argument.
|
||||||
It's return value gets used, if not None, to write data to the socket.
|
It's return value gets used, if not None, to write data to the socket.
|
||||||
@@ -46,28 +49,32 @@ class UnixSocket:
|
|||||||
self.reader = None
|
self.reader = None
|
||||||
|
|
||||||
async def read_single_line(self) -> str|None:
|
async def read_single_line(self) -> str|None:
|
||||||
reader, writer = await self.get_socket_connection()
|
reader, _ = await self.get_socket_connection()
|
||||||
|
|
||||||
if self.reader == None:
|
try:
|
||||||
return None
|
assert reader
|
||||||
|
except AssertionError:
|
||||||
|
return
|
||||||
|
|
||||||
return await self._read_single_line(reader)
|
return await self._read_single_line(reader)
|
||||||
|
|
||||||
async def write_single_line(self, message : str):
|
async def write_single_line(self, message : str):
|
||||||
reader, writer = await self.get_socket_connection()
|
_, writer = await self.get_socket_connection()
|
||||||
|
|
||||||
if self.writer == None:
|
try:
|
||||||
return;
|
assert writer
|
||||||
|
except AssertionError:
|
||||||
|
return
|
||||||
|
|
||||||
await self._write_single_line(writer, message)
|
await self._write_single_line(writer, message)
|
||||||
|
|
||||||
async def _read_single_line(self, reader) -> str:
|
async def _read_single_line(self, reader: asyncio.StreamReader) -> str:
|
||||||
line = bytearray()
|
line = bytearray()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
line.extend(await reader.readuntil())
|
line.extend(await reader.readuntil())
|
||||||
except asyncio.LimitOverrunError:
|
except asyncio.LimitOverrunError:
|
||||||
line.extend(await reader.read(reader._limit))
|
line.extend(await reader.read(reader._limit)) # type: ignore
|
||||||
continue
|
continue
|
||||||
except asyncio.IncompleteReadError as err:
|
except asyncio.IncompleteReadError as err:
|
||||||
line.extend(err.partial)
|
line.extend(err.partial)
|
||||||
@@ -77,27 +84,27 @@ class UnixSocket:
|
|||||||
|
|
||||||
return line.decode("utf-8")
|
return line.decode("utf-8")
|
||||||
|
|
||||||
async def _write_single_line(self, writer, message : str):
|
async def _write_single_line(self, writer: asyncio.StreamWriter, message : str):
|
||||||
if not message.endswith("\n"):
|
if not message.endswith("\n"):
|
||||||
message += "\n"
|
message += "\n"
|
||||||
|
|
||||||
writer.write(message.encode("utf-8"))
|
writer.write(message.encode("utf-8"))
|
||||||
await writer.drain()
|
await writer.drain()
|
||||||
|
|
||||||
async def _listen_for_method_call(self, reader, writer):
|
async def _listen_for_method_call(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
|
||||||
while True:
|
while True:
|
||||||
line = await self._read_single_line(reader)
|
line = await self._read_single_line(reader)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = await self.on_new_message(line)
|
res = await self.on_new_message(line)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
if res != None:
|
if res != None:
|
||||||
await self._write_single_line(writer, res)
|
await self._write_single_line(writer, res)
|
||||||
|
|
||||||
class PortSocket (UnixSocket):
|
class PortSocket (UnixSocket):
|
||||||
def __init__(self, on_new_message):
|
def __init__(self, on_new_message: Callable[[str], Awaitable[str|None]]):
|
||||||
'''
|
'''
|
||||||
on_new_message takes 1 string argument.
|
on_new_message takes 1 string argument.
|
||||||
It's return value gets used, if not None, to write data to the socket.
|
It's return value gets used, if not None, to write data to the socket.
|
||||||
@@ -125,7 +132,7 @@ class PortSocket (UnixSocket):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if ON_WINDOWS:
|
if ON_WINDOWS:
|
||||||
class LocalSocket (PortSocket):
|
class LocalSocket (PortSocket): # type: ignore
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
class LocalSocket (UnixSocket):
|
class LocalSocket (UnixSocket):
|
||||||
|
|||||||
+8
-7
@@ -1,5 +1,6 @@
|
|||||||
# Change PyInstaller files permissions
|
# Change PyInstaller files permissions
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Dict
|
||||||
from localplatform import (chmod, chown, service_stop, service_start,
|
from localplatform import (chmod, chown, service_stop, service_start,
|
||||||
ON_WINDOWS, get_log_level, get_live_reload,
|
ON_WINDOWS, get_log_level, get_live_reload,
|
||||||
get_server_port, get_server_host, get_chown_plugin_path,
|
get_server_port, get_server_host, get_chown_plugin_path,
|
||||||
@@ -16,7 +17,7 @@ import multiprocessing
|
|||||||
import aiohttp_cors # type: ignore
|
import aiohttp_cors # type: ignore
|
||||||
# Partial imports
|
# Partial imports
|
||||||
from aiohttp import client_exceptions
|
from aiohttp import client_exceptions
|
||||||
from aiohttp.web import Application, Response, get, run_app, static # type: ignore
|
from aiohttp.web import Application, Response, Request, get, run_app, static # type: ignore
|
||||||
from aiohttp_jinja2 import setup as jinja_setup
|
from aiohttp_jinja2 import setup as jinja_setup
|
||||||
|
|
||||||
# local modules
|
# local modules
|
||||||
@@ -70,7 +71,7 @@ class PluginManager:
|
|||||||
|
|
||||||
jinja_setup(self.web_app)
|
jinja_setup(self.web_app)
|
||||||
|
|
||||||
async def startup(_):
|
async def startup(_: Application):
|
||||||
if self.settings.getSetting("cef_forward", False):
|
if self.settings.getSetting("cef_forward", False):
|
||||||
self.loop.create_task(service_start(REMOTE_DEBUGGER_UNIT))
|
self.loop.create_task(service_start(REMOTE_DEBUGGER_UNIT))
|
||||||
else:
|
else:
|
||||||
@@ -84,16 +85,16 @@ class PluginManager:
|
|||||||
self.web_app.add_routes([get("/auth/token", self.get_auth_token)])
|
self.web_app.add_routes([get("/auth/token", self.get_auth_token)])
|
||||||
|
|
||||||
for route in list(self.web_app.router.routes()):
|
for route in list(self.web_app.router.routes()):
|
||||||
self.cors.add(route)
|
self.cors.add(route) # type: ignore
|
||||||
self.web_app.add_routes([static("/static", path.join(path.dirname(__file__), 'static'))])
|
self.web_app.add_routes([static("/static", path.join(path.dirname(__file__), 'static'))])
|
||||||
self.web_app.add_routes([static("/legacy", path.join(path.dirname(__file__), 'legacy'))])
|
self.web_app.add_routes([static("/legacy", path.join(path.dirname(__file__), 'legacy'))])
|
||||||
|
|
||||||
def exception_handler(self, loop, context):
|
def exception_handler(self, loop: AbstractEventLoop, context: Dict[str, str]):
|
||||||
if context["message"] == "Unclosed connection":
|
if context["message"] == "Unclosed connection":
|
||||||
return
|
return
|
||||||
loop.default_exception_handler(context)
|
loop.default_exception_handler(context)
|
||||||
|
|
||||||
async def get_auth_token(self, request):
|
async def get_auth_token(self, request: Request):
|
||||||
return Response(text=get_csrf_token())
|
return Response(text=get_csrf_token())
|
||||||
|
|
||||||
async def load_plugins(self):
|
async def load_plugins(self):
|
||||||
@@ -144,7 +145,7 @@ class PluginManager:
|
|||||||
# This is because of https://github.com/aio-libs/aiohttp/blob/3ee7091b40a1bc58a8d7846e7878a77640e96996/aiohttp/client_ws.py#L321
|
# This is because of https://github.com/aio-libs/aiohttp/blob/3ee7091b40a1bc58a8d7846e7878a77640e96996/aiohttp/client_ws.py#L321
|
||||||
logger.info("CEF has disconnected...")
|
logger.info("CEF has disconnected...")
|
||||||
# At this point the loop starts again and we connect to the freshly started Steam client once it is ready.
|
# At this point the loop starts again and we connect to the freshly started Steam client once it is ready.
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logger.error("Exception while reading page events " + format_exc())
|
logger.error("Exception while reading page events " + format_exc())
|
||||||
await tab.close_websocket()
|
await tab.close_websocket()
|
||||||
pass
|
pass
|
||||||
@@ -154,7 +155,7 @@ class PluginManager:
|
|||||||
# logger.info("Plugin loader isn't present in Steam anymore, reinjecting...")
|
# logger.info("Plugin loader isn't present in Steam anymore, reinjecting...")
|
||||||
# await self.inject_javascript(tab)
|
# await self.inject_javascript(tab)
|
||||||
|
|
||||||
async def inject_javascript(self, tab: Tab, first=False, request=None):
|
async def inject_javascript(self, tab: Tab, first: bool=False, request: Request|None=None):
|
||||||
logger.info("Loading Decky frontend!")
|
logger.info("Loading Decky frontend!")
|
||||||
try:
|
try:
|
||||||
if first:
|
if first:
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ class PluginWrapper:
|
|||||||
self.plugin_path = plugin_path
|
self.plugin_path = plugin_path
|
||||||
self.plugin_directory = plugin_directory
|
self.plugin_directory = plugin_directory
|
||||||
self.method_call_lock = Lock()
|
self.method_call_lock = Lock()
|
||||||
self.socket = LocalSocket(self._on_new_message)
|
self.socket: LocalSocket = LocalSocket(self._on_new_message)
|
||||||
|
|
||||||
self.version = None
|
self.version = None
|
||||||
|
|
||||||
|
|||||||
+18
-9
@@ -1,23 +1,31 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
|
||||||
from asyncio import sleep
|
from asyncio import sleep
|
||||||
from ensurepip import version
|
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import getcwd, path, remove
|
from os import getcwd, path, remove
|
||||||
|
from typing import List, TypedDict
|
||||||
|
from backend.main import PluginManager
|
||||||
from localplatform import chmod, service_restart, ON_LINUX, get_keep_systemd_service, get_selinux
|
from localplatform import chmod, service_restart, ON_LINUX, get_keep_systemd_service, get_selinux
|
||||||
|
|
||||||
from aiohttp import ClientSession, web
|
from aiohttp import ClientSession, web
|
||||||
|
|
||||||
import helpers
|
import helpers
|
||||||
from injector import get_gamepadui_tab, inject_to_tab
|
from injector import get_gamepadui_tab
|
||||||
from settings import SettingsManager
|
from settings import SettingsManager
|
||||||
|
|
||||||
logger = getLogger("Updater")
|
logger = getLogger("Updater")
|
||||||
|
|
||||||
|
class RemoteVerAsset(TypedDict):
|
||||||
|
name: str
|
||||||
|
browser_download_url: str
|
||||||
|
class RemoteVer(TypedDict):
|
||||||
|
tag_name: str
|
||||||
|
prerelease: bool
|
||||||
|
assets: List[RemoteVerAsset]
|
||||||
|
|
||||||
class Updater:
|
class Updater:
|
||||||
def __init__(self, context) -> None:
|
def __init__(self, context: PluginManager) -> None:
|
||||||
self.context = context
|
self.context = context
|
||||||
self.settings = self.context.settings
|
self.settings = self.context.settings
|
||||||
# Exposes updater methods to frontend
|
# Exposes updater methods to frontend
|
||||||
@@ -28,8 +36,8 @@ class Updater:
|
|||||||
"do_restart": self.do_restart,
|
"do_restart": self.do_restart,
|
||||||
"check_for_updates": self.check_for_updates
|
"check_for_updates": self.check_for_updates
|
||||||
}
|
}
|
||||||
self.remoteVer = None
|
self.remoteVer: RemoteVer | None = None
|
||||||
self.allRemoteVers = None
|
self.allRemoteVers: List[RemoteVer] = []
|
||||||
self.localVer = helpers.get_loader_version()
|
self.localVer = helpers.get_loader_version()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -44,7 +52,7 @@ class Updater:
|
|||||||
])
|
])
|
||||||
context.loop.create_task(self.version_reloader())
|
context.loop.create_task(self.version_reloader())
|
||||||
|
|
||||||
async def _handle_server_method_call(self, request):
|
async def _handle_server_method_call(self, request: web.Request):
|
||||||
method_name = request.match_info["method_name"]
|
method_name = request.match_info["method_name"]
|
||||||
try:
|
try:
|
||||||
args = await request.json()
|
args = await request.json()
|
||||||
@@ -52,7 +60,7 @@ class Updater:
|
|||||||
args = {}
|
args = {}
|
||||||
res = {}
|
res = {}
|
||||||
try:
|
try:
|
||||||
r = await self.updater_methods[method_name](**args)
|
r = await self.updater_methods[method_name](**args) # type: ignore
|
||||||
res["result"] = r
|
res["result"] = r
|
||||||
res["success"] = True
|
res["success"] = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -105,7 +113,7 @@ class Updater:
|
|||||||
selectedBranch = self.get_branch(self.context.settings)
|
selectedBranch = self.get_branch(self.context.settings)
|
||||||
async with ClientSession() as web:
|
async with ClientSession() as web:
|
||||||
async with web.request("GET", "https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases", ssl=helpers.get_ssl_context()) as res:
|
async with web.request("GET", "https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases", ssl=helpers.get_ssl_context()) as res:
|
||||||
remoteVersions = await res.json()
|
remoteVersions: List[RemoteVer] = await res.json()
|
||||||
if selectedBranch == 0:
|
if selectedBranch == 0:
|
||||||
logger.debug("release type: release")
|
logger.debug("release type: release")
|
||||||
remoteVersions = list(filter(lambda ver: ver["tag_name"].startswith("v") and not ver["prerelease"] and not ver["tag_name"].find("-pre") > 0 and ver["tag_name"], remoteVersions))
|
remoteVersions = list(filter(lambda ver: ver["tag_name"].startswith("v") and not ver["prerelease"] and not ver["tag_name"].find("-pre") > 0 and ver["tag_name"], remoteVersions))
|
||||||
@@ -142,6 +150,7 @@ class Updater:
|
|||||||
|
|
||||||
async def do_update(self):
|
async def do_update(self):
|
||||||
logger.debug("Starting update.")
|
logger.debug("Starting update.")
|
||||||
|
assert self.remoteVer
|
||||||
version = self.remoteVer["tag_name"]
|
version = self.remoteVer["tag_name"]
|
||||||
download_url = None
|
download_url = None
|
||||||
download_filename = "PluginLoader" if ON_LINUX else "PluginLoader.exe"
|
download_filename = "PluginLoader" if ON_LINUX else "PluginLoader.exe"
|
||||||
|
|||||||
+42
-30
@@ -1,3 +1,4 @@
|
|||||||
|
from os import stat_result
|
||||||
import uuid
|
import uuid
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
from os.path import splitext
|
from os.path import splitext
|
||||||
@@ -5,12 +6,12 @@ import re
|
|||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from stat import FILE_ATTRIBUTE_HIDDEN # type: ignore
|
from stat import FILE_ATTRIBUTE_HIDDEN # type: ignore
|
||||||
|
|
||||||
from asyncio import start_server, gather, open_connection
|
from asyncio import StreamReader, StreamWriter, start_server, gather, open_connection
|
||||||
from aiohttp import ClientSession, web
|
from aiohttp import ClientSession, web
|
||||||
from typing import Dict
|
from typing import Callable, Coroutine, Dict, Any, List, TypedDict
|
||||||
|
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from backend.browser import PluginInstallType
|
from backend.browser import PluginInstallRequest, PluginInstallType
|
||||||
from backend.main import PluginManager
|
from backend.main import PluginManager
|
||||||
from injector import inject_to_tab, get_gamepadui_tab, close_old_tabs, get_tab
|
from injector import inject_to_tab, get_gamepadui_tab, close_old_tabs, get_tab
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -18,10 +19,15 @@ from localplatform import ON_WINDOWS
|
|||||||
import helpers
|
import helpers
|
||||||
from localplatform import service_stop, service_start, get_home_path, get_username
|
from localplatform import service_stop, service_start, get_home_path, get_username
|
||||||
|
|
||||||
|
class FilePickerObj(TypedDict):
|
||||||
|
file: Path
|
||||||
|
filest: stat_result
|
||||||
|
is_dir: bool
|
||||||
|
|
||||||
class Utilities:
|
class Utilities:
|
||||||
def __init__(self, context: PluginManager) -> None:
|
def __init__(self, context: PluginManager) -> None:
|
||||||
self.context = context
|
self.context = context
|
||||||
self.util_methods: Dict[] = {
|
self.util_methods: Dict[str, Callable[..., Coroutine[Any, Any, Any]]] = {
|
||||||
"ping": self.ping,
|
"ping": self.ping,
|
||||||
"http_request": self.http_request,
|
"http_request": self.http_request,
|
||||||
"install_plugin": self.install_plugin,
|
"install_plugin": self.install_plugin,
|
||||||
@@ -54,7 +60,7 @@ class Utilities:
|
|||||||
web.post("/methods/{method_name}", self._handle_server_method_call)
|
web.post("/methods/{method_name}", self._handle_server_method_call)
|
||||||
])
|
])
|
||||||
|
|
||||||
async def _handle_server_method_call(self, request):
|
async def _handle_server_method_call(self, request: web.Request):
|
||||||
method_name = request.match_info["method_name"]
|
method_name = request.match_info["method_name"]
|
||||||
try:
|
try:
|
||||||
args = await request.json()
|
args = await request.json()
|
||||||
@@ -70,7 +76,7 @@ class Utilities:
|
|||||||
res["success"] = False
|
res["success"] = False
|
||||||
return web.json_response(res)
|
return web.json_response(res)
|
||||||
|
|
||||||
async def install_plugin(self, artifact="", name="No name", version="dev", hash=False, install_type=PluginInstallType.INSTALL):
|
async def install_plugin(self, artifact: str="", name: str="No name", version: str="dev", hash: str="", install_type: PluginInstallType=PluginInstallType.INSTALL):
|
||||||
return await self.context.plugin_browser.request_plugin_install(
|
return await self.context.plugin_browser.request_plugin_install(
|
||||||
artifact=artifact,
|
artifact=artifact,
|
||||||
name=name,
|
name=name,
|
||||||
@@ -79,21 +85,21 @@ class Utilities:
|
|||||||
install_type=install_type
|
install_type=install_type
|
||||||
)
|
)
|
||||||
|
|
||||||
async def install_plugins(self, requests):
|
async def install_plugins(self, requests: List[PluginInstallRequest]):
|
||||||
return await self.context.plugin_browser.request_multiple_plugin_installs(
|
return await self.context.plugin_browser.request_multiple_plugin_installs(
|
||||||
requests=requests
|
requests=requests
|
||||||
)
|
)
|
||||||
|
|
||||||
async def confirm_plugin_install(self, request_id):
|
async def confirm_plugin_install(self, request_id: str):
|
||||||
return await self.context.plugin_browser.confirm_plugin_install(request_id)
|
return await self.context.plugin_browser.confirm_plugin_install(request_id)
|
||||||
|
|
||||||
def cancel_plugin_install(self, request_id):
|
async def cancel_plugin_install(self, request_id: str):
|
||||||
return self.context.plugin_browser.cancel_plugin_install(request_id)
|
return self.context.plugin_browser.cancel_plugin_install(request_id)
|
||||||
|
|
||||||
async def uninstall_plugin(self, name):
|
async def uninstall_plugin(self, name: str):
|
||||||
return await self.context.plugin_browser.uninstall_plugin(name)
|
return await self.context.plugin_browser.uninstall_plugin(name)
|
||||||
|
|
||||||
async def http_request(self, method="", url="", **kwargs):
|
async def http_request(self, method: str="", url: str="", **kwargs: Any):
|
||||||
async with ClientSession() as web:
|
async with ClientSession() as web:
|
||||||
res = await web.request(method, url, ssl=helpers.get_ssl_context(), **kwargs)
|
res = await web.request(method, url, ssl=helpers.get_ssl_context(), **kwargs)
|
||||||
text = await res.text()
|
text = await res.text()
|
||||||
@@ -103,12 +109,13 @@ class Utilities:
|
|||||||
"body": text
|
"body": text
|
||||||
}
|
}
|
||||||
|
|
||||||
async def ping(self, **kwargs):
|
async def ping(self, **kwargs: Any):
|
||||||
return "pong"
|
return "pong"
|
||||||
|
|
||||||
async def execute_in_tab(self, tab, run_async, code):
|
async def execute_in_tab(self, tab: str, run_async: bool, code: str):
|
||||||
try:
|
try:
|
||||||
result = await inject_to_tab(tab, code, run_async)
|
result = await inject_to_tab(tab, code, run_async)
|
||||||
|
assert result
|
||||||
if "exceptionDetails" in result["result"]:
|
if "exceptionDetails" in result["result"]:
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
@@ -125,7 +132,7 @@ class Utilities:
|
|||||||
"result": e
|
"result": e
|
||||||
}
|
}
|
||||||
|
|
||||||
async def inject_css_into_tab(self, tab, style):
|
async def inject_css_into_tab(self, tab: str, style: str):
|
||||||
try:
|
try:
|
||||||
css_id = str(uuid.uuid4())
|
css_id = str(uuid.uuid4())
|
||||||
|
|
||||||
@@ -139,7 +146,7 @@ class Utilities:
|
|||||||
}})()
|
}})()
|
||||||
""", False)
|
""", False)
|
||||||
|
|
||||||
if "exceptionDetails" in result["result"]:
|
if result and "exceptionDetails" in result["result"]:
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
"result": result["result"]
|
"result": result["result"]
|
||||||
@@ -155,7 +162,7 @@ class Utilities:
|
|||||||
"result": e
|
"result": e
|
||||||
}
|
}
|
||||||
|
|
||||||
async def remove_css_from_tab(self, tab, css_id):
|
async def remove_css_from_tab(self, tab: str, css_id: str):
|
||||||
try:
|
try:
|
||||||
result = await inject_to_tab(tab,
|
result = await inject_to_tab(tab,
|
||||||
f"""
|
f"""
|
||||||
@@ -167,7 +174,7 @@ class Utilities:
|
|||||||
}})()
|
}})()
|
||||||
""", False)
|
""", False)
|
||||||
|
|
||||||
if "exceptionDetails" in result["result"]:
|
if result and "exceptionDetails" in result["result"]:
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": False,
|
||||||
"result": result
|
"result": result
|
||||||
@@ -182,10 +189,10 @@ class Utilities:
|
|||||||
"result": e
|
"result": e
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_setting(self, key, default):
|
async def get_setting(self, key: str, default: Any):
|
||||||
return self.context.settings.getSetting(key, default)
|
return self.context.settings.getSetting(key, default)
|
||||||
|
|
||||||
async def set_setting(self, key, value):
|
async def set_setting(self, key: str, value: Any):
|
||||||
return self.context.settings.setSetting(key, value)
|
return self.context.settings.setSetting(key, value)
|
||||||
|
|
||||||
async def allow_remote_debugging(self):
|
async def allow_remote_debugging(self):
|
||||||
@@ -210,17 +217,18 @@ class Utilities:
|
|||||||
if path == None:
|
if path == None:
|
||||||
path = get_home_path()
|
path = get_home_path()
|
||||||
|
|
||||||
path = Path(path).resolve()
|
path_obj = Path(path).resolve()
|
||||||
|
|
||||||
files, folders = [], []
|
files: List[FilePickerObj] = []
|
||||||
|
folders: List[FilePickerObj] = []
|
||||||
|
|
||||||
#Resolving all files/folders in the requested directory
|
#Resolving all files/folders in the requested directory
|
||||||
for file in path.iterdir():
|
for file in path_obj.iterdir():
|
||||||
if file.exists():
|
if file.exists():
|
||||||
filest = file.stat()
|
filest = file.stat()
|
||||||
is_hidden = file.name.startswith('.')
|
is_hidden = file.name.startswith('.')
|
||||||
if ON_WINDOWS and not is_hidden:
|
if ON_WINDOWS and not is_hidden:
|
||||||
is_hidden = bool(filest.st_file_attributes & FILE_ATTRIBUTE_HIDDEN)
|
is_hidden = bool(filest.st_file_attributes & FILE_ATTRIBUTE_HIDDEN) # type: ignore
|
||||||
if include_folders and file.is_dir():
|
if include_folders and file.is_dir():
|
||||||
if (is_hidden and include_hidden) or not is_hidden:
|
if (is_hidden and include_hidden) or not is_hidden:
|
||||||
folders.append({"file": file, "filest": filest, "is_dir": True})
|
folders.append({"file": file, "filest": filest, "is_dir": True})
|
||||||
@@ -234,9 +242,9 @@ class Utilities:
|
|||||||
if filter_for is not None:
|
if filter_for is not None:
|
||||||
try:
|
try:
|
||||||
if re.compile(filter_for):
|
if re.compile(filter_for):
|
||||||
files = filter(lambda file: re.search(filter_for, file.name) != None, files)
|
files = list(filter(lambda file: re.search(filter_for, file["file"].name) != None, files))
|
||||||
except re.error:
|
except re.error:
|
||||||
files = filter(lambda file: file.name.find(filter_for) != -1, files)
|
files = list(filter(lambda file: file["file"].name.find(filter_for) != -1, files))
|
||||||
|
|
||||||
# Ordering logic
|
# Ordering logic
|
||||||
ord_arg = order_by.split("_")
|
ord_arg = order_by.split("_")
|
||||||
@@ -256,6 +264,9 @@ class Utilities:
|
|||||||
files.sort(key=lambda x: x['filest'].st_size, reverse = not rev)
|
files.sort(key=lambda x: x['filest'].st_size, reverse = not rev)
|
||||||
# Folders has no file size, order by name instead
|
# Folders has no file size, order by name instead
|
||||||
folders.sort(key=lambda x: x['file'].name.casefold())
|
folders.sort(key=lambda x: x['file'].name.casefold())
|
||||||
|
case _:
|
||||||
|
files.sort(key=lambda x: x['file'].name.casefold(), reverse = rev)
|
||||||
|
folders.sort(key=lambda x: x['file'].name.casefold(), reverse = rev)
|
||||||
|
|
||||||
#Constructing the final file list, folders first
|
#Constructing the final file list, folders first
|
||||||
all = [{
|
all = [{
|
||||||
@@ -275,14 +286,14 @@ class Utilities:
|
|||||||
|
|
||||||
|
|
||||||
# Based on https://stackoverflow.com/a/46422554/13174603
|
# Based on https://stackoverflow.com/a/46422554/13174603
|
||||||
def start_rdt_proxy(self, ip, port):
|
def start_rdt_proxy(self, ip: str, port: int):
|
||||||
async def pipe(reader, writer):
|
async def pipe(reader: StreamReader, writer: StreamWriter):
|
||||||
try:
|
try:
|
||||||
while not reader.at_eof():
|
while not reader.at_eof():
|
||||||
writer.write(await reader.read(2048))
|
writer.write(await reader.read(2048))
|
||||||
finally:
|
finally:
|
||||||
writer.close()
|
writer.close()
|
||||||
async def handle_client(local_reader, local_writer):
|
async def handle_client(local_reader: StreamReader, local_writer: StreamWriter):
|
||||||
try:
|
try:
|
||||||
remote_reader, remote_writer = await open_connection(
|
remote_reader, remote_writer = await open_connection(
|
||||||
ip, port)
|
ip, port)
|
||||||
@@ -298,6 +309,7 @@ class Utilities:
|
|||||||
def stop_rdt_proxy(self):
|
def stop_rdt_proxy(self):
|
||||||
if self.rdt_proxy_server:
|
if self.rdt_proxy_server:
|
||||||
self.rdt_proxy_server.close()
|
self.rdt_proxy_server.close()
|
||||||
|
if self.rdt_proxy_task:
|
||||||
self.rdt_proxy_task.cancel()
|
self.rdt_proxy_task.cancel()
|
||||||
|
|
||||||
async def _enable_rdt(self):
|
async def _enable_rdt(self):
|
||||||
@@ -348,11 +360,11 @@ class Utilities:
|
|||||||
await tab.evaluate_js("location.reload();", False, True, False)
|
await tab.evaluate_js("location.reload();", False, True, False)
|
||||||
self.logger.info("React DevTools disabled")
|
self.logger.info("React DevTools disabled")
|
||||||
|
|
||||||
async def get_user_info(self) -> dict:
|
async def get_user_info(self) -> Dict[str, str]:
|
||||||
return {
|
return {
|
||||||
"username": get_username(),
|
"username": get_username(),
|
||||||
"path": get_home_path()
|
"path": get_home_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
async def get_tab_id(self, name):
|
async def get_tab_id(self, name: str):
|
||||||
return (await get_tab(name)).id
|
return (await get_tab(name)).id
|
||||||
|
|||||||
Reference in New Issue
Block a user