From 7ae06ff5d8312ea2a3325070cbb13f5e9cb1afe8 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 15 Sep 2023 00:40:28 +0300
Subject: [PATCH] RareCore: Move entitlements request into an independent
worker
Yes, we are back at this. Entitlements are important to have early
as Ubisoft redemption requires them, and they don't depend on anything
else.
* Move config helper initialization into RareCore to make it available
earlier.
---
rare/components/__init__.py | 2 +-
rare/shared/rare_core.py | 73 ++++++++++++++++++---------------
rare/shared/workers/__init__.py | 2 +-
rare/shared/workers/fetch.py | 58 +++++++++++++++-----------
4 files changed, 78 insertions(+), 57 deletions(-)
diff --git a/rare/components/__init__.py b/rare/components/__init__.py
index e76dacf1..f4c9cce4 100644
--- a/rare/components/__init__.py
+++ b/rare/components/__init__.py
@@ -12,7 +12,7 @@ from requests import HTTPError
from rare.components.dialogs.launch_dialog import LaunchDialog
from rare.components.main_window import MainWindow
from rare.shared import RareCore
-from rare.utils import config_helper, paths
+from rare.utils import paths
from rare.utils.misc import ExitCodes
from rare.widgets.rare_app import RareApp, RareAppException
diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py
index 3582304a..9afcaac2 100644
--- a/rare/shared/rare_core.py
+++ b/rare/shared/rare_core.py
@@ -16,12 +16,15 @@ from rare.models.base_game import RareSaveGame
from rare.models.game import RareGame, RareEosOverlay
from rare.models.signals import GlobalSignals
from rare.utils.metrics import timelogger
+from rare.utils import config_helper
from .image_manager import ImageManager
from .workers import (
QueueWorker,
VerifyWorker,
MoveWorker,
FetchWorker,
+ GamesDlcsWorker,
+ EntitlementsWorker,
OriginWineWorker,
)
from .workers.uninstall import uninstall_game
@@ -70,6 +73,10 @@ class RareCore(QObject):
self.__eos_overlay.signals.game.install.connect(self.__signals.game.install)
self.__eos_overlay.signals.game.uninstall.connect(self.__signals.game.uninstall)
+ self.__fetch_progress: int = 0
+ self.__fetched_games_dlcs: bool = False
+ self.__fetched_entitlements: bool = False
+
RareCore.__instance = self
def enqueue_worker(self, rgame: RareGame, worker: QueueWorker):
@@ -303,24 +310,45 @@ class RareCore(QObject):
logger.info(f'Marking "{rgame.app_title}" as not installed because an exception has occurred...')
logger.error(e)
rgame.set_installed(False)
- self.progress.emit(int(idx/length * 80) + 20, self.tr("Loaded {}").format(rgame.app_title))
+ progress = int(idx/length * self.__fetch_progress) + (100 - self.__fetch_progress)
+ self.progress.emit(progress, self.tr("Loaded {}").format(rgame.app_title))
+
+ @pyqtSlot(int, str)
+ def __on_fetch_progress(self, increment: int, message: str):
+ self.__fetch_progress += increment
+ self.progress.emit(self.__fetch_progress, message)
@pyqtSlot(object, int)
- def __on_fetch_result(self, result: Tuple[List, Dict], res_type: int):
- logger.info(f"Got API results for {FetchWorker.Result(res_type).name}")
- self.progress.emit(15, self.tr("Preparing library"))
- self.__add_games_and_dlcs(*result)
- self.progress.emit(100, self.tr("Launching Rare"))
- logger.debug(f"Fetch time {time.perf_counter() - self.__start_time} seconds")
- QTimer.singleShot(100, self.__post_init)
- self.completed.emit()
+ def __on_fetch_result(self, result: Tuple, result_type: int):
+ if result_type == FetchWorker.Result.GAMESDLCS:
+ self.__add_games_and_dlcs(*result)
+ self.__fetched_games_dlcs = True
+
+ if result_type == FetchWorker.Result.ENTITLEMENTS:
+ self.__core.lgd.entitlements = result
+ self.__fetched_entitlements = True
+
+ logger.info(f"Acquired data for {FetchWorker.Result(result_type).name}")
+
+ if all([self.__fetched_games_dlcs, self.__fetched_entitlements]):
+ logger.debug(f"Fetch time {time.perf_counter() - self.__start_time} seconds")
+ self.progress.emit(100, self.tr("Launching Rare"))
+ self.completed.emit()
+ QTimer.singleShot(100, self.__post_init)
def fetch(self):
self.__start_time = time.perf_counter()
- fetch_worker = FetchWorker(self.__core, self.__args)
- fetch_worker.signals.progress.connect(self.progress)
- fetch_worker.signals.result.connect(self.__on_fetch_result)
- QThreadPool.globalInstance().start(fetch_worker)
+
+ games_dlcs_worker = GamesDlcsWorker(self.__core, self.__args)
+ games_dlcs_worker.signals.progress.connect(self.__on_fetch_progress)
+ games_dlcs_worker.signals.result.connect(self.__on_fetch_result)
+
+ entitlements_worker = EntitlementsWorker(self.__core, self.__args)
+ entitlements_worker.signals.progress.connect(self.__on_fetch_progress)
+ entitlements_worker.signals.result.connect(self.__on_fetch_result)
+
+ QThreadPool.globalInstance().start(games_dlcs_worker)
+ QThreadPool.globalInstance().start(entitlements_worker)
def fetch_saves(self):
def __fetch() -> None:
@@ -346,24 +374,6 @@ class RareCore(QObject):
saves_worker = QRunnable.create(__fetch)
QThreadPool.globalInstance().start(saves_worker)
- def fetch_entitlements(self) -> None:
- def __fetch() -> None:
- try:
- if (entitlements := self.__core.lgd.entitlements) is None:
- with timelogger(logger, "Request entitlements"):
- entitlements = self.__core.egs.get_user_entitlements()
- self.__core.lgd.entitlements = entitlements
- for game in self.__library.values():
- game.grant_date()
- except (HTTPError, ConnectionError) as e:
- logger.error(f"Exception while fetching entitlements from EGS.")
- logger.error(e)
- return
- logger.info(f"Entitlements: {len(list(entitlements))}")
-
- entitlements_worker = QRunnable.create(__fetch)
- QThreadPool.globalInstance().start(entitlements_worker)
-
def resolve_origin(self) -> None:
origin_worker = OriginWineWorker(self.__core, list(self.origin_games))
QThreadPool.globalInstance().start(origin_worker)
@@ -371,7 +381,6 @@ class RareCore(QObject):
def __post_init(self) -> None:
if not self.__args.offline:
self.fetch_saves()
- # self.fetch_entitlements()
self.resolve_origin()
@property
diff --git a/rare/shared/workers/__init__.py b/rare/shared/workers/__init__.py
index b11df089..12d816c0 100644
--- a/rare/shared/workers/__init__.py
+++ b/rare/shared/workers/__init__.py
@@ -1,4 +1,4 @@
-from .fetch import FetchWorker
+from .fetch import FetchWorker, GamesDlcsWorker, EntitlementsWorker
from .install_info import InstallInfoWorker
from .move import MoveWorker
from .uninstall import UninstallWorker
diff --git a/rare/shared/workers/fetch.py b/rare/shared/workers/fetch.py
index a1173ad5..1d4fe761 100644
--- a/rare/shared/workers/fetch.py
+++ b/rare/shared/workers/fetch.py
@@ -15,9 +15,9 @@ logger = getLogger("FetchWorker")
class FetchWorker(Worker):
class Result(IntEnum):
- GAMES = 1
- NON_ASSET = 2
- COMBINED = 3
+ ERROR = 0
+ GAMESDLCS = 1
+ ENTITLEMENTS = 2
class Signals(QObject):
progress = pyqtSignal(int, str)
@@ -30,7 +30,33 @@ class FetchWorker(Worker):
self.args = args
self.settings = QSettings()
+
+class EntitlementsWorker(FetchWorker):
+ def __init__(self, core: LegendaryCore, args: Namespace):
+ super(EntitlementsWorker, self).__init__(core, args)
+
def run_real(self):
+ entitlements = ()
+ want_entitlements = not self.settings.value("exclude_entitlements", False, bool)
+ if want_entitlements:
+ # Get entitlements, Ubisoft integration also uses them
+ self.signals.progress.emit(0, self.signals.tr("Updating entitlements"))
+ with timelogger(logger, "Request entitlements"):
+ entitlements = self.core.egs.get_user_entitlements()
+ self.core.lgd.entitlements = entitlements
+ logger.info(f"Entitlements: %s", len(list(entitlements)))
+ self.signals.result.emit(entitlements, FetchWorker.Result.ENTITLEMENTS)
+ return
+
+
+class GamesDlcsWorker(FetchWorker):
+
+ def __init__(self, core: LegendaryCore, args: Namespace):
+ super(GamesDlcsWorker, self).__init__(core, args)
+ self.exclude_non_asset = QSettings().value("exclude_non_asset", False, bool)
+
+ def run_real(self):
+
# Fetch regular EGL games with assets
want_unreal = self.settings.value("unreal_meta", False, bool) or self.args.debug
want_win32 = self.settings.value("win32_meta", False, bool)
@@ -74,25 +100,19 @@ class FetchWorker(Worker):
)
logger.info(f"Games: %s. Games with DLCs: %s", len(games), len(dlc_dict))
- want_non_asset = not self.settings.value("exclude_non_asset", False, bool)
- want_entitlements = not self.settings.value("exclude_entitlements", False, bool)
-
# Fetch non-asset games
+ want_non_asset = not self.settings.value("exclude_non_asset", False, bool)
if want_non_asset:
self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata"))
try:
with timelogger(logger, "Request non-asset"):
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
except (HTTPError, ConnectionError) as e:
- logger.error("Network exception while fetching non asset games from EGS.")
+ logger.error(f"Network error while fetching non asset games")
logger.error(e)
na_games, na_dlc_dict = ([], {})
- # FIXME:
- # This is here because of broken appIds from Epic:
- # https://discord.com/channels/826881530310819914/884510635642216499/1111321692703305729
- # There is a tab character in the appId of Fallout New Vegas: Honest Hearts DLC, this breaks metadata storage
- # on Windows as they can't handle tabs at the end of the filename (?)
- # Legendary and Heroic are also affected, but it completely breaks Rare, so dodge it for now pending a fix.
+ # NOTE: This is here because of broken appIds from Epic
+ # https://discord.com/channels/826881530310819914/884510635642216499/1111321692703305729
except Exception as e:
logger.error("General exception while fetching non asset games from EGS.")
logger.error(e)
@@ -108,13 +128,5 @@ class FetchWorker(Worker):
dlc_dict[catalog_id] = dlcs
logger.info(f"Games: {len(games)}. Games with DLCs: {len(dlc_dict)}")
- if want_entitlements:
- # Get entitlements, Ubisoft integration also uses them
- self.signals.progress.emit(40, self.signals.tr("Updating entitlements"))
- with timelogger(logger, "Request entitlements"):
- entitlements = self.core.egs.get_user_entitlements()
- self.core.lgd.entitlements = entitlements
- logger.info(f"Entitlements: {len(list(entitlements))}")
-
- self.signals.progress.emit(50, self.signals.tr("Preparing games"))
- self.signals.result.emit((games, dlc_dict), FetchWorker.Result.COMBINED)
+ self.signals.progress.emit(40, self.signals.tr("Preparing library"))
+ self.signals.result.emit((games, dlc_dict), FetchWorker.Result.GAMESDLCS)