Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
lib-py-b2b / request.py
Size: Mime:
import base64
import hashlib
import hmac
import json
from datetime import datetime

from dateutil.parser import isoparse

from lib_b2b.base import BaseClass
from lib_b2b.persistent import Persistable
from lib_b2b.util import UtilityEncoder


class Request(BaseClass, Persistable):

    def __init__(self, headers, method, body, request_time: datetime,
                 query_params=None, uri_params=None,
                 context=None, stage_vars=None,
                 request_type: 'OrderRequestType' = None,
                 is_base64_encoded: bool = False):
        self.is_base64_encoded = is_base64_encoded
        self.request_type = request_type
        self.request_time = request_time
        self.query_params = query_params
        self.headers = headers
        self.uri_params = uri_params
        self.method = method
        self.body = body
        self._json_body = None
        self._raw_body = b''
        self.context = context
        self.stage_vars = stage_vars

    @property
    def json_body(self):
        if self.headers.get('content-type', '').startswith('application/json') or \
                self.headers.get('Content-Type', '').startswith('application/json') or \
                self.headers.get('CONTENT-TYPE', '').startswith('application/json'):
            if self._json_body is None:
                try:
                    self._json_body = json.loads(self.raw_body)
                except ValueError as ve:
                    raise ValueError('Error Parsing JSON') from ve
            return self._json_body
        else:
            raise ValueError('Invalid content-type')

    @property
    def raw_body(self):
        if not self._raw_body and self.body is not None:
            if self.is_base64_encoded:
                self._raw_body = self._base64decode(self.body)
            elif not isinstance(self.body, bytes):
                self._raw_body = self.body.encode('utf-8')
            else:
                self._raw_body = self.body
        return self._raw_body

    def _base64decode(self, encoded):
        if not isinstance(encoded, bytes):
            encoded = encoded.encode('ascii')
        output = base64.b64decode(encoded)
        return output

    def _base64encode(self, to_encode):
        if not isinstance(to_encode, bytes):
            to_encode = to_encode.encode('utf-8')
        output = base64.b64encode(to_encode)
        return output.decode('ascii')

    @property
    def statistics(self):
        from boto3.dynamodb.types import TypeSerializer
        ddb_serializer = TypeSerializer()
        ddb_ser = ddb_serializer.serialize(self.as_dict())
        ddb_ser_str = json.dumps(ddb_ser)
        ddb_size = len(ddb_ser_str.encode('utf-8'))
        json_size = len(json.dumps(self.as_dict()).encode('utf-8'))
        encoded_json_size = len(json.dumps(self.as_dict(encoded=True)).encode('utf-8'))
        signature = self.calculate_signature("thisisatestkeyforthepurposeoftesting".encode('utf-8'))
        return {
            'ddb_size': ddb_size,
            'json_size': json_size,
            'encoded_json_size': encoded_json_size,
            'signature': signature
        }

    def calculate_signature(self, key: bytes):
        _hash = hmac.new(key, self.raw_body, hashlib.sha256)
        hmac_calculated = base64.b64encode(_hash.digest()).decode()
        return hmac_calculated

    @staticmethod
    def from_(request, request_time: datetime, request_type: 'OrderRequestType' = None,
              encoded: bool = False) -> 'Request':
        return Request(
            query_params=dict(request.query_params) if request.query_params else None,
            headers=dict(request.headers) if request.headers else None,
            uri_params=request.uri_params,
            method=request.method,
            body=request.raw_body.decode('utf-8'),
            stage_vars=request.stage_vars,
            context=request.context,
            request_time=request_time,
            request_type=request_type,
            is_base64_encoded=encoded
        )

    @staticmethod
    def from_dict(data: dict, encoded: bool = False):
        from lib_b2b.order_request import OrderRequestType
        if encoded:
            encoded = data.get('body').encode('ascii')
            body = base64.b64decode(encoded)
        else:
            body = data.get('body')
        return Request(
            query_params=data.get('query_params'),
            headers=data.get('headers'),
            uri_params=data.get('uri_params'),
            method=data.get('method'),
            body=body,
            stage_vars=data.get('stage_vars'),
            context=data.get('context'),
            request_time=isoparse(data.get('request_time')),
            request_type=OrderRequestType(data.get('request_type')) if data.get('request_type') else None,
            is_base64_encoded=encoded
        )

    def as_dict(self, encoded: bool = False) -> dict:
        _data = {
            'query_params': self.query_params,
            'headers': self.headers,
            'uri_params': self.uri_params,
            'method': self.method,
            'body': self.body,
            'stage_vars': self.stage_vars,
            'context': self.context,
            'request_time': self.request_time.isoformat(),
            'request_type': self.request_type.value if self.request_type else None
        }
        if encoded:
            _data['body'] = self._base64encode(self.raw_body)
        return _data

    def as_json(self):
        return json.dumps(self.as_dict(), cls=UtilityEncoder)

    @classmethod
    def from_json(cls, json_str):
        return cls.from_dict(json.loads(json_str))

    def __eq__(self, other):
        return self.headers == other.headers and self.body == other.body