async def get_token(message, config, logger, **kwargs): account_info = protobuf.to_account_info(message.account_info) token = await logic.find_token( account_info, expiration_delta=config['custom']['token_expiration_delta']) if token.is_error('AccountRemovedByGDPR'): raise tt_exceptions.ApiError( code='xsolla.get_token.account_removed_by_gdpr', message='Account removed by user request and can not be processed') if token.is_error(): logger.info('token not found: %s', token.name) xsolla_client = xsolla.get_client(config['custom'], mode=message.mode) token = await logic.request_token(account_info, xsolla_client, logger) if token.is_error(): raise tt_exceptions.ApiError( code='xsolla.get_token.can_not_receive_token', message='Can not receive token from XSolla services') return xsolla_pb2.GetTokenResponse(token=token.value.value)
async def start_transaction(message, **kwargs): logger = log.ContextLogger() try: transaction_id = await operations.start_transaction( operations=[ protobuf.to_operation(operation) for operation in message.operations ], lifetime=datetime.timedelta(seconds=message.lifetime), autocommit=message.autocommit, restrictions=protobuf.to_restrictions(message.restrictions), logger=logger) except exceptions.NoOperationsInTransaction as e: raise tt_exceptions.ApiError( code='bank.start_transaction.no_operations_specified', message=str(e)) except exceptions.BalanceChangeExceededRestrictions as e: raise tt_exceptions.ApiError( code='bank.start_transaction.restrictions_exceeded', message=str(e)) return bank_pb2.StartTransactionResponse(transaction_id=transaction_id)
async def xsolla_hook(message, config, logger, **kwargs): notification_type = message.get('notification_type') if notification_type == 'user_validation': try: account_id = int(message['user']['id']) except ValueError: raise tt_exceptions.ApiError( code='INVALID_USER', message='Account with such credentials has not found', details={ 'code': 'xsolla.hook.user_validation.wrong_account_id_format' }) is_valid = await logic.validate_user(account_id=account_id) if not is_valid: raise tt_exceptions.ApiError( code='INVALID_USER', message='Account with such credentials has not found', details={ 'code': 'xsolla.hook.user_validation.account_not_found' }) elif notification_type == 'payment': invoice = logic.invoice_from_xsolla_data(message) result = await logic.register_invoice(invoice) if result.is_error(): raise tt_exceptions.ApiError( code='xsolla.hook.payment.can_not_register_invoice', message=f'Can not register invoice: {result.name}', details={ 'code': 'xsolla.hook.payment.can_not_register_invoice' }) elif notification_type == 'refund': result = await logic.register_cancellation( xsolla_id=message['transaction']['id']) if result.is_error(): raise tt_exceptions.ApiError( code='xsolla.hook.refund.can_not_register_cancelation', message=f'Can not register cancelation: {result.name}') else: raise tt_exceptions.ApiError( code='INVALID_PARAMETER', message='Service does not expect such notification type', details={ 'notification_type': notification_type, 'code': 'xsolla.hook.unknown_notification_type' }) return {'result': 'ok'}
async def place_sell_lot(message, **kwargs): try: lots_ids = await operations.place_sell_lots(lots=[protobuf.to_sell_lot(lot) for lot in message.lots]) except exceptions.SellLotForItemAlreadyCreated as e: raise tt_exceptions.ApiError(code='market.apply.sell_lot_for_item_already_created', message=str(e)) except exceptions.SellLotMaximumPriceExceeded as e: raise tt_exceptions.ApiError(code='market.apply.sell_lot_maximum_price_exceeded', message=str(e)) except exceptions.SellLotPriceBelowZero as e: raise tt_exceptions.ApiError(code='market.apply.sell_lot_price_below_zero', message=str(e)) return market_pb2.PlaceSellLotResponse(lots_ids=[lot_id.hex for lot_id in lots_ids])
async def change_speed(message, config, **kwargs): if str(message.type) not in config['custom']['types']: raise tt_exceptions.ApiError(code='timers.change_speed.unknown_type', message='unknown timer type {}'.format(message.type)) try: timer = await operations.change_speed(owner_id=message.owner_id, entity_id=message.entity_id, type=message.type, speed=message.speed) except exceptions.TimerNotFound as e: raise tt_exceptions.ApiError(code='timers.change_speed.timer_not_found', message=str(e)) return timers_pb2.ChangeSpeedResponse(timer=protobuf.from_timer(timer))
async def xsolla_extractor(request, config, logger): content = await request.content.read() auth_header = request.headers.get('Authorization', '') request_signature = get_auth_signature(auth_header) if request_signature is None: raise tt_exceptions.ApiError( code='INVALID_SIGNATURE', message='signature has not found in headers', details={ 'AuthorisationHeader': auth_header, 'code': 'xsolla.hook.signature_has_not_found' }) expected_signature = get_expected_auth_signature( content, config['custom']['hooks_key']) if request_signature != expected_signature: raise tt_exceptions.ApiError( code='INVALID_SIGNATURE', message='Received signature does not equal to calculated', details={ 'AuthorisationHeader': auth_header, 'code': 'xsolla.hook.unexpected_signature' }) data = s11n.from_json(content) if 'settings' not in data: raise tt_exceptions.ApiError( code='INVALID_PARAMETER', message='settings not found in request body', details={'code': 'xsolla.hook.no_settings_info'}) if data['settings'].get('project_id') != config['custom']['project_id']: raise tt_exceptions.ApiError( code='INVALID_PARAMETER', message='Unexpected project_id on request body', details={'code': 'xsolla.hook.wrong_project_id'}) if data['settings'].get('merchant_id') != config['custom']['merchant_id']: raise tt_exceptions.ApiError( code='INVALID_PARAMETER', message='Unexpected merchant_id on request body', details={'code': 'xsolla.hook.wrong_merchant_id'}) return data
async def create_battle(message, config, **kwargs): try: battle_id = await operations.create_battle( matchmaker_type=message.matchmaker_type, participants_ids=list(message.participants_ids)) except exceptions.DuplicateBattleParticipants as e: raise tt_exceptions.ApiError( code='matchmaker.create_battle.duplicate_participants', message=str(e)) except exceptions.BattleParticipantsIntersection as e: raise tt_exceptions.ApiError( code='matchmaker.create_battle.participants_intersection', message=str(e)) return matchmaker_pb2.CreateBattleResponse(battle_id=battle_id)
async def create_timer(message, config, **kwargs): if str(message.type) not in config['custom']['types']: raise tt_exceptions.ApiError(code='timers.create_timer.unknown_type', message='unknown timer type {}'.format(message.type)) try: timer = await operations.create_timer(owner_id=message.owner_id, entity_id=message.entity_id, type=message.type, speed=message.speed, border=message.border, callback_data=message.callback_data, resources=message.resources) except exceptions.TimerAlreadyExists as e: raise tt_exceptions.ApiError(code='timers.create_timer.duplicate_timer', message=str(e)) return timers_pb2.CreateTimerResponse(timer=protobuf.from_timer(timer))
async def rollback_transaction(message, **kwargs): logger = log.ContextLogger() try: await operations.rollback_transaction( transaction_id=message.transaction_id, logger=logger) except exceptions.NoTransactionToRollback as e: raise tt_exceptions.ApiError( code='bank.rollback_transaction.no_transacton_to_rollback', message=str(e)) except exceptions.BalanceChangeExceededRestrictions as e: raise tt_exceptions.ApiError( code='bank.start_transaction.restrictions_exceeded', message=str(e)) return bank_pb2.RollbackTransactionResponse()
async def data_protection_delete_data(message, config, **kwargs): if config['custom']['data_protector']['secret'] != message.secret: raise tt_exceptions.ApiError(code='properties.data_protection_delete_data.wrong_secret', message='wrong secret code') await operations.clean_object_properties(object_id=int(message.account_id)) return data_protector_pb2.PluginDeletionResponse(result=data_protector_pb2.PluginDeletionResponse.ResultType.SUCCESS)
async def request_report(message, config, **kwargs): if len(message.ids) == 0: raise tt_exceptions.ApiError( code='data_protector.request_report.no_ids_specified', message='no user identifies specified, no data to collect') for source_info in message.ids: if source_info.source not in config['custom']['sources']: raise tt_exceptions.ApiError( code='data_protector.request_report.wrong_source_id', message=f'unknowm source: {source_info.source}') report_id = await operations.create_report_base([ (source_info.source, source_info.id) for source_info in message.ids ]) return data_protector_pb2.RequestReportResponse(report_id=report_id.hex)
async def request_deletion(message, config, **kwargs): if len(message.ids) == 0: raise tt_exceptions.ApiError( code='data_protector.request_deletion.no_ids_specified', message='no user identifies specified, no data to collect') for source_info in message.ids: if source_info.source not in config['custom']['sources']: raise tt_exceptions.ApiError( code='data_protector.request_deletion.wrong_source_id', message=f'unknowm source: {source_info.source}') await operations.mark_for_deletion(core_id=message.core_id, ids=[(source_info.source, source_info.id) for source_info in message.ids]) return data_protector_pb2.RequestDeletionResponse()
async def data_protection_collect_data(message, config, **kwargs): if config['custom']['data_protector']['secret'] != message.secret: raise tt_exceptions.ApiError(code='properties.data_protection_collect_data.wrong_secret', message='wrong secret code') report = await operations.get_data_report(object_id=int(message.account_id)) return data_protector_pb2.PluginReportResponse(result=data_protector_pb2.PluginReportResponse.ResultType.SUCCESS, data=s11n.to_json(report))
async def accept_battle_request(message, config, **kwargs): try: battle_id, participants_ids = await operations.accept_battle_request( battle_request_id=message.battle_request_id, acceptor_id=message.acceptor_id) except exceptions.NoBattleRequestFound as e: raise tt_exceptions.ApiError( code='matchmaker.accept_battle_request.no_battle_request_found', message=str(e)) except exceptions.DuplicateBattleParticipants as e: raise tt_exceptions.ApiError( code='matchmaker.accept_battle_request.duplicate_participants', message=str(e)) except exceptions.BattleParticipantsIntersection as e: raise tt_exceptions.ApiError( code='matchmaker.accept_battle_request.participants_intersection', message=str(e)) return matchmaker_pb2.AcceptBattleRequestResponse( battle_id=battle_id, participants_ids=list(participants_ids))
async def apply(message, **kwargs): try: await operations.apply(operations=[ protobuf.to_operation(operation) for operation in message.operations ]) except exceptions.OperationsError as e: raise tt_exceptions.ApiError(code='storage.apply.operation_error', message=str(e)) return storage_pb2.ApplyResponse()
async def commit_transaction(message, **kwargs): logger = log.ContextLogger() try: await operations.commit_transaction( transaction_id=message.transaction_id, logger=logger) except exceptions.NoTransactionToCommit as e: raise tt_exceptions.ApiError( code='bank.commit_transaction.no_transacton_to_commit', message=str(e)) return bank_pb2.CommitTransactionResponse()
async def data_protection_collect_data(message, config, **kwargs): if config['custom']['data_protector']['secret'] != message.secret: raise tt_exceptions.ApiError( code='discord.data_protection_collect_data.wrong_secret', message='wrong secret code') account_info = await operations.get_account_info_by_game_id( int(message.account_id), create_if_not_exists=False) report = await operations.get_data_report(account_info=account_info) return data_protector_pb2.PluginReportResponse( result=data_protector_pb2.PluginReportResponse.ResultType.SUCCESS, data=s11n.to_json(report))
async def data_protection_delete_data(message, config, **kwargs): if config['custom']['data_protector']['secret'] != message.secret: raise tt_exceptions.ApiError( code='discord.data_protection_delete_data.wrong_secret', message='wrong secret code') account_info = await operations.get_account_info_by_game_id( int(message.account_id), create_if_not_exists=False) if account_info.discord_id is not None: await operations.unbind_discord_user(discord_id=account_info.discord_id ) return data_protector_pb2.PluginDeletionResponse( result=data_protector_pb2.PluginDeletionResponse.ResultType.SUCCESS)