# Path: federation/entities/matrix/entities.py
# class MatrixEntityMixin(BaseEntity):
#     _event_type: str = None
#     _payloads: List[Dict] = []
#     _profile_room_id = None
#     _txn_id: str = None
# 
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         # We always require an mxid
#         self._required.append('mxid')
#         # Create a transaction ID
#         self._txn_id = str(uuid4())
# 
#     @property
#     def event_type(self) -> str:
#         return self._event_type
# 
#     @classmethod
#     def from_base(cls, entity):
#         # type: (BaseEntity) -> MatrixEntityMixin
#         # noinspection PyArgumentList
#         return cls(**get_base_attributes(entity))
# 
#     # noinspection PyMethodMayBeStatic
#     def get_endpoint(self) -> str:
#         config = get_matrix_configuration()
#         return f"{config['homeserver_base_url']}/_matrix/client/r0"
# 
#     # noinspection PyMethodMayBeStatic
#     def get_endpoint_media(self) -> str:
#         config = get_matrix_configuration()
#         return f"{config['homeserver_base_url']}/_matrix/media/r0"
# 
#     def get_profile_room_id(self):
#         # TODO: we should cache these.
#         doc, status, error = fetch_document(
#             url=f"{self.get_endpoint()}/directory/room/{self.profile_room_alias_url_safe}",
#             extra_headers=appservice_auth_header(),
#         )
#         if status == 200:
#             data = json.loads(doc)
#             self._profile_room_id = data["room_id"]
# 
#     # noinspection PyMethodMayBeStatic
#     def payloads(self) -> List[Dict]:
#         return self._payloads
# 
#     @property
#     def profile_room_alias(self):
#         return f"#{self.mxid}"
# 
#     @property
#     def profile_room_alias_url_safe(self):
#         return f"{quote(self.profile_room_alias)}"
# 
#     @property
#     def server_name(self) -> str:
#         config = get_matrix_configuration()
#         return config['homeserver_name']
# 
#     @property
#     def txn_id(self) -> str:
#         return self._txn_id
# 
# Path: federation/types.py
# class UserType:
#     id: str = attr.ib()
#     private_key: Optional[Union[RsaKey, str]] = attr.ib(default=None)
#     receiver_variant: Optional[ReceiverVariant] = attr.ib(default=None)
# 
#     # Required only if sending to Diaspora protocol platforms
#     handle: Optional[str] = attr.ib(default=None)
#     guid: Optional[str] = attr.ib(default=None)
# 
#     # Required only if sending to Matrix protocol
#     mxid: Optional[str] = attr.ib(default=None)
#     # TODO needed?
#     variant: Optional[UserVariant] = attr.ib(default=None)
# 
#     @property
#     def rsa_private_key(self) -> RsaKey:
#         if isinstance(self.private_key, str):
#             return RSA.importKey(self.private_key)
#         return self.private_key
# 
# class RequestType:
#     """
#     Emulates structure of a Django HttpRequest for compatibility.
#     """
#     body: Union[str, bytes] = attr.ib()
# 
#     # Required when dealing with incoming AP payloads
#     headers: Dict = attr.ib(default=None)
#     method: str = attr.ib(default=None)
#     url: str = attr.ib(default=None)
# 
# Path: federation/utils/text.py
# def decode_if_bytes(text):
#     try:
#         return text.decode("utf-8")
#     except AttributeError:
#         return text


import json
import logging
import re
from typing import Callable, Tuple, List, Dict
from federation.entities.matrix.entities import MatrixEntityMixin
from federation.types import UserType, RequestType
from federation.utils.text import decode_if_bytes
            return True
    except Exception:
        pass
    return False


