From 74246cf4508695e8e39561042c5e8e0f86db21ea Mon Sep 17 00:00:00 2001 From: tappi287 Date: Sun, 30 Jan 2022 13:16:56 +0100 Subject: [PATCH] implement progress events --- app/app_fn.py | 5 ++-- app/events.py | 43 ++++++++++++++++++++++++++++++++ app/util/custom_app.py | 4 +-- app/util/manifest_worker.py | 35 ++++++++++++++++++++++++-- openvr_fsr_app.py | 5 +++- src/App.vue | 12 +++++++++ src/components/DirManager.vue | 1 + src/components/Main.vue | 23 +++++++++++++++-- src/components/SteamLibTable.vue | 22 +++++++++++++++- src/lang/translations/de.json | 1 + src/lang/translations/en.json | 1 + 11 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 app/events.py diff --git a/app/app_fn.py b/app/app_fn.py index 999f8bd..8d5d264 100644 --- a/app/app_fn.py +++ b/app/app_fn.py @@ -6,7 +6,7 @@ import app import app.mod from app.app_settings import AppSettings -from app.util.manifest_worker import ManifestWorker +from app.util.manifest_worker import ManifestWorker, run_update_steam_apps from app.util.custom_app import create_custom_app, scan_custom_library from app.util.utils import get_name_id @@ -133,7 +133,8 @@ def get_steam_lib_fn(): return json.dumps({'result': False, 'msg': msg}) logging.debug('Acquiring OpenVR Dll locations for %s Steam Apps.', len(steam_apps.keys())) - steam_apps = ManifestWorker.update_steam_apps(steam_apps) + # steam_apps = ManifestWorker.update_steam_apps(steam_apps) + steam_apps = run_update_steam_apps(steam_apps) # -- Restore Mod settings cached on disk and add custom apps cached_steam_apps = AppSettings.load_steam_apps() diff --git a/app/events.py b/app/events.py new file mode 100644 index 0000000..549d473 --- /dev/null +++ b/app/events.py @@ -0,0 +1,43 @@ +import logging +from typing import Optional + +import eel +import gevent +import gevent.event + + +class AppBaseEvent: + @classmethod + def get_nowait(cls) -> Optional[gevent.event.AsyncResult]: + if hasattr(cls, 'result'): + try: + return cls.result.get_nowait() + except gevent.Timeout: + pass + + @classmethod + def reset(cls): + if hasattr(cls, 'event') and hasattr(cls, 'result'): + cls.event.clear() + cls.result = gevent.event.AsyncResult() + + +class ProgressEvent(AppBaseEvent): + event = gevent.event.Event() + result = gevent.event.AsyncResult() + + @classmethod + def set(cls, value): + cls.result.set(value) + + +def progress_update(message): + ProgressEvent.set(message) + + +def app_event_loop(): + progress_event = ProgressEvent.get_nowait() + if progress_event: + logging.debug('Progress event callback to FrontEnd: %s', progress_event) + eel.update_progress(progress_event) + ProgressEvent.reset() diff --git a/app/util/custom_app.py b/app/util/custom_app.py index ad8769f..1309391 100644 --- a/app/util/custom_app.py +++ b/app/util/custom_app.py @@ -4,7 +4,7 @@ import app import app.mod -from app.util.manifest_worker import ManifestWorker +from app.util.manifest_worker import ManifestWorker, run_update_steam_apps from app.util.utils import get_name_id @@ -63,7 +63,7 @@ def scan_custom_library(dir_id: str, path: Path): custom_apps[app_id] = custom_app # -- Scan - custom_apps = ManifestWorker.update_steam_apps(custom_apps) + custom_apps = run_update_steam_apps(custom_apps) # -- Remove empty entries remove_ids = set() diff --git a/app/util/manifest_worker.py b/app/util/manifest_worker.py index cd2a1d7..1cdaf42 100644 --- a/app/util/manifest_worker.py +++ b/app/util/manifest_worker.py @@ -1,11 +1,30 @@ +import threading +from queue import Queue import concurrent.futures import logging import os from pathlib import Path from typing import Optional, List +import gevent + from app.globals import OPEN_VR_DLL, EXE_NAME from app.mod import get_available_mods +from app.events import progress_update + + +def run_update_steam_apps(steam_apps: dict) -> dict: + """ Calls ManifestWorker.update_steam_apps from thread to not block the event loop """ + q = Queue() + t = threading.Thread(target=ManifestWorker.update_steam_apps, args=(steam_apps, q)) + t.start() + + # -- Wait for thread to finish + while t.is_alive(): + gevent.sleep(1) + t.join(timeout=0.1) + + return q.get() class ManifestWorker: @@ -14,7 +33,7 @@ class ManifestWorker: chunk_size = 16 # Number of Manifests per worker @classmethod - def update_steam_apps(cls, steam_apps: dict) -> dict: + def update_steam_apps(cls, steam_apps: dict, queue: Queue = None) -> dict: app_id_list = list(steam_apps.keys()) # -- Split server addresses into chunks for workers @@ -30,8 +49,10 @@ def update_steam_apps(cls, steam_apps: dict) -> dict: [steam_apps.get(app_id) for app_id in id_chunk_ls] ) - logging.debug('Using %s worker threads to search for OpenVr Api Dll in %s SteamApps in %s chunks.', + logging.debug('Using maximum of %s worker threads to search thru %s Apps in %s chunks.', cls.max_workers, len(steam_apps.keys()), len(manifest_ls_chunks)) + progress = 0 + progress_update(f'{progress} / {len(steam_apps.keys())}') with concurrent.futures.ThreadPoolExecutor(max_workers=cls.max_workers) as executor: future_info = { @@ -55,6 +76,14 @@ def update_steam_apps(cls, steam_apps: dict) -> dict: for manifest in manifest_ls: steam_apps[manifest.get('appid')] = manifest + # -- Update Progress + progress += len(manifest_ls) + manifest = manifest_ls[-1:][0] + progress_update(f'{manifest.get("path", " ")[0:2]} {progress} / {len(steam_apps.keys())}') + + if queue is not None: + queue.put(steam_apps) + return steam_apps @staticmethod @@ -71,6 +100,8 @@ def worker(manifest_ls): logging.error('Error reading path for: %s %s', manifest.get('name', 'Unknown'), e) continue + progress_update(f'{manifest["path"][0:2]} {Path(manifest["path"]).stem}') + # -- LookUp OpenVr Api location(s) try: open_vr_dll_path_ls = ManifestWorker.find_open_vr_dll(Path(manifest['path'])) diff --git a/openvr_fsr_app.py b/openvr_fsr_app.py index 76389f6..198f48b 100644 --- a/openvr_fsr_app.py +++ b/openvr_fsr_app.py @@ -6,6 +6,7 @@ import eel from app import expose_app_methods, CLOSE_EVENT +from app.events import app_event_loop from app.app_settings import AppSettings from app.globals import FROZEN, get_version from app.log import setup_logging @@ -74,8 +75,10 @@ def start_eel(): # -- Run until window/tab closed while not CLOSE_EVENT.is_set(): + CLOSE_EVENT.wait(timeout=1) + # --- Event loop --- - CLOSE_EVENT.wait(timeout=10) + app_event_loop() # Capture exception events AppExceptionHook.exception_event_loop() diff --git a/src/App.vue b/src/App.vue index f2776cc..a24d15f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -50,6 +50,13 @@ async function appExceptionFunc (event) { window.dispatchEvent(excEvent) } // --- /> +// --- export default { name: 'App', @@ -76,6 +83,9 @@ export default { resetAdmin: async function () { await window.eel.reset_admin() }, + emitProgressEvent: function (event) { + this.$eventHub.$emit('update-progress', event.detail) + }, }, components: { Updater, @@ -88,11 +98,13 @@ export default { created() { window.addEventListener('beforeunload', this.requestClose) window.addEventListener('app-exception-event', this.setException) + window.addEventListener('update-progress-event', this.emitProgressEvent) }, computed: { }, destroyed() { window.removeEventListener('app-exception-event', this.setException) + window.removeEventListener('update-progress-event', this.emitProgressEvent) } } diff --git a/src/components/DirManager.vue b/src/components/DirManager.vue index 944420c..178b24b 100644 --- a/src/components/DirManager.vue +++ b/src/components/DirManager.vue @@ -140,6 +140,7 @@ export default { if (this.addDir === '') { return } this.$eventHub.$emit('set-busy', true) this.$eventHub.$emit('toggle-dir-manager') + this.$eventHub.$emit('update-progress', '') const r = await getEelJsonObject(window.eel.add_custom_dir(this.addDir)()) if (!r.result) { diff --git a/src/components/Main.vue b/src/components/Main.vue index 875e905..d03bba0 100644 --- a/src/components/Main.vue +++ b/src/components/Main.vue @@ -83,7 +83,15 @@ - + @@ -102,7 +110,7 @@ export default { return { showDirManager: false, showDirManagerMod: true, showDirManagerCustom: true, version: version, - isBusy: false, + isBusy: false, progressMessage: '', appName: process.env.VUE_APP_FRIENDLY_NAME, } }, @@ -120,6 +128,15 @@ export default { solid: true, }) }, + setProgressMessage: function (message) { + // Set progress message + this.progressMessage = message + + // Clear after timeout + setTimeout(() => { + this.setProgressMessage('') + }, 15000) + }, toggleDirManager: function (showMod = true, showCustom = true) { this.showDirManagerMod = showMod; this.showDirManagerCustom = showCustom this.showDirManager = !this.showDirManager @@ -133,11 +150,13 @@ export default { this.$eventHub.$on('make-toast', this.makeToast) this.$eventHub.$on('set-busy', this.setBusy) this.$eventHub.$on('toggle-dir-manager', this.toggleDirManager) + this.$eventHub.$on('update-progress', this.setProgressMessage) }, beforeDestroy() { this.$eventHub.$off('make-toast') this.$eventHub.$off('set-busy') this.$eventHub.$off('toggle-dir-manager') + this.$eventHub.$off('update-progress') }, components: { DirManager, diff --git a/src/components/SteamLibTable.vue b/src/components/SteamLibTable.vue index 1aed704..741b61c 100644 --- a/src/components/SteamLibTable.vue +++ b/src/components/SteamLibTable.vue @@ -33,7 +33,7 @@ - {{ $t('lib.bgSearch') }} + {{ steamLibBusyMessage }} @@ -188,10 +188,20 @@ export default { { key: 'openVr', label: 'Open VR', sortable: true, class: 'text-right' }, ], currentFsrVersion: '', currentFovVersion: '', currentVrpVersion: '', + progressMessage: '' } }, methods: { isBusy: function () { return this.backgroundBusy || this.steamlibBusy }, + setProgressMessage: function (message) { + // Set progress message + this.progressMessage = message + + // Clear after timeout + setTimeout(() => { + this.setProgressMessage('') + }, 10000) + }, updateTableSort(sortByRow = 'name', descending = false) { this.sortBy = sortByRow; this.sortDesc = descending }, @@ -258,6 +268,8 @@ export default { // Scan the disk in the background this.backgroundBusy = true const r = await getEelJsonObject(window.eel.get_steam_lib()()) + this.$eventHub.$emit('update-progress', '') + if (!r.result) { this.$eventHub.$emit('make-toast', 'Could not load Steam Library!', 'danger', 'Steam Library', true, -1) @@ -313,6 +325,12 @@ export default { tableBusy() { return this.isBusy() }, + steamLibBusyMessage() { + if (this.progressMessage !== '') { + return this.$t('lib.bgSearchPre') + this.progressMessage + ' ...' + } + return this.$t('lib.bgSearch') + }, computedList() { let steamTableData = [] for (const appId in this.steamApps) { @@ -327,6 +345,7 @@ export default { created() { this.$eventHub.$on('reload-steam-lib', this.loadSteamLib) this.$eventHub.$on('sort-steam-lib', this.updateTableSort) + this.$eventHub.$on('update-progress', this.setProgressMessage) }, async mounted() { await this.loadSteamLib() @@ -340,6 +359,7 @@ export default { destroyed() { this.$eventHub.$off('reload-steam-lib') this.$eventHub.$off('sort-steam-lib') + this.$eventHub.$off('update-progress') } } diff --git a/src/lang/translations/de.json b/src/lang/translations/de.json index d14e843..de9838e 100644 --- a/src/lang/translations/de.json +++ b/src/lang/translations/de.json @@ -45,6 +45,7 @@ "appId": "App ID", "name": "Anwendungs Name", "sizeGb": "Größe", + "bgSearchPre": "Scanne: ", "bgSearch": "Durchsuche Steam Bibliothek im Hintergrund ...", "busy": "Steam Bibliothek wird gescannt ...", "noResults": "Keine Ergebnisse mit aktuellen Filter Einstellungen", diff --git a/src/lang/translations/en.json b/src/lang/translations/en.json index 6b85079..7b937e1 100644 --- a/src/lang/translations/en.json +++ b/src/lang/translations/en.json @@ -45,6 +45,7 @@ "appId": "App ID", "name": "Name", "sizeGb": "Size", + "bgSearchPre": "Scanning: ", "bgSearch": "Updating SteamLib in the background ...", "busy": "Steam library is being scanned ...", "noResults": "No results with current filter settings",