async def send(conn, batch_list, timeout): batch_request = client_pb2.ClientBatchSubmitRequest() batch_request.batches.extend(list(batch_list.batches)) batch_request.wait_for_commit = True validator_response = await conn.send( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, batch_request.SerializeToString(), timeout ) client_response = client_pb2.ClientBatchSubmitResponse() client_response.ParseFromString(validator_response.content) resp = client_response.batch_statuses[0] if resp.status == client_pb2.BatchStatus.COMMITTED: return resp elif resp.status == client_pb2.BatchStatus.INVALID: raise ApiBadRequest('Bad Request: {}'.format( resp.invalid_transactions[0].message )) elif resp.status == client_pb2.BatchStatus.PENDING: raise ApiInternalError( 'Internal Error: Transaction submitted but timed out.' ) elif resp.status == client_pb2.BatchStatus.UNKNOWN: raise ApiInternalError( 'Internal Error: Something went wrong. Try again later.' )
async def submit_batches(self, request): """Accepts a binary encoded BatchList and submits it to the validator. Request: body: octet-stream BatchList of one or more Batches query: - wait: Request should not return until all batches committed Response: status: - 200: Batches submitted, but wait timed out before committed - 201: All batches submitted and committed - 202: Batches submitted and pending (not told to wait) data: Status of uncommitted batches (if any, when told to wait) link: /batches or /batch_status link for submitted batches """ # Parse request if request.headers['Content-Type'] != 'application/octet-stream': return errors.WrongBodyType() payload = await request.read() if not payload: return errors.EmptyProtobuf() try: batch_list = BatchList() batch_list.ParseFromString(payload) except DecodeError: return errors.BadProtobuf() # Query validator error_traps = [error_handlers.InvalidBatch()] validator_query = client_pb2.ClientBatchSubmitRequest( batches=batch_list.batches) self._set_wait(request, validator_query) response = await self._query_validator( Message.CLIENT_BATCH_SUBMIT_REQUEST, client_pb2.ClientBatchSubmitResponse, validator_query, error_traps) # Build response envelope data = response['batch_statuses'] or None link = '{}://{}/batch_status?id={}'.format( request.scheme, request.host, ','.join(b.header_signature for b in batch_list.batches)) if data is None: status = 202 elif any(s != 'COMMITTED' for _, s in data.items()): status = 200 else: status = 201 data = None link = link.replace('batch_status', 'batches') return self._wrap_response(data=data, metadata={'link': link}, status=status)
async def submit_batches(self, request): """Accepts a binary encoded BatchList and submits it to the validator. Request: body: octet-stream BatchList of one or more Batches Response: status: - 202: Batches submitted and pending link: /batches or /batch_status link for submitted batches """ timer_ctx = self._post_batches_total_time.time() self._post_batches_count.inc() # Parse request if request.headers['Content-Type'] != 'application/octet-stream': LOGGER.debug('Submission headers had wrong Content-Type: %s', request.headers['Content-Type']) self._post_batches_error.inc() raise errors.SubmissionWrongContentType() body = await request.read() if not body: LOGGER.debug('Submission contained an empty body') self._post_batches_error.inc() raise errors.NoBatchesSubmitted() try: batch_list = BatchList() batch_list.ParseFromString(body) except DecodeError: LOGGER.debug('Submission body could not be decoded: %s', body) self._post_batches_error.inc() raise errors.BadProtobufSubmitted() # Query validator error_traps = [error_handlers.BatchInvalidTrap] validator_query = client_pb2.ClientBatchSubmitRequest( batches=batch_list.batches) with self._post_batches_validator_time.time(): await self._query_validator(Message.CLIENT_BATCH_SUBMIT_REQUEST, client_pb2.ClientBatchSubmitResponse, validator_query, error_traps) # Build response envelope id_string = ','.join(b.header_signature for b in batch_list.batches) status = 202 link = self._build_url(request, path='/batch_status', id=id_string) retval = self._wrap_response(request, metadata={'link': link}, status=status) timer_ctx.stop() return retval
def batches_post(self, request): """ Takes protobuf binary from HTTP POST, and sends it to the validator """ # Parse request if request.headers['Content-Type'] != 'application/octet-stream': return errors.WrongBodyType() payload = yield from request.read() if not payload: return errors.EmptyProtobuf() try: batch_list = BatchList() batch_list.ParseFromString(payload) except DecodeError: return errors.BadProtobuf() # Query validator error_traps = [error_handlers.InvalidBatch()] validator_query = client.ClientBatchSubmitRequest( batches=batch_list.batches) self._set_wait(request, validator_query) response = self._query_validator(Message.CLIENT_BATCH_SUBMIT_REQUEST, client.ClientBatchSubmitResponse, validator_query, error_traps) # Build response data = response['batch_statuses'] metadata = { 'link': '{}://{}/batch_status?id={}'.format( request.scheme, request.host, ','.join(b.header_signature for b in batch_list.batches)) } if not data: status = 202 data = None elif any(s != 'COMMITTED' for _, s in data.items()): status = 200 else: status = 201 data = None # Replace with /batches link when implemented metadata = None return RouteHandler._wrap_response(data=data, metadata=metadata, status=status)
async def submit_batches(self, request): """Accepts a binary encoded BatchList and submits it to the validator. Request: body: octet-stream BatchList of one or more Batches query: - wait: Request should not return until all batches committed Response: status: - 200: Batches submitted, but wait timed out before committed - 201: All batches submitted and committed - 202: Batches submitted and pending (not told to wait) data: Status of uncommitted batches (if any, when told to wait) link: /batches or /batch_status link for submitted batches """ timer_ctx = self._post_batches_total_time.time() self._post_batches_count.inc() # Parse request if request.headers['Content-Type'] != 'application/octet-stream': LOGGER.debug('Submission headers had wrong Content-Type: %s', request.headers['Content-Type']) self._post_batches_error.inc() raise errors.SubmissionWrongContentType() body = await request.read() if not body: LOGGER.debug('Submission contained an empty body') self._post_batches_error.inc() raise errors.NoBatchesSubmitted() try: batch_list = BatchList() batch_list.ParseFromString(body) except DecodeError: LOGGER.debug('Submission body could not be decoded: %s', body) self._post_batches_error.inc() raise errors.BadProtobufSubmitted() # Query validator error_traps = [error_handlers.BatchInvalidTrap] validator_query = client_pb2.ClientBatchSubmitRequest( batches=batch_list.batches) self._set_wait(request, validator_query) with self._post_batches_validator_time.time(): response = await self._query_validator( Message.CLIENT_BATCH_SUBMIT_REQUEST, client_pb2.ClientBatchSubmitResponse, validator_query, error_traps) # Build response envelope data = self._drop_id_prefixes( self._drop_empty_props(response['batch_statuses'])) or None id_string = ','.join(b.header_signature for b in batch_list.batches) if data is None or any(d['status'] != 'COMMITTED' for d in data): status = 202 link = self._build_url(request, path='/batch_status', id=id_string) else: status = 201 data = None link = self._build_url(request, wait=False, id=id_string) retval = self._wrap_response(request, data=data, metadata={'link': link}, status=status) timer_ctx.stop() return retval