class Protocol:
    actor = None
    get_contact_key = None
    payload = None
    request = None
    user = None

    # noinspection PyUnusedLocal
    @staticmethod
    def build_send(entity: MatrixEntityMixin, *args, **kwargs) -> List[Dict]:
        """
        Build POST data for sending out to the homeserver.

        :param entity: The outbound ready entity for this protocol.
        :returns: list of payloads
        """
        return entity.payloads()

    def extract_actor(self):
        # TODO TBD
        pass

    def receive(
            self,

# Path: federation/entities/matrix/entities.py
# class MatrixEntityMixin(BaseEntity):
#     _event_type: str = None
#     _payloads: List[Dict] = []
#     _profile_room_id = None
#     _txn_id: str = None
# 
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         # We always require an mxid
#         self._required.append('mxid')
#         # Create a transaction ID
#         self._txn_id = str(uuid4())
# 
#     @property
#     def event_type(self) -> str:
#         return self._event_type
# 
#     @classmethod
#     def from_base(cls, entity):
#         # type: (BaseEntity) -> MatrixEntityMixin
#         # noinspection PyArgumentList
#         return cls(**get_base_attributes(entity))
# 
#     # noinspection PyMethodMayBeStatic
#     def get_endpoint(self) -> str:
#         config = get_matrix_configuration()
#         return f"{config['homeserver_base_url']}/_matrix/client/r0"
# 
#     # noinspection PyMethodMayBeStatic
#     def get_endpoint_media(self) -> str:
#         config = get_matrix_configuration()
#         return f"{config['homeserver_base_url']}/_matrix/media/r0"
# 
#     def get_profile_room_id(self):
#         # TODO: we should cache these.
#         doc, status, error = fetch_document(
#             url=f"{self.get_endpoint()}/directory/room/{self.profile_room_alias_url_safe}",
#             extra_headers=appservice_auth_header(),
#         )
#         if status == 200:
#             data = json.loads(doc)
#             self._profile_room_id = data["room_id"]
# 
#     # noinspection PyMethodMayBeStatic
#     def payloads(self) -> List[Dict]:
#         return self._payloads
# 
#     @property
#     def profile_room_alias(self):
#         return f"#{self.mxid}"
# 
#     @property
#     def profile_room_alias_url_safe(self):
#         return f"{quote(self.profile_room_alias)}"
# 
#     @property
#     def server_name(self) -> str:
#         config = get_matrix_configuration()
#         return config['homeserver_name']
# 
#     @property
#     def txn_id(self) -> str:
#         return self._txn_id
# 
# Path: federation/types.py
# class UserType:
#     id: str = attr.ib()
#     private_key: Optional[Union[RsaKey, str]] = attr.ib(default=None)
#     receiver_variant: Optional[ReceiverVariant] = attr.ib(default=None)
# 
#     # Required only if sending to Diaspora protocol platforms
#     handle: Optional[str] = attr.ib(default=None)
#     guid: Optional[str] = attr.ib(default=None)
# 
#     # Required only if sending to Matrix protocol
#     mxid: Optional[str] = attr.ib(default=None)
#     # TODO needed?
#     variant: Optional[UserVariant] = attr.ib(default=None)
# 
#     @property
#     def rsa_private_key(self) -> RsaKey:
#         if isinstance(self.private_key, str):
#             return RSA.importKey(self.private_key)
#         return self.private_key
# 
# class RequestType:
#     """
#     Emulates structure of a Django HttpRequest for compatibility.
#     """
#     body: Union[str, bytes] = attr.ib()
# 
#     # Required when dealing with incoming AP payloads
#     headers: Dict = attr.ib(default=None)
#     method: str = attr.ib(default=None)
#     url: str = attr.ib(default=None)
# 
# Path: federation/utils/text.py
# def decode_if_bytes(text):
#     try:
#         return text.decode("utf-8")
#     except AttributeError:
#         return text


# Path: federation/protocols/matrix/protocol.py
import json
import logging
import re
from typing import Callable, Tuple, List, Dict
from federation.entities.matrix.entities import MatrixEntityMixin
from federation.types import UserType, RequestType
from federation.utils.text import decode_if_bytes

            return True
    except Exception:
        pass
    return False


class Protocol:
    actor = None
    get_contact_key = None
    payload = None
    request = None
    user = None

    # noinspection PyUnusedLocal
    @staticmethod
    def build_send(entity: MatrixEntityMixin, *args, **kwargs) -> List[Dict]:
        """
        Build POST data for sending out to the homeserver.

        :param entity: The outbound ready entity for this protocol.
        :returns: list of payloads
        """
        return entity.payloads()

    def extract_actor(self):
        # TODO TBD
        pass

    def receive(
            self,

            request: RequestType,