77from enum import Enum
88from typing import Any , Dict , List , Optional , Set , Union
99
10- from galaxy .api .consts import Feature
10+ from galaxy .api .consts import Feature , OSCompatibility
1111from galaxy .api .errors import ImportInProgress , UnknownError
1212from galaxy .api .jsonrpc import ApplicationError , NotificationClient , Server
1313from galaxy .api .types import Achievement , Authentication , FriendInfo , Game , GameTime , LocalGame , NextStep , GameLibrarySettings
1414from galaxy .task_manager import TaskManager
1515
16+
1617class JSONEncoder (json .JSONEncoder ):
1718 def default (self , o ): # pylint: disable=method-hidden
1819 if dataclasses .is_dataclass (o ):
@@ -47,6 +48,7 @@ def __init__(self, platform, version, reader, writer, handshake_token):
4748 self ._achievements_import_in_progress = False
4849 self ._game_times_import_in_progress = False
4950 self ._game_library_settings_import_in_progress = False
51+ self ._os_compatibility_import_in_progress = False
5052
5153 self ._persistent_cache = dict ()
5254
@@ -113,6 +115,9 @@ def __init__(self, platform, version, reader, writer, handshake_token):
113115 self ._register_method ("start_game_library_settings_import" , self ._start_game_library_settings_import )
114116 self ._detect_feature (Feature .ImportGameLibrarySettings , ["get_game_library_settings" ])
115117
118+ self ._register_method ("start_os_compatibility_import" , self ._start_os_compatibility_import )
119+ self ._detect_feature (Feature .ImportOSCompatibility , ["get_os_compatibility" ])
120+
116121 async def __aenter__ (self ):
117122 return self
118123
@@ -173,6 +178,7 @@ def _register_notification(self, name, handler, internal=False, immediate=False,
173178 def _wrap_external_method (self , handler , name : str ):
174179 async def wrapper (* args , ** kwargs ):
175180 return await self ._external_task_manager .create_task (handler (* args , ** kwargs ), name , False )
181+
176182 return wrapper
177183
178184 async def run (self ):
@@ -420,6 +426,27 @@ def _game_library_settings_import_failure(self, game_id: str, error: Application
420426 def _game_library_settings_import_finished (self ) -> None :
421427 self ._notification_client .notify ("game_library_settings_import_finished" , None )
422428
429+ def _os_compatibility_import_success (self , game_id : str , os_compatibility : Optional [OSCompatibility ]) -> None :
430+ self ._notification_client .notify (
431+ "os_compatibility_import_success" ,
432+ {
433+ "game_id" : game_id ,
434+ "os_compatibility" : os_compatibility
435+ }
436+ )
437+
438+ def _os_compatibility_import_failure (self , game_id : str , error : ApplicationError ) -> None :
439+ self ._notification_client .notify (
440+ "os_compatibility_import_failure" ,
441+ {
442+ "game_id" : game_id ,
443+ "error" : error .json ()
444+ }
445+ )
446+
447+ def _os_compatibility_import_finished (self ) -> None :
448+ self ._notification_client .notify ("os_compatibility_import_finished" , None )
449+
423450 def lost_authentication (self ) -> None :
424451 """Notify the client that integration has lost authentication for the
425452 current user and is unable to perform actions which would require it.
@@ -805,7 +832,7 @@ async def prepare_game_library_settings_context(self, game_ids: List[str]) -> An
805832 This allows for optimizations like batch requests to platform API.
806833 Default implementation returns None.
807834
808- :param game_ids: the ids of the games for which game time are imported
835+ :param game_ids: the ids of the games for which game library settings are imported
809836 :return: context
810837 """
811838 return None
@@ -815,17 +842,74 @@ async def get_game_library_settings(self, game_id: str, context: Any) -> GameLib
815842 identified by the provided game_id.
816843 This method is called by import task initialized by GOG Galaxy Client.
817844
818- :param game_id: the id of the game for which the game time is returned
845+ :param game_id: the id of the game for which the game library settings are imported
819846 :param context: the value returned from :meth:`prepare_game_library_settings_context`
820847 :return: GameLibrarySettings object
821848 """
822849 raise NotImplementedError ()
823850
824851 def game_library_settings_import_complete (self ) -> None :
825- """Override this method to handle operations after game times import is finished
852+ """Override this method to handle operations after game library settings import is finished
826853 (like updating cache).
827854 """
828855
856+ async def _start_os_compatibility_import (self , game_ids : List [str ]) -> None :
857+ if self ._os_compatibility_import_in_progress :
858+ raise ImportInProgress ()
859+
860+ context = await self .prepare_os_compatibility_context (game_ids )
861+
862+ async def import_os_compatibility (game_id , context_ ):
863+ try :
864+ os_compatibility = await self .get_os_compatibility (game_id , context_ )
865+ self ._os_compatibility_import_success (game_id , os_compatibility )
866+ except ApplicationError as error :
867+ self ._os_compatibility_import_failure (game_id , error )
868+ except Exception :
869+ logging .exception ("Unexpected exception raised in import_os_compatibility" )
870+ self ._os_compatibility_import_failure (game_id , UnknownError ())
871+
872+ async def import_os_compatibility_set (game_ids_ , context_ ):
873+ try :
874+ await asyncio .gather (* [
875+ import_os_compatibility (game_id , context_ ) for game_id in game_ids_
876+ ])
877+ finally :
878+ self ._os_compatibility_import_finished ()
879+ self ._os_compatibility_import_in_progress = False
880+ self .os_compatibility_import_complete ()
881+
882+ self ._external_task_manager .create_task (
883+ import_os_compatibility_set (game_ids , context ),
884+ "game OS compatibility import" ,
885+ handle_exceptions = False
886+ )
887+ self ._os_compatibility_import_in_progress = True
888+
889+ async def prepare_os_compatibility_context (self , game_ids : List [str ]) -> Any :
890+ """Override this method to prepare context for get_os_compatibility.
891+ This allows for optimizations like batch requests to platform API.
892+ Default implementation returns None.
893+
894+ :param game_ids: the ids of the games for which game os compatibility is imported
895+ :return: context
896+ """
897+ return None
898+
899+ async def get_os_compatibility (self , game_id : str , context : Any ) -> Optional [OSCompatibility ]:
900+ """Override this method to return the OS compatibility for the game with the provided game_id.
901+ This method is called by import task initialized by GOG Galaxy Client.
902+
903+ :param game_id: the id of the game for which the game os compatibility is imported
904+ :param context: the value returned from :meth:`prepare_os_compatibility_context`
905+ :return: OSCompatibility flags indicating compatible OSs, or None if compatibility is not know
906+ """
907+ raise NotImplementedError ()
908+
909+ def os_compatibility_import_complete (self ) -> None :
910+ """Override this method to handle operations after OS compatibility import is finished (like updating cache)."""
911+
912+
829913def create_and_run_plugin (plugin_class , argv ):
830914 """Call this method as an entry point for the implemented integration.
831915
0 commit comments