# Path: stoq/data_classes.py
# class Payload:
#     def __init__(
#         self,
#         content: Union[bytes, str],
#         payload_meta: Optional[PayloadMeta] = None,
#         extracted_by: Optional[Union[str, List[str]]] = None,
#         extracted_from: Optional[Union[str, List[str]]] = None,
#         payload_id: Optional[str] = None,
#     ) -> None:
#         """
# 
#         Object to store payload and related information
# 
#         :param content: Raw bytes to be scanned
#         :param payload_meta: Metadata pertaining to originating source
#         :param extracted_by: Name of plugin that extracted the payload
#         :param extracted_from: Unique payload ID the payload was extracted from
#         :param payload_id: Unique ID of payload
# 
#         >>> from stoq import PayloadMeta, Payload
#         >>> content = b'This is a raw payload'
#         >>> payload_meta = PayloadMeta(should_archive=True)
#         >>> payload = Payload(content, payload_meta=payload_meta)
# 
#         """
#         self.content = content if isinstance(content, bytes) else content.encode()
#         self.dispatch_meta: Dict[str, Dict] = {}
#         self.results = PayloadResults(
#             payload_id=payload_id,
#             size=len(content),
#             payload_meta=payload_meta,
#             extracted_from=extracted_from,
#             extracted_by=extracted_by,
#         )
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# class DispatcherResponse:
#     def __init__(
#         self,
#         plugin_names: Optional[List[str]] = None,
#         meta: Optional[Dict] = None,
#         errors: Optional[List[Error]] = None,
#     ) -> None:
#         """
# 
#         Object containing response from dispatcher plugins
# 
#         :param plugins_names: Plugins to send payload to for scanning
#         :param meta: Metadata pertaining to dispatching results
#         :param errors: Errors that occurred
# 
#         >>> from stoq import DispatcherResponse
#         >>> plugins = ['yara', 'exif']
#         >>> meta = {'hit': 'exe_file'}
#         >>> dispatcher = DispatcherResponse(plugin_names=plugins, meta=meta)
# 
#         """
#         self.plugin_names = [] if plugin_names is None else plugin_names
#         self.meta = {} if meta is None else meta
#         self.errors = errors or []
# 
#     def __str__(self) -> str:
#         return helpers.dumps(self)
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# class Request:
#     def __init__(
#         self,
#         payloads: Optional[List[Payload]] = None,
#         request_meta: Optional[RequestMeta] = None,
#         errors: Optional[List[Error]] = None,
#     ):
#         """
# 
#         Object that contains the state of a ``Stoq`` scan. This object is accessible within 
#         all archiver, dispatcher, and worker plugins.
# 
#         :param payloads: All payloads that are being processed, to include extracted payloads
#         :param request_meta: Original ``RequestMeta`` object
#         :param errors: All errors that have been generated by plugins or ``Stoq``
# 
#         """
# 
#         self.payloads = payloads or []
#         self.request_meta = request_meta or RequestMeta()
#         self.errors = errors or []
# 
#     def __str__(self) -> str:
#         return helpers.dumps(self)
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# Path: stoq/plugins/base.py
# class BasePlugin(ABC):
#     def __init__(self, config: StoqConfigParser) -> None:
#         self.config = config
#         self.plugin_name = config.get('Core', 'Name', fallback=self.__class__.__name__)
#         self.__author__ = config.get('Documentation', 'Author', fallback='')
#         self.__version__ = config.get('Documentation', 'Version', fallback='')
#         self.__website__ = config.get('Documentation', 'Website', fallback='')
#         self.__description__ = config.get('Documentation', 'Description', fallback='')
#         self.log = logging.getLogger(f'stoq.{self.plugin_name}')


from typing import Optional
from abc import abstractmethod, ABC
from stoq.data_classes import Payload, DispatcherResponse, Request
from stoq.plugins import BasePlugin
        from stoq.plugins import DispatcherPlugin
        from stoq.helpers import StoqConfigParser
        from stoq.data_classes import Payload, DispatcherResponse, Request


        class ExampleDispatcher(DispatcherPlugin):
            def __init__(self, config: StoqConfigParser) -> None:
                super().__init__(config)
                self.msg = config.get('options', 'msg', fallback='Useful content here')

            async def get_dispatches(
                self, payload: Payload, request: Request
            ) -> Optional[DispatcherResponse]:
                dr = DispatcherResponse()
                dr.meta['example_key'] = 'Useful metadata info'
                dr.meta['msg'] = self.msg
                return dr


    API
    ===

