bemaniutils/bemani/utils/sampleclient.py

212 lines
8.8 KiB
Python
Executable File

#! /usr/bin/env python3
import argparse
import json
import requests
import sys
from typing import Dict, List, Any, Optional
class APIClient:
API_VERSION = 'v1'
def __init__(self, base_uri: str, token: str) -> None:
self.base_uri = base_uri
self.token = token
def exchange_data(self, request_uri: str, request_args: Dict[str, Any]) -> Dict[str, Any]:
if self.base_uri[-1:] != '/':
uri = '{}/{}'.format(self.base_uri, request_uri)
else:
uri = '{}{}'.format(self.base_uri, request_uri)
headers = {
'Authorization': 'Token {}'.format(self.token),
'Content-Type': 'application/json; charset=utf-8',
}
data = json.dumps(request_args).encode('utf8')
r = requests.request(
'GET',
uri,
headers=headers,
data=data,
allow_redirects=False,
)
if r.headers['content-type'] != 'application/json; charset=utf-8':
raise Exception('API returned invalid content type \'{}\'!'.format(r.headers['content-type']))
jsondata = r.json()
if r.status_code == 200:
return jsondata
if 'error' not in jsondata:
raise Exception('API returned error code {} but did not include \'error\' attribute in response JSON!'.format(r.status_code))
error = jsondata['error']
if r.status_code == 401:
raise Exception('The API token used is not authorized against the server!')
if r.status_code == 404:
raise Exception('The server does not support this game/version or request object and returned \'{}\''.format(error))
if r.status_code == 405:
raise Exception('The server did not recognize the request and returned \'{}\''.format(error))
if r.status_code == 500:
raise Exception('The server had an error processing the request and returned \'{}\''.format(error))
if r.status_code == 501:
raise Exception('The server does not support this version of the API!')
raise Exception('The server returned an invalid status code {}!'.format(r.status_code))
def info_exchange(self) -> None:
resp = self.exchange_data('', {})
print('Server name: {}'.format(resp['name']))
print('Server admin email: {}'.format(resp['email']))
print('Server supported versions: {}'.format(', '.join(resp['versions'])))
def __id_check(self, idtype: str, ids: List[str]) -> None:
if idtype not in ['card', 'song', 'instance', 'server']:
raise Exception('Invalid ID type provided!')
if idtype == 'card' and len(ids) == 0:
raise Exception('Invalid number of IDs given!')
if idtype == 'song' and len(ids) not in [1, 2]:
raise Exception('Invalid number of IDs given!')
if idtype == 'instance' and len(ids) != 3:
raise Exception('Invalid number of IDs given!')
if idtype == 'server' and len(ids) != 0:
raise Exception('Invalid number of IDs given!')
def records_exchange(self, game: str, version: str, idtype: str, ids: List[str], since: Optional[int], until: Optional[int]) -> None:
self.__id_check(idtype, ids)
params = {
'ids': ids,
'type': idtype,
'objects': ['records'],
} # type: Dict[str, Any]
if since is not None:
params['since'] = since
if until is not None:
params['until'] = until
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
params,
)
print(json.dumps(resp['records'], indent=4))
def profile_exchange(self, game: str, version: str, idtype: str, ids: List[str]) -> None:
self.__id_check(idtype, ids)
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': ids,
'type': idtype,
'objects': ['profile'],
},
)
print(json.dumps(resp['profile'], indent=4))
def statistics_exchange(self, game: str, version: str, idtype: str, ids: List[str]) -> None:
self.__id_check(idtype, ids)
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': ids,
'type': idtype,
'objects': ['statistics'],
},
)
print(json.dumps(resp['statistics'], indent=4))
def catalog_exchange(self, game: str, version: str) -> None:
resp = self.exchange_data(
'{}/{}/{}'.format(self.API_VERSION, game, version),
{
'ids': [],
'type': 'server',
'objects': ['catalog'],
},
)
print(json.dumps(resp['catalog'], indent=4))
def main():
# Global arguments
parser = argparse.ArgumentParser(description='A sample API client for an e-AMUSEMENT API provider.')
parser.add_argument('-t', '--token', type=str, required=True, help='The authorization token for speaing to the API.')
parser.add_argument('-b', '--base', type=str, required=True, help='Base URI to connect to for all requests.')
subparser = parser.add_subparsers(dest='request')
# Info request
subparser.add_parser('info')
# Score request
record_parser = subparser.add_parser('records')
record_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look records up for.')
record_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look records up for.')
record_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'song', 'instance', 'server'], help='The type of ID used to look up records.')
record_parser.add_argument('-s', '--since', metavar='TIMESTAMP', default=None, type=int, help='Only load records updated since TIMESTAMP')
record_parser.add_argument('-u', '--until', metavar='TIMESTAMP', default=None, type=int, help='Only load records updated before TIMESTAMP')
record_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up records for.')
# Profile request
profile_parser = subparser.add_parser('profile')
profile_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look profiles up for.')
profile_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look profiles up for.')
profile_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'server'], help='The type of ID used to look up profiles.')
profile_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up profiles for.')
# Statistics request
statistic_parser = subparser.add_parser('statistics')
statistic_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look statistics up for.')
statistic_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look statistics up for.')
statistic_parser.add_argument('-t', '--type', type=str, required=True, choices=['card', 'song', 'instance', 'server'], help='The type of ID used to look up statistics.')
statistic_parser.add_argument('id', metavar='ID', nargs='*', type=str, help='The ID we will look up statistics for.')
# Catalog request
catalog_parser = subparser.add_parser('catalog')
catalog_parser.add_argument('-g', '--game', type=str, required=True, help='The game we want to look catalog entries up for.')
catalog_parser.add_argument('-v', '--version', type=str, required=True, help='The version we want to look catalog entries up for.')
# Grab args
args = parser.parse_args()
client = APIClient(args.base, args.token)
if args.request == 'info':
client.info_exchange()
elif args.request == 'records':
client.records_exchange(
args.game,
args.version,
args.type,
args.id,
args.since,
args.until,
)
elif args.request == 'profile':
client.profile_exchange(
args.game,
args.version,
args.type,
args.id,
)
elif args.request == 'statistics':
client.statistics_exchange(
args.game,
args.version,
args.type,
args.id,
)
elif args.request == 'catalog':
client.catalog_exchange(
args.game,
args.version,
)
else:
raise Exception('Invalid request type {}!'.format(args.request))
if __name__ == '__main__':
try:
main()
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)