mirror of
https://github.com/derrod/legendary.git
synced 2024-12-22 17:55:27 +00:00
[api/cli/core] Make API timeout configurable
This commit is contained in:
parent
dd099c0afd
commit
03ef95923d
|
@ -29,7 +29,7 @@ class EPCAPI:
|
||||||
_store_gql_host = 'store-launcher.epicgames.com'
|
_store_gql_host = 'store-launcher.epicgames.com'
|
||||||
_artifact_service_host = 'artifact-public-service-prod.beee.live.use1a.on.epicgames.com'
|
_artifact_service_host = 'artifact-public-service-prod.beee.live.use1a.on.epicgames.com'
|
||||||
|
|
||||||
def __init__(self, lc='en', cc='US'):
|
def __init__(self, lc='en', cc='US', timeout=10.0):
|
||||||
self.log = logging.getLogger('EPCAPI')
|
self.log = logging.getLogger('EPCAPI')
|
||||||
|
|
||||||
self.session = requests.session()
|
self.session = requests.session()
|
||||||
|
@ -47,6 +47,7 @@ class EPCAPI:
|
||||||
|
|
||||||
self.language_code = lc
|
self.language_code = lc
|
||||||
self.country_code = cc
|
self.country_code = cc
|
||||||
|
self.request_timeout = timeout
|
||||||
|
|
||||||
def update_egs_params(self, egs_params):
|
def update_egs_params(self, egs_params):
|
||||||
# update user-agent
|
# update user-agent
|
||||||
|
@ -66,7 +67,8 @@ class EPCAPI:
|
||||||
|
|
||||||
def resume_session(self, session):
|
def resume_session(self, session):
|
||||||
self.session.headers['Authorization'] = f'bearer {session["access_token"]}'
|
self.session.headers['Authorization'] = f'bearer {session["access_token"]}'
|
||||||
r = self.session.get(f'https://{self._oauth_host}/account/api/oauth/verify')
|
r = self.session.get(f'https://{self._oauth_host}/account/api/oauth/verify',
|
||||||
|
timeout=self.request_timeout)
|
||||||
if r.status_code >= 500:
|
if r.status_code >= 500:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
|
@ -97,7 +99,8 @@ class EPCAPI:
|
||||||
raise ValueError('At least one token type must be specified!')
|
raise ValueError('At least one token type must be specified!')
|
||||||
|
|
||||||
r = self.session.post(f'https://{self._oauth_host}/account/api/oauth/token',
|
r = self.session.post(f'https://{self._oauth_host}/account/api/oauth/token',
|
||||||
data=params, auth=self._oauth_basic)
|
data=params, auth=self._oauth_basic,
|
||||||
|
timeout=self.request_timeout)
|
||||||
# Only raise HTTP exceptions on server errors
|
# Only raise HTTP exceptions on server errors
|
||||||
if r.status_code >= 500:
|
if r.status_code >= 500:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
@ -115,10 +118,12 @@ class EPCAPI:
|
||||||
return j
|
return j
|
||||||
|
|
||||||
def invalidate_session(self): # unused
|
def invalidate_session(self): # unused
|
||||||
r = self.session.delete(f'https://{self._oauth_host}/account/api/oauth/sessions/kill/{self.access_token}')
|
_ = self.session.delete(f'https://{self._oauth_host}/account/api/oauth/sessions/kill/{self.access_token}',
|
||||||
|
timeout=self.request_timeout)
|
||||||
|
|
||||||
def get_game_token(self):
|
def get_game_token(self):
|
||||||
r = self.session.get(f'https://{self._oauth_host}/account/api/oauth/exchange')
|
r = self.session.get(f'https://{self._oauth_host}/account/api/oauth/exchange',
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -126,32 +131,35 @@ class EPCAPI:
|
||||||
user_id = self.user.get('account_id')
|
user_id = self.user.get('account_id')
|
||||||
r = self.session.post(f'https://{self._ecommerce_host}/ecommerceintegration/api/public/'
|
r = self.session.post(f'https://{self._ecommerce_host}/ecommerceintegration/api/public/'
|
||||||
f'platforms/EPIC/identities/{user_id}/ownershipToken',
|
f'platforms/EPIC/identities/{user_id}/ownershipToken',
|
||||||
data=dict(nsCatalogItemId=f'{namespace}:{catalog_item_id}'))
|
data=dict(nsCatalogItemId=f'{namespace}:{catalog_item_id}'),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.content
|
return r.content
|
||||||
|
|
||||||
def get_external_auths(self):
|
def get_external_auths(self):
|
||||||
user_id = self.user.get('account_id')
|
user_id = self.user.get('account_id')
|
||||||
r = self.session.get(f'https://{self._oauth_host}/account/api/public/account/{user_id}/externalAuths')
|
r = self.session.get(f'https://{self._oauth_host}/account/api/public/account/{user_id}/externalAuths',
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def get_game_assets(self, platform='Windows', label='Live'):
|
def get_game_assets(self, platform='Windows', label='Live'):
|
||||||
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/{platform}',
|
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/{platform}',
|
||||||
params=dict(label=label))
|
params=dict(label=label), timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def get_game_manifest(self, namespace, catalog_item_id, app_name, platform='Windows', label='Live'):
|
def get_game_manifest(self, namespace, catalog_item_id, app_name, platform='Windows', label='Live'):
|
||||||
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/v2/platform'
|
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/v2/platform'
|
||||||
f'/{platform}/namespace/{namespace}/catalogItem/{catalog_item_id}/app'
|
f'/{platform}/namespace/{namespace}/catalogItem/{catalog_item_id}/app'
|
||||||
f'/{app_name}/label/{label}')
|
f'/{app_name}/label/{label}',
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def get_launcher_manifests(self, platform='Windows', label=None):
|
def get_launcher_manifests(self, platform='Windows', label=None):
|
||||||
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/v2/platform/'
|
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/v2/platform/'
|
||||||
f'{platform}/launcher',
|
f'{platform}/launcher', timeout=self.request_timeout,
|
||||||
params=dict(label=label if label else self._label))
|
params=dict(label=label if label else self._label))
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
@ -159,7 +167,7 @@ class EPCAPI:
|
||||||
def get_user_entitlements(self):
|
def get_user_entitlements(self):
|
||||||
user_id = self.user.get('account_id')
|
user_id = self.user.get('account_id')
|
||||||
r = self.session.get(f'https://{self._entitlements_host}/entitlement/api/account/{user_id}/entitlements',
|
r = self.session.get(f'https://{self._entitlements_host}/entitlement/api/account/{user_id}/entitlements',
|
||||||
params=dict(start=0, count=5000))
|
params=dict(start=0, count=5000), timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -167,7 +175,7 @@ class EPCAPI:
|
||||||
r = self.session.get(f'https://{self._catalog_host}/catalog/api/shared/namespace/{namespace}/bulk/items',
|
r = self.session.get(f'https://{self._catalog_host}/catalog/api/shared/namespace/{namespace}/bulk/items',
|
||||||
params=dict(id=catalog_item_id, includeDLCDetails=True, includeMainGameDetails=True,
|
params=dict(id=catalog_item_id, includeDLCDetails=True, includeMainGameDetails=True,
|
||||||
country=self.country_code, locale=self.language_code),
|
country=self.country_code, locale=self.language_code),
|
||||||
timeout=timeout)
|
timeout=timeout or self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json().get(catalog_item_id, None)
|
return r.json().get(catalog_item_id, None)
|
||||||
|
|
||||||
|
@ -177,7 +185,8 @@ class EPCAPI:
|
||||||
r = self.session.post(f'https://{self._artifact_service_host}/artifact-service/api/public/v1/dependency/'
|
r = self.session.post(f'https://{self._artifact_service_host}/artifact-service/api/public/v1/dependency/'
|
||||||
f'sandbox/{sandbox_id}/artifact/{artifact_id}/ticket',
|
f'sandbox/{sandbox_id}/artifact/{artifact_id}/ticket',
|
||||||
json=dict(label=label, expiresInSeconds=300, platform=platform),
|
json=dict(label=label, expiresInSeconds=300, platform=platform),
|
||||||
params=dict(useSandboxAwareLabel='false'))
|
params=dict(useSandboxAwareLabel='false'),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -185,14 +194,16 @@ class EPCAPI:
|
||||||
# Untested as get_artifact_service_ticket is not working yet either
|
# Untested as get_artifact_service_ticket is not working yet either
|
||||||
r = self.session.post(f'https://{self._launcher_host}/launcher/api/public/assets/v2/'
|
r = self.session.post(f'https://{self._launcher_host}/launcher/api/public/assets/v2/'
|
||||||
f'by-ticket/app/{artifact_id}',
|
f'by-ticket/app/{artifact_id}',
|
||||||
headers=dict(authorization=f'bearer {ticket["signedTicket"]}'))
|
headers=dict(authorization=f'bearer {ticket["signedTicket"]}'),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
def get_library_items(self, include_metadata=True):
|
def get_library_items(self, include_metadata=True):
|
||||||
records = []
|
records = []
|
||||||
r = self.session.get(f'https://{self._library_host}/library/api/public/items',
|
r = self.session.get(f'https://{self._library_host}/library/api/public/items',
|
||||||
params=dict(includeMetadata=include_metadata))
|
params=dict(includeMetadata=include_metadata),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
j = r.json()
|
j = r.json()
|
||||||
records.extend(j['records'])
|
records.extend(j['records'])
|
||||||
|
@ -200,7 +211,8 @@ class EPCAPI:
|
||||||
# Fetch remaining library entries as long as there is a cursor
|
# Fetch remaining library entries as long as there is a cursor
|
||||||
while cursor := j['responseMetadata'].get('nextCursor', None):
|
while cursor := j['responseMetadata'].get('nextCursor', None):
|
||||||
r = self.session.get(f'https://{self._library_host}/library/api/public/items',
|
r = self.session.get(f'https://{self._library_host}/library/api/public/items',
|
||||||
params=dict(includeMetadata=include_metadata, cursor=cursor))
|
params=dict(includeMetadata=include_metadata, cursor=cursor),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
j = r.json()
|
j = r.json()
|
||||||
records.extend(j['records'])
|
records.extend(j['records'])
|
||||||
|
@ -217,10 +229,13 @@ class EPCAPI:
|
||||||
|
|
||||||
if filenames:
|
if filenames:
|
||||||
r = self.session.post(f'https://{self._datastorage_host}/api/v1/access/egstore/savesync/'
|
r = self.session.post(f'https://{self._datastorage_host}/api/v1/access/egstore/savesync/'
|
||||||
f'{user_id}/{app_name}', json=dict(files=filenames))
|
f'{user_id}/{app_name}',
|
||||||
|
json=dict(files=filenames),
|
||||||
|
timeout=self.request_timeout)
|
||||||
else:
|
else:
|
||||||
r = self.session.get(f'https://{self._datastorage_host}/api/v1/access/egstore/savesync/'
|
r = self.session.get(f'https://{self._datastorage_host}/api/v1/access/egstore/savesync/'
|
||||||
f'{user_id}/{app_name}')
|
f'{user_id}/{app_name}',
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -229,7 +244,7 @@ class EPCAPI:
|
||||||
|
|
||||||
def delete_game_cloud_save_file(self, path):
|
def delete_game_cloud_save_file(self, path):
|
||||||
url = f'https://{self._datastorage_host}/api/v1/data/egstore/{path}'
|
url = f'https://{self._datastorage_host}/api/v1/data/egstore/{path}'
|
||||||
r = self.session.delete(url)
|
r = self.session.delete(url, timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
def store_get_uplay_codes(self):
|
def store_get_uplay_codes(self):
|
||||||
|
@ -237,7 +252,8 @@ class EPCAPI:
|
||||||
r = self.session.post(f'https://{self._store_gql_host}/graphql',
|
r = self.session.post(f'https://{self._store_gql_host}/graphql',
|
||||||
headers={'user-agent': self._store_user_agent},
|
headers={'user-agent': self._store_user_agent},
|
||||||
json=dict(query=uplay_codes_query,
|
json=dict(query=uplay_codes_query,
|
||||||
variables=dict(accountId=user_id)))
|
variables=dict(accountId=user_id)),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -248,7 +264,8 @@ class EPCAPI:
|
||||||
json=dict(query=uplay_claim_query,
|
json=dict(query=uplay_claim_query,
|
||||||
variables=dict(accountId=user_id,
|
variables=dict(accountId=user_id,
|
||||||
uplayAccountId=uplay_id,
|
uplayAccountId=uplay_id,
|
||||||
gameId=game_id)))
|
gameId=game_id)),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
@ -258,6 +275,7 @@ class EPCAPI:
|
||||||
headers={'user-agent': self._store_user_agent},
|
headers={'user-agent': self._store_user_agent},
|
||||||
json=dict(query=uplay_redeem_query,
|
json=dict(query=uplay_redeem_query,
|
||||||
variables=dict(accountId=user_id,
|
variables=dict(accountId=user_id,
|
||||||
uplayAccountId=uplay_id)))
|
uplayAccountId=uplay_id)),
|
||||||
|
timeout=self.request_timeout)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
|
@ -39,8 +39,8 @@ logger = logging.getLogger('cli')
|
||||||
|
|
||||||
|
|
||||||
class LegendaryCLI:
|
class LegendaryCLI:
|
||||||
def __init__(self, override_config=None):
|
def __init__(self, override_config=None, api_timeout=None):
|
||||||
self.core = LegendaryCore(override_config)
|
self.core = LegendaryCore(override_config, timeout=api_timeout)
|
||||||
self.logger = logging.getLogger('cli')
|
self.logger = logging.getLogger('cli')
|
||||||
self.logging_queue = None
|
self.logging_queue = None
|
||||||
|
|
||||||
|
@ -2142,6 +2142,9 @@ def main():
|
||||||
help='Pretty-print JSON')
|
help='Pretty-print JSON')
|
||||||
parser.add_argument('-H', '--full-help', dest='full_help', action='store_true',
|
parser.add_argument('-H', '--full-help', dest='full_help', action='store_true',
|
||||||
help='Show full help (including individual command help)')
|
help='Show full help (including individual command help)')
|
||||||
|
parser.add_argument('-T', '--api-timeout', dest='api_timeout', action='store',
|
||||||
|
type=float, default=10, metavar='<seconds>',
|
||||||
|
help='API HTTP request timeout (default: 10 seconds)')
|
||||||
|
|
||||||
# all the commands
|
# all the commands
|
||||||
subparsers = parser.add_subparsers(title='Commands', dest='subparser_name', metavar='<command>')
|
subparsers = parser.add_subparsers(title='Commands', dest='subparser_name', metavar='<command>')
|
||||||
|
@ -2477,7 +2480,7 @@ def main():
|
||||||
print(subparser.format_help())
|
print(subparser.format_help())
|
||||||
return
|
return
|
||||||
|
|
||||||
cli = LegendaryCLI(override_config=args.config_file)
|
cli = LegendaryCLI(override_config=args.config_file, api_timeout=args.api_timeout)
|
||||||
ql = cli.setup_threaded_logging()
|
ql = cli.setup_threaded_logging()
|
||||||
|
|
||||||
config_ll = cli.core.lgd.config.get('Legendary', 'log_level', fallback='info')
|
config_ll = cli.core.lgd.config.get('Legendary', 'log_level', fallback='info')
|
||||||
|
|
|
@ -56,9 +56,9 @@ class LegendaryCore:
|
||||||
"""
|
"""
|
||||||
_egl_version = '11.0.1-14907503+++Portal+Release-Live'
|
_egl_version = '11.0.1-14907503+++Portal+Release-Live'
|
||||||
|
|
||||||
def __init__(self, override_config=None):
|
def __init__(self, override_config=None, timeout=10.0):
|
||||||
self.log = logging.getLogger('Core')
|
self.log = logging.getLogger('Core')
|
||||||
self.egs = EPCAPI()
|
self.egs = EPCAPI(timeout=timeout)
|
||||||
self.lgd = LGDLFS(config_file=override_config)
|
self.lgd = LGDLFS(config_file=override_config)
|
||||||
self.egl = EPCLFS()
|
self.egl = EPCLFS()
|
||||||
self.lgdapi = LGDAPI()
|
self.lgdapi = LGDAPI()
|
||||||
|
|
Loading…
Reference in a new issue