mirror of
https://github.com/gogcom/galaxy-integrations-python-api.git
synced 2026-01-01 03:18:25 -05:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aaeca6b47e | ||
|
|
fe8f7e929a | ||
|
|
49da4d4d37 | ||
|
|
9745dcd8ef | ||
|
|
ad758b0da9 |
@@ -4,10 +4,10 @@ Platform ID list for GOG Galaxy 2.0 Integrations
|
||||
|
||||
| ID | Name |
|
||||
| --- | --- |
|
||||
| test | Testing purposes |
|
||||
| steam | Steam |
|
||||
| psn | PlayStation Network |
|
||||
| xboxone | Xbox Live |
|
||||
| generic | Manually added games |
|
||||
| origin | Origin |
|
||||
| uplay | Uplay |
|
||||
| battlenet | Battle.net |
|
||||
|
||||
40
README.md
40
README.md
@@ -36,20 +36,31 @@ Communication between an integration and the client is also possible with the us
|
||||
import sys
|
||||
from galaxy.api.plugin import Plugin, create_and_run_plugin
|
||||
from galaxy.api.consts import Platform
|
||||
from galaxy.api.types import Authentication, Game, LicenseInfo, LicenseType
|
||||
|
||||
|
||||
class PluginExample(Plugin):
|
||||
def __init__(self, reader, writer, token):
|
||||
super().__init__(
|
||||
Platform.Generic, # Choose platform from available list
|
||||
"0.1", # Version
|
||||
Platform.Test, # choose platform from available list
|
||||
"0.1", # version
|
||||
reader,
|
||||
writer,
|
||||
token
|
||||
)
|
||||
|
||||
# implement methods
|
||||
|
||||
# required
|
||||
async def authenticate(self, stored_credentials=None):
|
||||
pass
|
||||
return Authentication('test_user_id', 'Test User Name')
|
||||
|
||||
# required
|
||||
async def get_owned_games(self):
|
||||
return [
|
||||
Game('test', 'The Test', None, LicenseInfo(LicenseType.SinglePurchase))
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
create_and_run_plugin(PluginExample, sys.argv)
|
||||
@@ -76,6 +87,20 @@ In order to be found by GOG Galaxy 2.0 an integration folder should be placed in
|
||||
|
||||
`~/Library/Application Support/GOG.com/Galaxy/plugins/installed`
|
||||
|
||||
### Logging
|
||||
<a href='https://docs.python.org/3.7/howto/logging.html'>Root logger</a> is already setup by GOG Galaxy to store rotated log files in:
|
||||
|
||||
- Windows:
|
||||
|
||||
`%programdata%\GOG.com\Galaxy\logs`
|
||||
|
||||
- macOS:
|
||||
|
||||
`/Users/Shared/GOG.com/Galaxy/Logs`
|
||||
|
||||
Plugin logs are kept in `plugin-<platform>-<guid>.log`.
|
||||
When debugging, inspecting the other side of communication in the `GalaxyClient.log` can be helpful as well.
|
||||
|
||||
### Manifest
|
||||
|
||||
<a name="deploy-manifest"></a>
|
||||
@@ -84,8 +109,8 @@ Obligatory JSON file to be placed in an integration folder.
|
||||
```json
|
||||
{
|
||||
"name": "Example plugin",
|
||||
"platform": "generic",
|
||||
"guid": "UNIQUE-GUID",
|
||||
"platform": "test",
|
||||
"guid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
"version": "0.1",
|
||||
"description": "Example plugin",
|
||||
"author": "Name",
|
||||
@@ -97,9 +122,8 @@ Obligatory JSON file to be placed in an integration folder.
|
||||
|
||||
| property | description |
|
||||
|---------------|---|
|
||||
| `guid` | |
|
||||
| `description` | |
|
||||
| `url` | |
|
||||
| `guid` | custom Globally Unique Identifier |
|
||||
| `version` | the same string as `version` in `Plugin` constructor |
|
||||
| `script` | path of the entry point module, relative to the integration folder |
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -7,4 +7,4 @@ pytest-flakes==4.0.0
|
||||
# because of pip bug https://github.com/pypa/pip/issues/4780
|
||||
aiohttp==3.5.4
|
||||
certifi==2019.3.9
|
||||
psutil==5.6.3; sys_platform == 'darwin'
|
||||
psutil==5.6.6; sys_platform == 'darwin'
|
||||
|
||||
4
setup.py
4
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="galaxy.plugin.api",
|
||||
version="0.64",
|
||||
version="0.65.1",
|
||||
description="GOG Galaxy Integrations Python API",
|
||||
author='Galaxy team',
|
||||
author_email='galaxy@gog.com',
|
||||
@@ -11,6 +11,6 @@ setup(
|
||||
install_requires=[
|
||||
"aiohttp>=3.5.4",
|
||||
"certifi>=2019.3.9",
|
||||
"psutil>=5.6.3; sys_platform == 'darwin'"
|
||||
"psutil>=5.6.6; sys_platform == 'darwin'"
|
||||
]
|
||||
)
|
||||
|
||||
@@ -152,3 +152,13 @@ class PresenceState(Enum):
|
||||
Online = "online"
|
||||
Offline = "offline"
|
||||
Away = "away"
|
||||
|
||||
|
||||
class SubscriptionDiscovery(Flag):
|
||||
"""Possible capabilities which inform what methods of subscriptions ownership detection are supported.
|
||||
|
||||
:param AUTOMATIC: integration can retrieve the proper status of subscription ownership.
|
||||
:param USER_ENABLED: integration can handle override of ~class::`Subscription.owned` value to True
|
||||
"""
|
||||
AUTOMATIC = 1
|
||||
USER_ENABLED = 2
|
||||
|
||||
@@ -360,7 +360,8 @@ class Connection():
|
||||
|
||||
@staticmethod
|
||||
def _log_error(response, error, sensitive_params):
|
||||
data = anonymise_sensitive_params(error.data, sensitive_params)
|
||||
params = error.data if error.data is not None else {}
|
||||
data = anonymise_sensitive_params(params, sensitive_params)
|
||||
logger.info("Handling error: id=%s, code=%s, description=%s, data=%s",
|
||||
response.id, error.code, error.message, data
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from galaxy.api.consts import LicenseType, LocalGameState, PresenceState
|
||||
from galaxy.api.consts import LicenseType, LocalGameState, PresenceState, SubscriptionDiscovery
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -217,6 +217,7 @@ class UserPresence:
|
||||
in_game_status: Optional[str] = None
|
||||
full_status: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Subscription:
|
||||
"""Information about a subscription.
|
||||
@@ -224,10 +225,21 @@ class Subscription:
|
||||
:param subscription_name: name of the subscription, will also be used as its identifier.
|
||||
:param owned: whether the subscription is owned or not, None if unknown.
|
||||
:param end_time: unix timestamp of when the subscription ends, None if unknown.
|
||||
:param subscription_discovery: combination of settings that can be manually
|
||||
chosen by user to determine subscription handling behaviour. For example, if the integration cannot retrieve games
|
||||
for subscription when user doesn't own it, then USER_ENABLED should not be used.
|
||||
If the integration cannot determine subscription ownership for a user then AUTOMATIC should not be used.
|
||||
|
||||
"""
|
||||
subscription_name: str
|
||||
owned: Optional[bool] = None
|
||||
end_time: Optional[int] = None
|
||||
subscription_discovery: SubscriptionDiscovery = SubscriptionDiscovery.AUTOMATIC | \
|
||||
SubscriptionDiscovery.USER_ENABLED
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.subscription_discovery in [SubscriptionDiscovery.AUTOMATIC, SubscriptionDiscovery.USER_ENABLED,
|
||||
SubscriptionDiscovery.AUTOMATIC | SubscriptionDiscovery.USER_ENABLED]
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -6,7 +6,6 @@ Exemplary simple web service could looks like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
from galaxy.http import create_client_session, handle_exception
|
||||
|
||||
class BackendClient:
|
||||
|
||||
@@ -4,7 +4,7 @@ import asyncio
|
||||
from galaxy.unittest.mock import async_return_value
|
||||
from tests import create_message, get_messages
|
||||
from galaxy.api.errors import (
|
||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied
|
||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied, UnknownError
|
||||
)
|
||||
from galaxy.api.jsonrpc import JsonRpcError
|
||||
@pytest.mark.asyncio
|
||||
@@ -40,7 +40,7 @@ async def test_refresh_credentials_success(plugin, read, write):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("exception", [
|
||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied
|
||||
BackendNotAvailable, BackendTimeout, BackendError, InvalidCredentials, NetworkError, AccessDenied, UnknownError
|
||||
])
|
||||
async def test_refresh_credentials_failure(exception, plugin, read, write):
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from galaxy.api.types import Subscription, SubscriptionGame
|
||||
from galaxy.api.consts import SubscriptionDiscovery
|
||||
from galaxy.api.errors import FailedParsingManifest, BackendError, UnknownError
|
||||
from galaxy.unittest.mock import async_return_value
|
||||
|
||||
@@ -17,8 +18,8 @@ async def test_get_subscriptions_success(plugin, read, write):
|
||||
|
||||
plugin.get_subscriptions.return_value = async_return_value([
|
||||
Subscription("1"),
|
||||
Subscription("2", False),
|
||||
Subscription("3", True, 1580899100)
|
||||
Subscription("2", False, subscription_discovery=SubscriptionDiscovery.AUTOMATIC),
|
||||
Subscription("3", True, 1580899100, SubscriptionDiscovery.USER_ENABLED)
|
||||
])
|
||||
await plugin.run()
|
||||
plugin.get_subscriptions.assert_called_with()
|
||||
@@ -30,16 +31,19 @@ async def test_get_subscriptions_success(plugin, read, write):
|
||||
"result": {
|
||||
"subscriptions": [
|
||||
{
|
||||
"subscription_name": "1"
|
||||
"subscription_name": "1",
|
||||
'subscription_discovery': 3
|
||||
},
|
||||
{
|
||||
"subscription_name": "2",
|
||||
"owned": False
|
||||
"owned": False,
|
||||
'subscription_discovery': 1
|
||||
},
|
||||
{
|
||||
"subscription_name": "3",
|
||||
"owned": True,
|
||||
"end_time": 1580899100
|
||||
"end_time": 1580899100,
|
||||
'subscription_discovery': 2
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -77,6 +81,7 @@ async def test_get_subscriptions_failure_generic(plugin, read, write, error, cod
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_subscription_games_success(plugin, read, write):
|
||||
plugin.prepare_subscription_games_context.return_value = async_return_value(5)
|
||||
|
||||
Reference in New Issue
Block a user