예제 #1
0
class Connector(object):
    """The Connector

    See module description for more context.
    """

    REQUIRED_KEYS = {"name", "mapping", "message"}
    RECEIVER_NAME = "bm-connector"

    def __init__(self, config=None):
        """Initialise the Connector and starts to listen to incoming messages.

        :param config:      Configuration to use (default config if None).
        """
        self.log = logging.getLogger(self.__class__.__name__)

        if config is None:
            config = ConnConfig()
            self.log.info("Falling back to default configuration.")

        # errors up to here are allowed to terminate the program

        mappings = self._read_mappings(config.mappings)
        self.mapper = Mapper(mappings)
        self.log.debug("Mappings read.")

        self.sender = Sender(config.send.address, config.send.port,
                             config.broker.endpoint_prefix +
                             config.connector_id,
                             config.broker.topic,
                             config.connector_id)
        self.log.info("Sender created.")

        self.receiver = Receiver(self.RECEIVER_NAME,
                                 config.listen.address, config.listen.port)
        self.log.info("Receiver created.")
        self.receiver.listen("/", self.handle_receive)

    def _read_mappings(self, location):
        """Read the mappings into a list of dictionaries."""
        # os/fs errors here are allowed to terminate the program
        # yaml parse errors should not crash but log
        mappings = []
        for root, _, files in walk(location):
            for f in files:
                filepath = os.path.join(root, f)
                with open(filepath, "r") as fd:
                    # TODO extract the below block?
                    try:
                        mp = yaml.load(fd)
                        for i in self.REQUIRED_KEYS:
                            if i not in mp:
                                raise LookupError(i)
                        mappings.append(mp)
                    except LookupError as e:
                        self.log.error(
                            "Missing key '{}' in file '{}'. Ignoring."
                            .format(e.args[0], filepath))
                    except Exception:
                        # TODO find correct exception types.
                        self.log.error(
                            "Failed to read mapping in '{}'. Ignoring."
                            .format(filepath))
        return mappings

    def handle_receive(self, message):
        """Handle message via mapping.

        :param message:     The message to map and send. (json)
        """
        mapped = self.mapper.transform(message)
        if mapped:
            self.log.info("Mapped message is '{}'.".format(mapped))
            self.sender.send(mapped)
예제 #2
0
def launch_receiver(coder):
    receiver = Receiver(coder=coder)
    receiver.listen()