mirror of
https://github.com/gogcom/galaxy-integrations-python-api.git
synced 2026-01-06 05:48:18 -05:00
Compare commits
5 Commits
deployed_0
...
deployed_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
909cc10762 | ||
|
|
9b4537c54f | ||
|
|
2e90c66390 | ||
|
|
8647b06ca2 | ||
|
|
f6522be74d |
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="galaxy.plugin.api",
|
name="galaxy.plugin.api",
|
||||||
version="0.32.1",
|
version="0.33",
|
||||||
description="GOG Galaxy Integrations Python API",
|
description="GOG Galaxy Integrations Python API",
|
||||||
author='Galaxy team',
|
author='Galaxy team',
|
||||||
author_email='galaxy@gog.com',
|
author_email='galaxy@gog.com',
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ class UnknownBackendResponse(ApplicationError):
|
|||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
super().__init__(4, "Backend responded in uknown way", data)
|
super().__init__(4, "Backend responded in uknown way", data)
|
||||||
|
|
||||||
|
class TooManyRequests(ApplicationError):
|
||||||
|
def __init__(self, data=None):
|
||||||
|
super().__init__(5, "Too many requests. Try again later", data)
|
||||||
|
|
||||||
class InvalidCredentials(ApplicationError):
|
class InvalidCredentials(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
super().__init__(100, "Invalid credentials", data)
|
super().__init__(100, "Invalid credentials", data)
|
||||||
@@ -50,18 +54,6 @@ class AccessDenied(ApplicationError):
|
|||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
super().__init__(106, "Access denied", data)
|
super().__init__(106, "Access denied", data)
|
||||||
|
|
||||||
class ParentalControlBlock(ApplicationError):
|
|
||||||
def __init__(self, data=None):
|
|
||||||
super().__init__(107, "Parental control block", data)
|
|
||||||
|
|
||||||
class DeviceBlocked(ApplicationError):
|
|
||||||
def __init__(self, data=None):
|
|
||||||
super().__init__(108, "Device blocked", data)
|
|
||||||
|
|
||||||
class RegionBlocked(ApplicationError):
|
|
||||||
def __init__(self, data=None):
|
|
||||||
super().__init__(109, "Region blocked", data)
|
|
||||||
|
|
||||||
class FailedParsingManifest(ApplicationError):
|
class FailedParsingManifest(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
super().__init__(200, "Failed parsing manifest", data)
|
super().__init__(200, "Failed parsing manifest", data)
|
||||||
@@ -80,4 +72,4 @@ class MessageNotFound(ApplicationError):
|
|||||||
|
|
||||||
class ImportInProgress(ApplicationError):
|
class ImportInProgress(ApplicationError):
|
||||||
def __init__(self, data=None):
|
def __init__(self, data=None):
|
||||||
super().__init__(600, "Import already in progress", data)
|
super().__init__(600, "Import already in progress", data)
|
||||||
|
|||||||
@@ -54,17 +54,15 @@ Method = namedtuple("Method", ["callback", "signature", "internal", "sensitive_p
|
|||||||
|
|
||||||
def anonymise_sensitive_params(params, sensitive_params):
|
def anonymise_sensitive_params(params, sensitive_params):
|
||||||
anomized_data = "****"
|
anomized_data = "****"
|
||||||
if not sensitive_params:
|
|
||||||
return params
|
if isinstance(sensitive_params, bool):
|
||||||
|
if sensitive_params:
|
||||||
|
return {k:anomized_data for k,v in params.items()}
|
||||||
|
|
||||||
if isinstance(sensitive_params, Iterable):
|
if isinstance(sensitive_params, Iterable):
|
||||||
anomized_params = params.copy()
|
return {k: anomized_data if k in sensitive_params else v for k, v in params.items()}
|
||||||
for key in anomized_params.keys():
|
|
||||||
if key in sensitive_params:
|
|
||||||
anomized_params[key] = anomized_data
|
|
||||||
return anomized_params
|
|
||||||
|
|
||||||
return anomized_data
|
return params
|
||||||
|
|
||||||
class Server():
|
class Server():
|
||||||
def __init__(self, reader, writer, encoder=json.JSONEncoder()):
|
def __init__(self, reader, writer, encoder=json.JSONEncoder()):
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ from galaxy.api.jsonrpc import Server, NotificationClient, ApplicationError
|
|||||||
from galaxy.api.consts import Feature
|
from galaxy.api.consts import Feature
|
||||||
from galaxy.api.errors import UnknownError, ImportInProgress
|
from galaxy.api.errors import UnknownError, ImportInProgress
|
||||||
|
|
||||||
|
|
||||||
class JSONEncoder(json.JSONEncoder):
|
class JSONEncoder(json.JSONEncoder):
|
||||||
def default(self, o): # pylint: disable=method-hidden
|
def default(self, o): # pylint: disable=method-hidden
|
||||||
if dataclasses.is_dataclass(o):
|
if dataclasses.is_dataclass(o):
|
||||||
# filter None values
|
# filter None values
|
||||||
def dict_factory(elements):
|
def dict_factory(elements):
|
||||||
@@ -26,7 +27,8 @@ class JSONEncoder(json.JSONEncoder):
|
|||||||
return o.value
|
return o.value
|
||||||
return super().default(o)
|
return super().default(o)
|
||||||
|
|
||||||
class Plugin():
|
|
||||||
|
class Plugin:
|
||||||
"""Use and override methods of this class to create a new platform integration."""
|
"""Use and override methods of this class to create a new platform integration."""
|
||||||
def __init__(self, platform, version, reader, writer, handshake_token):
|
def __init__(self, platform, version, reader, writer, handshake_token):
|
||||||
logging.info("Creating plugin for platform %s, version %s", platform.value, version)
|
logging.info("Creating plugin for platform %s, version %s", platform.value, version)
|
||||||
@@ -50,9 +52,12 @@ class Plugin():
|
|||||||
self._achievements_import_in_progress = False
|
self._achievements_import_in_progress = False
|
||||||
self._game_times_import_in_progress = False
|
self._game_times_import_in_progress = False
|
||||||
|
|
||||||
|
self._persistent_cache = dict()
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
self._register_method("shutdown", self._shutdown, internal=True)
|
self._register_method("shutdown", self._shutdown, internal=True)
|
||||||
self._register_method("get_capabilities", self._get_capabilities, internal=True)
|
self._register_method("get_capabilities", self._get_capabilities, internal=True)
|
||||||
|
self._register_method("initialize_cache", self._initialize_cache, internal=True)
|
||||||
self._register_method("ping", self._ping, internal=True)
|
self._register_method("ping", self._ping, internal=True)
|
||||||
|
|
||||||
# implemented by developer
|
# implemented by developer
|
||||||
@@ -156,6 +161,12 @@ class Plugin():
|
|||||||
|
|
||||||
return features
|
return features
|
||||||
|
|
||||||
|
@property
|
||||||
|
def persistent_cache(self) -> Dict:
|
||||||
|
"""The cache is only available after the :meth:`~.handshake_complete()` is called.
|
||||||
|
"""
|
||||||
|
return self._persistent_cache
|
||||||
|
|
||||||
def _implements(self, handlers):
|
def _implements(self, handlers):
|
||||||
for handler in handlers:
|
for handler in handlers:
|
||||||
if handler.__name__ not in self.__class__.__dict__:
|
if handler.__name__ not in self.__class__.__dict__:
|
||||||
@@ -192,7 +203,7 @@ class Plugin():
|
|||||||
self._feature_methods.setdefault(feature, []).append(handler)
|
self._feature_methods.setdefault(feature, []).append(handler)
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
"""Plugin main coroutine."""
|
"""Plugin's main coroutine."""
|
||||||
async def pass_control():
|
async def pass_control():
|
||||||
while self._active:
|
while self._active:
|
||||||
try:
|
try:
|
||||||
@@ -216,6 +227,10 @@ class Plugin():
|
|||||||
"token": self._handshake_token
|
"token": self._handshake_token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _initialize_cache(self, data: Dict):
|
||||||
|
self._persistent_cache = data
|
||||||
|
self.handshake_complete()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _ping():
|
def _ping():
|
||||||
pass
|
pass
|
||||||
@@ -264,7 +279,7 @@ class Plugin():
|
|||||||
self.add_game(game)
|
self.add_game(game)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
params = {"owned_game" : game}
|
params = {"owned_game": game}
|
||||||
self._notification_client.notify("owned_game_added", params)
|
self._notification_client.notify("owned_game_added", params)
|
||||||
|
|
||||||
def remove_game(self, game_id: str):
|
def remove_game(self, game_id: str):
|
||||||
@@ -286,7 +301,7 @@ class Plugin():
|
|||||||
self.remove_game(game.game_id)
|
self.remove_game(game.game_id)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
params = {"game_id" : game_id}
|
params = {"game_id": game_id}
|
||||||
self._notification_client.notify("owned_game_removed", params)
|
self._notification_client.notify("owned_game_removed", params)
|
||||||
|
|
||||||
def update_game(self, game: Game):
|
def update_game(self, game: Game):
|
||||||
@@ -295,7 +310,7 @@ class Plugin():
|
|||||||
|
|
||||||
:param game: Game to update
|
:param game: Game to update
|
||||||
"""
|
"""
|
||||||
params = {"owned_game" : game}
|
params = {"owned_game": game}
|
||||||
self._notification_client.notify("owned_game_updated", params)
|
self._notification_client.notify("owned_game_updated", params)
|
||||||
|
|
||||||
def unlock_achievement(self, game_id: str, achievement: Achievement):
|
def unlock_achievement(self, game_id: str, achievement: Achievement):
|
||||||
@@ -367,7 +382,7 @@ class Plugin():
|
|||||||
if self._check_statuses_task is None or self._check_statuses_task.done():
|
if self._check_statuses_task is None or self._check_statuses_task.done():
|
||||||
self._check_statuses_task = asyncio.create_task(self._check_statuses())
|
self._check_statuses_task = asyncio.create_task(self._check_statuses())
|
||||||
"""
|
"""
|
||||||
params = {"local_game" : local_game}
|
params = {"local_game": local_game}
|
||||||
self._notification_client.notify("local_game_status_changed", params)
|
self._notification_client.notify("local_game_status_changed", params)
|
||||||
|
|
||||||
def add_friend(self, user: FriendInfo):
|
def add_friend(self, user: FriendInfo):
|
||||||
@@ -375,7 +390,7 @@ class Plugin():
|
|||||||
|
|
||||||
:param user: FriendInfo of a user that the client will add to friends list
|
:param user: FriendInfo of a user that the client will add to friends list
|
||||||
"""
|
"""
|
||||||
params = {"friend_info" : user}
|
params = {"friend_info": user}
|
||||||
self._notification_client.notify("friend_added", params)
|
self._notification_client.notify("friend_added", params)
|
||||||
|
|
||||||
def remove_friend(self, user_id: str):
|
def remove_friend(self, user_id: str):
|
||||||
@@ -383,7 +398,7 @@ class Plugin():
|
|||||||
|
|
||||||
:param user_id: id of the user to remove from friends list
|
:param user_id: id of the user to remove from friends list
|
||||||
"""
|
"""
|
||||||
params = {"user_id" : user_id}
|
params = {"user_id": user_id}
|
||||||
self._notification_client.notify("friend_removed", params)
|
self._notification_client.notify("friend_removed", params)
|
||||||
|
|
||||||
def update_room(self, room_id: str, unread_message_count=None, new_messages=None):
|
def update_room(self, room_id: str, unread_message_count=None, new_messages=None):
|
||||||
@@ -406,7 +421,7 @@ class Plugin():
|
|||||||
|
|
||||||
:param game_time: game time to update
|
:param game_time: game time to update
|
||||||
"""
|
"""
|
||||||
params = {"game_time" : game_time}
|
params = {"game_time": game_time}
|
||||||
self._notification_client.notify("game_time_updated", params)
|
self._notification_client.notify("game_time_updated", params)
|
||||||
|
|
||||||
def game_time_import_success(self, game_time: GameTime):
|
def game_time_import_success(self, game_time: GameTime):
|
||||||
@@ -415,7 +430,7 @@ class Plugin():
|
|||||||
|
|
||||||
:param game_time: game_time which was imported
|
:param game_time: game_time which was imported
|
||||||
"""
|
"""
|
||||||
params = {"game_time" : game_time}
|
params = {"game_time": game_time}
|
||||||
self._notification_client.notify("game_time_import_success", params)
|
self._notification_client.notify("game_time_import_success", params)
|
||||||
|
|
||||||
def game_time_import_failure(self, game_id: str, error: ApplicationError):
|
def game_time_import_failure(self, game_id: str, error: ApplicationError):
|
||||||
@@ -446,7 +461,22 @@ class Plugin():
|
|||||||
"""
|
"""
|
||||||
self._notification_client.notify("authentication_lost", None)
|
self._notification_client.notify("authentication_lost", None)
|
||||||
|
|
||||||
|
def push_cache(self):
|
||||||
|
"""Push local copy of the persistent cache to the GOG Galaxy Client replacing existing one.
|
||||||
|
"""
|
||||||
|
self._notification_client.notify(
|
||||||
|
"push_cache",
|
||||||
|
params={"data": self._persistent_cache}
|
||||||
|
)
|
||||||
|
|
||||||
# handlers
|
# handlers
|
||||||
|
def handshake_complete(self):
|
||||||
|
"""This method is called right after the handshake with the GOG Galaxy Client is complete and
|
||||||
|
before any other operations are called by the GOG Galaxy Client.
|
||||||
|
Persistent cache is available when this method is called.
|
||||||
|
Override it if you need to do additional plugin initializations.
|
||||||
|
This method is called internally."""
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
"""This method is called periodically.
|
"""This method is called periodically.
|
||||||
Override it to implement periodical non-blocking tasks.
|
Override it to implement periodical non-blocking tasks.
|
||||||
@@ -470,14 +500,14 @@ class Plugin():
|
|||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""This method is called on integration shutdown.
|
"""This method is called on integration shutdown.
|
||||||
Override it to implement tear down.
|
Override it to implement tear down.
|
||||||
This method is called by the GOG Galaxy client."""
|
This method is called by the GOG Galaxy Client."""
|
||||||
|
|
||||||
# methods
|
# methods
|
||||||
async def authenticate(self, stored_credentials:dict=None):
|
async def authenticate(self, stored_credentials: dict = None):
|
||||||
"""Override this method to handle user authentication.
|
"""Override this method to handle user authentication.
|
||||||
This method should either return :class:`~galaxy.api.types.Authentication` if the authentication is finished
|
This method should either return :class:`~galaxy.api.types.Authentication` if the authentication is finished
|
||||||
or :class:`~galaxy.api.types.NextStep` if it requires going to another url.
|
or :class:`~galaxy.api.types.NextStep` if it requires going to another url.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param stored_credentials: If the client received any credentials to store locally
|
:param stored_credentials: If the client received any credentials to store locally
|
||||||
in the previous session they will be passed here as a parameter.
|
in the previous session they will be passed here as a parameter.
|
||||||
@@ -506,7 +536,7 @@ class Plugin():
|
|||||||
This method's parameters provide the data extracted from the web page navigation that previous NextStep finished on.
|
This method's parameters provide the data extracted from the web page navigation that previous NextStep finished on.
|
||||||
This method should either return galaxy.api.types.Authentication if the authentication is finished
|
This method should either return galaxy.api.types.Authentication if the authentication is finished
|
||||||
or galaxy.api.types.NextStep if it requires going to another cef url.
|
or galaxy.api.types.NextStep if it requires going to another cef url.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param step: deprecated.
|
:param step: deprecated.
|
||||||
:param credentials: end_uri previous NextStep finished on.
|
:param credentials: end_uri previous NextStep finished on.
|
||||||
@@ -531,8 +561,8 @@ class Plugin():
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
async def get_owned_games(self) -> List[Game]:
|
async def get_owned_games(self) -> List[Game]:
|
||||||
"""Override this method to return owned games for currenly logged in user.
|
"""Override this method to return owned games for currently logged in user.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
Example of possible override of the method:
|
Example of possible override of the method:
|
||||||
|
|
||||||
@@ -558,7 +588,7 @@ class Plugin():
|
|||||||
|
|
||||||
async def start_achievements_import(self, game_ids: List[str]):
|
async def start_achievements_import(self, game_ids: List[str]):
|
||||||
"""Starts the task of importing achievements.
|
"""Starts the task of importing achievements.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param game_ids: ids of the games for which the achievements are imported
|
:param game_ids: ids of the games for which the achievements are imported
|
||||||
"""
|
"""
|
||||||
@@ -580,9 +610,9 @@ class Plugin():
|
|||||||
Override this method to return the unlocked achievements
|
Override this method to return the unlocked achievements
|
||||||
of the user that is currently logged in to the plugin.
|
of the user that is currently logged in to the plugin.
|
||||||
Call game_achievements_import_success/game_achievements_import_failure for each game_id on the list.
|
Call game_achievements_import_success/game_achievements_import_failure for each game_id on the list.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param game_id: ids of the games for which to import unlocked achievements
|
:param game_ids: ids of the games for which to import unlocked achievements
|
||||||
"""
|
"""
|
||||||
async def import_game_achievements(game_id):
|
async def import_game_achievements(game_id):
|
||||||
try:
|
try:
|
||||||
@@ -597,7 +627,7 @@ class Plugin():
|
|||||||
async def get_local_games(self) -> List[LocalGame]:
|
async def get_local_games(self) -> List[LocalGame]:
|
||||||
"""Override this method to return the list of
|
"""Override this method to return the list of
|
||||||
games present locally on the users pc.
|
games present locally on the users pc.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
Example of possible override of the method:
|
Example of possible override of the method:
|
||||||
|
|
||||||
@@ -619,7 +649,7 @@ class Plugin():
|
|||||||
async def launch_game(self, game_id: str):
|
async def launch_game(self, game_id: str):
|
||||||
"""Override this method to launch the game
|
"""Override this method to launch the game
|
||||||
identified by the provided game_id.
|
identified by the provided game_id.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param str game_id: id of the game to launch
|
:param str game_id: id of the game to launch
|
||||||
|
|
||||||
@@ -637,7 +667,7 @@ class Plugin():
|
|||||||
async def install_game(self, game_id: str):
|
async def install_game(self, game_id: str):
|
||||||
"""Override this method to install the game
|
"""Override this method to install the game
|
||||||
identified by the provided game_id.
|
identified by the provided game_id.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param str game_id: id of the game to install
|
:param str game_id: id of the game to install
|
||||||
|
|
||||||
@@ -655,7 +685,7 @@ class Plugin():
|
|||||||
async def uninstall_game(self, game_id: str):
|
async def uninstall_game(self, game_id: str):
|
||||||
"""Override this method to uninstall the game
|
"""Override this method to uninstall the game
|
||||||
identified by the provided game_id.
|
identified by the provided game_id.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param str game_id: id of the game to uninstall
|
:param str game_id: id of the game to uninstall
|
||||||
|
|
||||||
@@ -673,7 +703,7 @@ class Plugin():
|
|||||||
async def get_friends(self) -> List[FriendInfo]:
|
async def get_friends(self) -> List[FriendInfo]:
|
||||||
"""Override this method to return the friends list
|
"""Override this method to return the friends list
|
||||||
of the currently authenticated user.
|
of the currently authenticated user.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
Example of possible override of the method:
|
Example of possible override of the method:
|
||||||
|
|
||||||
@@ -692,7 +722,7 @@ class Plugin():
|
|||||||
|
|
||||||
async def get_users(self, user_id_list: List[str]) -> List[UserInfo]:
|
async def get_users(self, user_id_list: List[str]) -> List[UserInfo]:
|
||||||
"""WIP, Override this method to return the list of users matching the provided ids.
|
"""WIP, Override this method to return the list of users matching the provided ids.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param user_id_list: list of user ids
|
:param user_id_list: list of user ids
|
||||||
"""
|
"""
|
||||||
@@ -700,7 +730,7 @@ class Plugin():
|
|||||||
|
|
||||||
async def send_message(self, room_id: str, message_text: str):
|
async def send_message(self, room_id: str, message_text: str):
|
||||||
"""WIP, Override this method to send message to a chat room.
|
"""WIP, Override this method to send message to a chat room.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param room_id: id of the room to which the message should be sent
|
:param room_id: id of the room to which the message should be sent
|
||||||
:param message_text: text which should be sent in the message
|
:param message_text: text which should be sent in the message
|
||||||
@@ -709,22 +739,23 @@ class Plugin():
|
|||||||
|
|
||||||
async def mark_as_read(self, room_id: str, last_message_id: str):
|
async def mark_as_read(self, room_id: str, last_message_id: str):
|
||||||
"""WIP, Override this method to mark messages in a chat room as read up to the id provided in the parameter.
|
"""WIP, Override this method to mark messages in a chat room as read up to the id provided in the parameter.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param room_id: id of the room
|
:param room_id: id of the room
|
||||||
:param last_message_id: id of the last message; room is marked as read only if this id matches the last message id known to the client
|
:param last_message_id: id of the last message; room is marked as read only if this id matches
|
||||||
|
the last message id known to the client
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
async def get_rooms(self) -> List[Room]:
|
async def get_rooms(self) -> List[Room]:
|
||||||
"""WIP, Override this method to return the chat rooms in which the user is currently in.
|
"""WIP, Override this method to return the chat rooms in which the user is currently in.
|
||||||
This method is called by the GOG Galaxy client
|
This method is called by the GOG Galaxy Client
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
async def get_room_history_from_message(self, room_id: str, message_id: str):
|
async def get_room_history_from_message(self, room_id: str, message_id: str):
|
||||||
"""WIP, Override this method to return the chat room history since the message provided in parameter.
|
"""WIP, Override this method to return the chat room history since the message provided in parameter.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param room_id: id of the room
|
:param room_id: id of the room
|
||||||
:param message_id: id of the message since which the history should be retrieved
|
:param message_id: id of the message since which the history should be retrieved
|
||||||
@@ -733,7 +764,7 @@ class Plugin():
|
|||||||
|
|
||||||
async def get_room_history_from_timestamp(self, room_id: str, from_timestamp: int):
|
async def get_room_history_from_timestamp(self, room_id: str, from_timestamp: int):
|
||||||
"""WIP, Override this method to return the chat room history since the timestamp provided in parameter.
|
"""WIP, Override this method to return the chat room history since the timestamp provided in parameter.
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param room_id: id of the room
|
:param room_id: id of the room
|
||||||
:param from_timestamp: timestamp since which the history should be retrieved
|
:param from_timestamp: timestamp since which the history should be retrieved
|
||||||
@@ -749,7 +780,7 @@ class Plugin():
|
|||||||
|
|
||||||
async def start_game_times_import(self, game_ids: List[str]):
|
async def start_game_times_import(self, game_ids: List[str]):
|
||||||
"""Starts the task of importing game times
|
"""Starts the task of importing game times
|
||||||
This method is called by the GOG Galaxy client.
|
This method is called by the GOG Galaxy Client.
|
||||||
|
|
||||||
:param game_ids: ids of the games for which the game time is imported
|
:param game_ids: ids of the games for which the game time is imported
|
||||||
"""
|
"""
|
||||||
@@ -829,7 +860,7 @@ def create_and_run_plugin(plugin_class, argv):
|
|||||||
|
|
||||||
async def coroutine():
|
async def coroutine():
|
||||||
reader, writer = await asyncio.open_connection("127.0.0.1", port)
|
reader, writer = await asyncio.open_connection("127.0.0.1", port)
|
||||||
extra_info = writer.get_extra_info('sockname')
|
extra_info = writer.get_extra_info("sockname")
|
||||||
logging.info("Using local address: %s:%u", *extra_info)
|
logging.info("Using local address: %s:%u", *extra_info)
|
||||||
plugin = plugin_class(reader, writer, token)
|
plugin = plugin_class(reader, writer, token)
|
||||||
await plugin.run()
|
await plugin.run()
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import aiohttp
|
|||||||
import certifi
|
import certifi
|
||||||
|
|
||||||
from galaxy.api.errors import (
|
from galaxy.api.errors import (
|
||||||
AccessDenied, AuthenticationRequired,
|
AccessDenied, AuthenticationRequired, BackendTimeout, BackendNotAvailable, BackendError, NetworkError,
|
||||||
BackendTimeout, BackendNotAvailable, BackendError, NetworkError, UnknownBackendResponse, UnknownError
|
TooManyRequests, UnknownBackendResponse, UnknownError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class HttpClient:
|
class HttpClient:
|
||||||
def __init__(self, limit=20, timeout=aiohttp.ClientTimeout(total=60), cookie_jar=None):
|
def __init__(self, limit=20, timeout=aiohttp.ClientTimeout(total=60), cookie_jar=None):
|
||||||
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||||
@@ -39,6 +40,8 @@ class HttpClient:
|
|||||||
raise AccessDenied()
|
raise AccessDenied()
|
||||||
if response.status == HTTPStatus.SERVICE_UNAVAILABLE:
|
if response.status == HTTPStatus.SERVICE_UNAVAILABLE:
|
||||||
raise BackendNotAvailable()
|
raise BackendNotAvailable()
|
||||||
|
if response.status == HTTPStatus.TOO_MANY_REQUESTS:
|
||||||
|
raise TooManyRequests()
|
||||||
if response.status >= 500:
|
if response.status >= 500:
|
||||||
raise BackendError()
|
raise BackendError()
|
||||||
if response.status >= 400:
|
if response.status >= 400:
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ def write(writer):
|
|||||||
def plugin(reader, writer):
|
def plugin(reader, writer):
|
||||||
"""Return plugin instance with all feature methods mocked"""
|
"""Return plugin instance with all feature methods mocked"""
|
||||||
async_methods = (
|
async_methods = (
|
||||||
|
"handshake_complete",
|
||||||
"authenticate",
|
"authenticate",
|
||||||
"get_owned_games",
|
"get_owned_games",
|
||||||
"get_unlocked_achievements",
|
"get_unlocked_achievements",
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import pytest
|
|||||||
from galaxy.api.types import Authentication
|
from galaxy.api.types import Authentication
|
||||||
from galaxy.api.errors import (
|
from galaxy.api.errors import (
|
||||||
UnknownError, InvalidCredentials, NetworkError, LoggedInElsewhere, ProtocolError,
|
UnknownError, InvalidCredentials, NetworkError, LoggedInElsewhere, ProtocolError,
|
||||||
BackendNotAvailable, BackendTimeout, BackendError, TemporaryBlocked, Banned, AccessDenied,
|
BackendNotAvailable, BackendTimeout, BackendError, TemporaryBlocked, Banned, AccessDenied
|
||||||
ParentalControlBlock, DeviceBlocked, RegionBlocked
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_success(plugin, readline, write):
|
def test_success(plugin, readline, write):
|
||||||
@@ -44,9 +43,6 @@ def test_success(plugin, readline, write):
|
|||||||
pytest.param(TemporaryBlocked, 104, "Temporary blocked", id="temporary_blocked"),
|
pytest.param(TemporaryBlocked, 104, "Temporary blocked", id="temporary_blocked"),
|
||||||
pytest.param(Banned, 105, "Banned", id="banned"),
|
pytest.param(Banned, 105, "Banned", id="banned"),
|
||||||
pytest.param(AccessDenied, 106, "Access denied", id="access_denied"),
|
pytest.param(AccessDenied, 106, "Access denied", id="access_denied"),
|
||||||
pytest.param(ParentalControlBlock, 107, "Parental control block", id="parental_control_clock"),
|
|
||||||
pytest.param(DeviceBlocked, 108, "Device blocked", id="device_blocked"),
|
|
||||||
pytest.param(RegionBlocked, 109, "Region blocked", id="region_blocked")
|
|
||||||
])
|
])
|
||||||
def test_failure(plugin, readline, write, error, code, message):
|
def test_failure(plugin, readline, write, error, code, message):
|
||||||
request = {
|
request = {
|
||||||
|
|||||||
71
tests/test_persistent_cache.py
Normal file
71
tests/test_persistent_cache.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def assert_rpc_response(write, response_id, result=None):
|
||||||
|
assert json.loads(write.call_args[0][0]) == {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": str(response_id),
|
||||||
|
"result": result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def assert_rpc_request(write, method, params=None):
|
||||||
|
assert json.loads(write.call_args[0][0]) == {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": method,
|
||||||
|
"params": {"data": params}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def cache_data():
|
||||||
|
return {
|
||||||
|
"persistent key": "persistent value",
|
||||||
|
"persistent object": {"answer to everything": 42}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialize_cache(plugin, readline, write, cache_data):
|
||||||
|
request_id = 3
|
||||||
|
request = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": str(request_id),
|
||||||
|
"method": "initialize_cache",
|
||||||
|
"params": {"data": cache_data}
|
||||||
|
}
|
||||||
|
readline.side_effect = [json.dumps(request)]
|
||||||
|
|
||||||
|
assert {} == plugin.persistent_cache
|
||||||
|
asyncio.run(plugin.run())
|
||||||
|
plugin.handshake_complete.assert_called_once_with()
|
||||||
|
assert cache_data == plugin.persistent_cache
|
||||||
|
assert_rpc_response(write, response_id=request_id)
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_cache(plugin, write, cache_data):
|
||||||
|
async def runner():
|
||||||
|
assert {} == plugin.persistent_cache
|
||||||
|
|
||||||
|
plugin.persistent_cache.update(cache_data)
|
||||||
|
plugin.push_cache()
|
||||||
|
|
||||||
|
assert_rpc_request(write, "push_cache", cache_data)
|
||||||
|
assert cache_data == plugin.persistent_cache
|
||||||
|
|
||||||
|
asyncio.run(runner())
|
||||||
|
|
||||||
|
|
||||||
|
def test_clear_cache(plugin, write, cache_data):
|
||||||
|
async def runner():
|
||||||
|
plugin._persistent_cache = cache_data
|
||||||
|
|
||||||
|
plugin.persistent_cache.clear()
|
||||||
|
plugin.push_cache()
|
||||||
|
|
||||||
|
assert_rpc_request(write, "push_cache", {})
|
||||||
|
assert {} == plugin.persistent_cache
|
||||||
|
|
||||||
|
asyncio.run(runner())
|
||||||
Reference in New Issue
Block a user