mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-11 21:22:01 +00:00
Download Remote Binaries during Store Install (#177)
* Download Remote Binaries during store install. Fix Manual Install Modal Type * Use Unix Line endings. (Thanks WSL) * Fix Merge Commit with main branch.
This commit is contained in:
+49
-2
@@ -8,14 +8,14 @@ from concurrent.futures import ProcessPoolExecutor
|
|||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import path, rename, listdir
|
from os import R_OK, W_OK, path, rename, listdir, access, mkdir
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
from time import time
|
from time import time
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
# Local modules
|
# Local modules
|
||||||
from helpers import get_ssl_context, get_user, get_user_group
|
from helpers import get_ssl_context, get_user, get_user_group, download_remote_binary_to_path
|
||||||
from injector import get_tab, inject_to_tab
|
from injector import get_tab, inject_to_tab
|
||||||
|
|
||||||
logger = getLogger("Browser")
|
logger = getLogger("Browser")
|
||||||
@@ -48,6 +48,49 @@ class PluginBrowser:
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
async def _download_remote_binaries_for_plugin_with_name(self, plugin_name):
|
||||||
|
rv = False
|
||||||
|
try:
|
||||||
|
pluginBasePath = path.join(self.plugin_path, plugin_name)
|
||||||
|
packageJsonPath = path.join(pluginBasePath, 'package.json')
|
||||||
|
pluginBinPath = path.join(pluginBasePath, 'bin')
|
||||||
|
|
||||||
|
if access(packageJsonPath, R_OK):
|
||||||
|
with open(packageJsonPath, 'r') as f:
|
||||||
|
packageJson = json.load(f)
|
||||||
|
if len(packageJson["remote_binary"]) > 0:
|
||||||
|
# create bin directory if needed.
|
||||||
|
rc=call(["chmod", "-R", "777", pluginBasePath])
|
||||||
|
if access(pluginBasePath, W_OK):
|
||||||
|
|
||||||
|
if not path.exists(pluginBinPath):
|
||||||
|
mkdir(pluginBinPath)
|
||||||
|
|
||||||
|
if not access(pluginBinPath, W_OK):
|
||||||
|
rc=call(["chmod", "-R", "777", pluginBinPath])
|
||||||
|
|
||||||
|
rv = True
|
||||||
|
for remoteBinary in packageJson["remote_binary"]:
|
||||||
|
# Required Fields. If any Remote Binary is missing these fail the install.
|
||||||
|
binName = remoteBinary["name"]
|
||||||
|
binURL = remoteBinary["url"]
|
||||||
|
binHash = remoteBinary["sha256hash"]
|
||||||
|
if not await download_remote_binary_to_path(binURL, binHash, path.join(pluginBinPath, binName)):
|
||||||
|
rv = False
|
||||||
|
raise Exception(f"Error Downloading Remote Binary {binName}@{binURL} with hash {binHash} to {path.join(pluginBinPath, binName)}")
|
||||||
|
|
||||||
|
code_chown = call(["chown", "-R", get_user()+":"+get_user_group(), self.plugin_path])
|
||||||
|
rc=call(["chmod", "-R", "555", pluginBasePath])
|
||||||
|
else:
|
||||||
|
rv = True
|
||||||
|
logger.debug(f"No Remote Binaries to Download")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
rv = False
|
||||||
|
logger.debug(str(e))
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
def find_plugin_folder(self, name):
|
def find_plugin_folder(self, name):
|
||||||
for folder in listdir(self.plugin_path):
|
for folder in listdir(self.plugin_path):
|
||||||
try:
|
try:
|
||||||
@@ -99,6 +142,8 @@ class PluginBrowser:
|
|||||||
res_zip = BytesIO(data)
|
res_zip = BytesIO(data)
|
||||||
logger.debug("Unzipping...")
|
logger.debug("Unzipping...")
|
||||||
ret = self._unzip_to_plugin_dir(res_zip, name, hash)
|
ret = self._unzip_to_plugin_dir(res_zip, name, hash)
|
||||||
|
if ret:
|
||||||
|
ret = await self._download_remote_binaries_for_plugin_with_name(name)
|
||||||
if ret:
|
if ret:
|
||||||
logger.info(f"Installed {name} (Version: {version})")
|
logger.info(f"Installed {name} (Version: {version})")
|
||||||
plugin_dir = self.find_plugin_folder(name)
|
plugin_dir = self.find_plugin_folder(name)
|
||||||
@@ -108,6 +153,8 @@ class PluginBrowser:
|
|||||||
await sleep(1)
|
await sleep(1)
|
||||||
self.loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_dir)
|
self.loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_dir)
|
||||||
# await inject_to_tab("SP", "window.syncDeckyPlugins()")
|
# await inject_to_tab("SP", "window.syncDeckyPlugins()")
|
||||||
|
else:
|
||||||
|
logger.fatal(f"Failed Downloading Remote Binaries")
|
||||||
else:
|
else:
|
||||||
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
|
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
|
||||||
if self.loader.watcher:
|
if self.loader.watcher:
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import re
|
|||||||
import ssl
|
import ssl
|
||||||
import subprocess
|
import subprocess
|
||||||
import uuid
|
import uuid
|
||||||
|
import os
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
from hashlib import sha256
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
import certifi
|
import certifi
|
||||||
from aiohttp.web import Response, middleware
|
from aiohttp.web import Response, middleware
|
||||||
|
from aiohttp import ClientSession
|
||||||
|
|
||||||
REMOTE_DEBUGGER_UNIT = "steam-web-debug-portforward.service"
|
REMOTE_DEBUGGER_UNIT = "steam-web-debug-portforward.service"
|
||||||
|
|
||||||
@@ -83,6 +87,30 @@ def get_homebrew_path(home_path = None) -> str:
|
|||||||
return str(home_path+"/homebrew")
|
return str(home_path+"/homebrew")
|
||||||
# return str(home_path+"/homebrew")
|
# return str(home_path+"/homebrew")
|
||||||
|
|
||||||
|
# Download Remote Binaries to local Plugin
|
||||||
|
async def download_remote_binary_to_path(url, binHash, path) -> bool:
|
||||||
|
rv = False
|
||||||
|
try:
|
||||||
|
if os.access(os.path.dirname(path), os.W_OK):
|
||||||
|
async with ClientSession() as client:
|
||||||
|
res = await client.get(url, ssl=get_ssl_context())
|
||||||
|
if res.status == 200:
|
||||||
|
data = BytesIO(await res.read())
|
||||||
|
remoteHash = sha256(data.getbuffer()).hexdigest()
|
||||||
|
if binHash == remoteHash:
|
||||||
|
data.seek(0)
|
||||||
|
with open(path, 'wb') as f:
|
||||||
|
f.write(data.getbuffer())
|
||||||
|
rv = True
|
||||||
|
else:
|
||||||
|
raise Exception(f"Fatal Error: Hash Mismatch for remote binary {path}@{url}")
|
||||||
|
else:
|
||||||
|
rv = False
|
||||||
|
except:
|
||||||
|
rv = False
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
async def is_systemd_unit_active(unit_name: str) -> bool:
|
async def is_systemd_unit_active(unit_name: str) -> bool:
|
||||||
res = subprocess.run(["systemctl", "is-active", unit_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
res = subprocess.run(["systemctl", "is-active", unit_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
return res.returncode == 0
|
return res.returncode == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user