diff options
| -rw-r--r-- | backend/decky_loader/updater.py | 24 | ||||
| -rw-r--r-- | backend/locales/en-US.json | 4 | ||||
| -rw-r--r-- | frontend/src/components/settings/pages/general/Updater.tsx | 7 | ||||
| -rw-r--r-- | frontend/src/components/settings/pages/testing/index.tsx | 29 | ||||
| -rw-r--r-- | frontend/src/plugin-loader.tsx | 3 |
5 files changed, 51 insertions, 16 deletions
diff --git a/backend/decky_loader/updater.py b/backend/decky_loader/updater.py index 268ab240..1957c59d 100644 --- a/backend/decky_loader/updater.py +++ b/backend/decky_loader/updater.py @@ -137,27 +137,30 @@ class Updater: pass await sleep(60 * 60 * 6) # 6 hours - async def download_decky_binary(self, download_url: str, version: str, is_zip: bool = False): + async def download_decky_binary(self, download_url: str, version: str, is_zip: bool = False, size_in_bytes: int | None = None): download_filename = "PluginLoader" if ON_LINUX else "PluginLoader.exe" download_temp_filename = download_filename + ".new" tab = await get_gamepadui_tab() await tab.open_websocket() + if size_in_bytes == None: + size_in_bytes = 26214400 # 25MiB, a reasonable overestimate (19.6MiB as of 2024/02/25) + async with ClientSession() as web: logger.debug("Downloading binary") async with web.request("GET", download_url, ssl=helpers.get_ssl_context(), allow_redirects=True) as res: - total = int(res.headers.get('content-length', 0)) + total = int(res.headers.get('content-length', size_in_bytes)) + if total == 0: total = 1 with open(path.join(getcwd(), download_temp_filename), "wb") as out: progress = 0 raw = 0 async for c in res.content.iter_chunked(512): out.write(c) - if total != 0: - raw += len(c) - new_progress = round((raw / total) * 100) - if progress != new_progress: - self.context.loop.create_task(self.context.ws.emit("updater/update_download_percentage", new_progress)) - progress = new_progress + raw += len(c) + new_progress = round((raw / total) * 100) + if progress != new_progress: + self.context.loop.create_task(self.context.ws.emit("updater/update_download_percentage", new_progress)) + progress = new_progress with open(path.join(getcwd(), ".loader.version"), "w", encoding="utf-8") as out: out.write(version) @@ -277,9 +280,10 @@ class Updater: #If the request found at least one artifact to download... if int(jresp['total_count']) != 0: # this assumes that the artifact we want is the first one! - down_link = f"https://nightly.link/SteamDeckHomebrew/decky-loader/actions/artifacts/{jresp['artifacts'][0]['id']}.zip" + artifact = jresp['artifacts'][0] + down_link = f"https://nightly.link/SteamDeckHomebrew/decky-loader/actions/artifacts/{artifact['id']}.zip" #Then fetch it and restart itself - await self.download_decky_binary(down_link, f'PR-{pr_id}' , True) + await self.download_decky_binary(down_link, f'PR-{pr_id}', is_zip=True, size_in_bytes=artifact.get('size_in_bytes',None)) else: logger.error("workflow run not found", str(works)) raise Exception("Workflow run not found.") diff --git a/backend/locales/en-US.json b/backend/locales/en-US.json index fe544dea..e1e0b9ea 100644 --- a/backend/locales/en-US.json +++ b/backend/locales/en-US.json @@ -267,6 +267,8 @@ "Testing": { "download": "Download", "header": "The following versions of Decky Loader are built from open third-party Pull Requests. The Decky Loader team has not verified their functionality or security, and they may be outdated.", - "loading": "Loading open Pull Requests..." + "loading": "Loading open Pull Requests...", + "error": "Error Installing PR", + "start_download_toast": "Downloading PR #{{id}}" } } diff --git a/frontend/src/components/settings/pages/general/Updater.tsx b/frontend/src/components/settings/pages/general/Updater.tsx index 3c7e53f1..9fcc2dd3 100644 --- a/frontend/src/components/settings/pages/general/Updater.tsx +++ b/frontend/src/components/settings/pages/general/Updater.tsx @@ -66,7 +66,7 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n } export default function UpdaterSettings() { - const { isLoaderUpdating, setIsLoaderUpdating, versionInfo, setVersionInfo } = useDeckyState(); + const { isLoaderUpdating, versionInfo, setVersionInfo } = useDeckyState(); const [checkingForUpdates, setCheckingForUpdates] = useState<boolean>(false); const [updateProgress, setUpdateProgress] = useState<number>(-1); @@ -77,7 +77,6 @@ export default function UpdaterSettings() { useEffect(() => { const a = DeckyBackend.addEventListener('updater/update_download_percentage', (percentage) => { setUpdateProgress(percentage); - setIsLoaderUpdating(true); }); const b = DeckyBackend.addEventListener('updater/finish_download', () => { @@ -86,8 +85,8 @@ export default function UpdaterSettings() { }); return () => { - DeckyBackend.removeEventListener('frontend/update_download_percentage', a); - DeckyBackend.removeEventListener('frontend/finish_download', b); + DeckyBackend.removeEventListener('updater/update_download_percentage', a); + DeckyBackend.removeEventListener('updater/finish_download', b); }; }, []); diff --git a/frontend/src/components/settings/pages/testing/index.tsx b/frontend/src/components/settings/pages/testing/index.tsx index 4fe0f240..2467f3c5 100644 --- a/frontend/src/components/settings/pages/testing/index.tsx +++ b/frontend/src/components/settings/pages/testing/index.tsx @@ -5,6 +5,7 @@ import { Field, Focusable, Navigation, + ProgressBar, SteamSpinner, } from 'decky-frontend-lib'; import { useEffect, useState } from 'react'; @@ -26,8 +27,11 @@ const downloadTestingVersion = DeckyBackend.callable<[pr_id: number, sha: string export default function TestingVersionList() { const { t } = useTranslation(); + const [testingVersions, setTestingVersions] = useState<TestingVersion[]>([]); const [loading, setLoading] = useState<boolean>(true); + const [updateProgress, setUpdateProgress] = useState<number | null>(null); + const [reloading, setReloading] = useState<boolean>(false); useEffect(() => { (async () => { @@ -36,6 +40,21 @@ export default function TestingVersionList() { })(); }, []); + useEffect(() => { + const a = DeckyBackend.addEventListener('updater/update_download_percentage', (percentage) => { + setUpdateProgress(percentage); + }); + + const b = DeckyBackend.addEventListener('updater/finish_download', () => { + setReloading(true); + }); + + return () => { + DeckyBackend.removeEventListener('updater/update_download_percentage', a); + DeckyBackend.removeEventListener('updater/finish_download', b); + }; + }, []); + if (loading) { return ( <> @@ -54,6 +73,7 @@ export default function TestingVersionList() { return ( <DialogBody> + {updateProgress !== null && <ProgressBar nProgress={updateProgress} indeterminate={reloading} />} <DialogControlsSection> <h4>{t('Testing.header')}</h4> <ul style={{ listStyleType: 'none', padding: '0' }}> @@ -71,11 +91,18 @@ export default function TestingVersionList() { <DialogButton style={{ height: '40px', minWidth: '60px', marginRight: '10px' }} onClick={async () => { + DeckyPluginLoader.toaster.toast({ + title: t('Testing.start_download_toast', { id: version.id }), + body: null, + }); try { await downloadTestingVersion(version.id, version.head_sha); } catch (e) { if (e instanceof Error) { - DeckyPluginLoader.toaster.toast({ title: 'Error Installing PR', body: e.message }); + DeckyPluginLoader.toaster.toast({ + title: t('Testing.error'), + body: `${e.name}: ${e.message}`, + }); } } setSetting('branch', UpdateBranch.Testing); diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index d9b1211e..7a87253f 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -78,6 +78,9 @@ class PluginLoader extends Logger { 'loader/add_multiple_plugins_install_prompt', this.addMultiplePluginsInstallPrompt.bind(this), ); + DeckyBackend.addEventListener('updater/update_download_percentage', () => { + this.deckyState.setIsLoaderUpdating(true); + }); this.tabsHook.init(); |