"""




class DispatcherPlugin(BasePlugin, ABC):
    @abstractmethod
    async def get_dispatches(

# Path: stoq/data_classes.py
# class Payload:
#     def __init__(
#         self,
#         content: Union[bytes, str],
#         payload_meta: Optional[PayloadMeta] = None,
#         extracted_by: Optional[Union[str, List[str]]] = None,
#         extracted_from: Optional[Union[str, List[str]]] = None,
#         payload_id: Optional[str] = None,
#     ) -> None:
#         """
# 
#         Object to store payload and related information
# 
#         :param content: Raw bytes to be scanned
#         :param payload_meta: Metadata pertaining to originating source
#         :param extracted_by: Name of plugin that extracted the payload
#         :param extracted_from: Unique payload ID the payload was extracted from
#         :param payload_id: Unique ID of payload
# 
#         >>> from stoq import PayloadMeta, Payload
#         >>> content = b'This is a raw payload'
#         >>> payload_meta = PayloadMeta(should_archive=True)
#         >>> payload = Payload(content, payload_meta=payload_meta)
# 
#         """
#         self.content = content if isinstance(content, bytes) else content.encode()
#         self.dispatch_meta: Dict[str, Dict] = {}
#         self.results = PayloadResults(
#             payload_id=payload_id,
#             size=len(content),
#             payload_meta=payload_meta,
#             extracted_from=extracted_from,
#             extracted_by=extracted_by,
#         )
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# class DispatcherResponse:
#     def __init__(
#         self,
#         plugin_names: Optional[List[str]] = None,
#         meta: Optional[Dict] = None,
#         errors: Optional[List[Error]] = None,
#     ) -> None:
#         """
# 
#         Object containing response from dispatcher plugins
# 
#         :param plugins_names: Plugins to send payload to for scanning
#         :param meta: Metadata pertaining to dispatching results
#         :param errors: Errors that occurred
# 
#         >>> from stoq import DispatcherResponse
#         >>> plugins = ['yara', 'exif']
#         >>> meta = {'hit': 'exe_file'}
#         >>> dispatcher = DispatcherResponse(plugin_names=plugins, meta=meta)
# 
#         """
#         self.plugin_names = [] if plugin_names is None else plugin_names
#         self.meta = {} if meta is None else meta
#         self.errors = errors or []
# 
#     def __str__(self) -> str:
#         return helpers.dumps(self)
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# class Request:
#     def __init__(
#         self,
#         payloads: Optional[List[Payload]] = None,
#         request_meta: Optional[RequestMeta] = None,
#         errors: Optional[List[Error]] = None,
#     ):
#         """
# 
#         Object that contains the state of a ``Stoq`` scan. This object is accessible within 
#         all archiver, dispatcher, and worker plugins.
# 
#         :param payloads: All payloads that are being processed, to include extracted payloads
#         :param request_meta: Original ``RequestMeta`` object
#         :param errors: All errors that have been generated by plugins or ``Stoq``
# 
#         """
# 
#         self.payloads = payloads or []
#         self.request_meta = request_meta or RequestMeta()
#         self.errors = errors or []
# 
#     def __str__(self) -> str:
#         return helpers.dumps(self)
# 
#     def __repr__(self):
#         return repr(self.__dict__)
# 
# Path: stoq/plugins/base.py
# class BasePlugin(ABC):
#     def __init__(self, config: StoqConfigParser) -> None:
#         self.config = config
#         self.plugin_name = config.get('Core', 'Name', fallback=self.__class__.__name__)
#         self.__author__ = config.get('Documentation', 'Author', fallback='')
#         self.__version__ = config.get('Documentation', 'Version', fallback='')
#         self.__website__ = config.get('Documentation', 'Website', fallback='')
#         self.__description__ = config.get('Documentation', 'Description', fallback='')
#         self.log = logging.getLogger(f'stoq.{self.plugin_name}')


# Path: stoq/plugins/dispatcher.py
from typing import Optional
from abc import abstractmethod, ABC
from stoq.data_classes import Payload, DispatcherResponse, Request
from stoq.plugins import BasePlugin

        from stoq.plugins import DispatcherPlugin
        from stoq.helpers import StoqConfigParser
        from stoq.data_classes import Payload, DispatcherResponse, Request


        class ExampleDispatcher(DispatcherPlugin):
            def __init__(self, config: StoqConfigParser) -> None:
                super().__init__(config)
                self.msg = config.get('options', 'msg', fallback='Useful content here')

            async def get_dispatches(
                self, payload: Payload, request: Request
            ) -> Optional[DispatcherResponse]:
                dr = DispatcherResponse()
                dr.meta['example_key'] = 'Useful metadata info'
                dr.meta['msg'] = self.msg
                return dr


    API
    ===

"""




class DispatcherPlugin(BasePlugin, ABC):
    @abstractmethod
    async def get_dispatches(

        self, payload: Payload, request: Request