Example #1
0
    def __init__(self, name, link_config):
        self.name = name
        self.protocol = None
        self.queue = MessageQueue(name)
        self.lc_task = None
        self.sender_compid = link_config['sender_compid']
        self.target_compid = link_config['target_compid']
        self._orderid_no = 0

        self._logger = logging.getLogger(__name__)
Example #2
0
    def __init__(self, name, link_config):
        self.name = name
        self.protocol = None
        self.queue = MessageQueue(name)
        self.lc_task = None
        self.sender_compid = link_config["sender_compid"]
        self.target_compid = link_config["target_compid"]
        self._orderid_no = 0

        self._logger = logging.getLogger(__name__)
Example #3
0
class FIXTransport(internet.protocol.Protocol):
    """ This class is the interface between the FIXProtocol and
        the actual Twisted transport.

        Attributes:
            name: The descriptive name for the connection.
                Used mainly when logging.
            protocol: The protocol object that does the
                decoding of messages.
            queue: The queue used to read messages from.
            lc_task: The Twisted looping call task.
            sender_compid:
            target_compid:
    """

    # pylint: disable=too-many-instance-attributes

    def __init__(self, name, link_config):
        self.name = name
        self.protocol = None
        self.queue = MessageQueue(name)
        self.lc_task = None
        self.sender_compid = link_config['sender_compid']
        self.target_compid = link_config['target_compid']
        self._orderid_no = 0

        self._logger = logging.getLogger(__name__)

    def get_next_orderid(self):
        """ Generates a valid orderID.
            This uses a combination of the transport name,
            the current date, and an internal counter.

            Returns: a new orderID string
        """
        self._orderid_no += 1
        return "{0}/{1}/{2}".format(self.name,
                                    datetime.datetime.now().strftime("%Y%m%d"),
                                    self._orderid_no)

    def connectionMade(self):
        log_text(self._logger.info, self.name, "Connection made")

    def connectionLost(self, reason=None):
        # pylint: disable=unused-argument
        log_text(self._logger.info, self.name, "Connection lost")

    def dataReceived(self, data):
        """ This is the callback from Twisted.
        """
        self.protocol.on_data_received(data)

    def on_message_received(self, message):
        """ This is the callback from the protocol.
        """
        log_message(self._logger.info, self.name, message, 'message received')

        # forward the message to the queue only if not a
        # heartbeat/testrequest
        if message.msg_type() not in {FIX.HEARTBEAT, FIX.TEST_REQUEST}:
            self.queue.add(message)

    def send_message(self, message):
        """ This is the callback from the protocol.  Send the
            message onto through the transport.
        """
        self.protocol.prepare_send_message(message)
        data = message.to_binary()
        log_message(self._logger.info, self.name, message, 'message sent')

        if self.transport is not None:
            reactor.callFromThread(self.transport.write, data)

    def cancel(self):
        """ Cancel any remaining operations.
        """
        self.queue.cancel()

    def wait_for_message(self, title='', timeout=10):
        """ Waits until a message has been received.

            Basically, this checks the queue until a message
            has been received.  The purpose of this is to
            provide a synchronous interface on an asynchronous
            interface.

            Arguments:
                title: This is used for logging, to indicate
                    what we are waiting for.
                timeout: The timeout in secs.  (Default: 10)

            Returns: A message

            Raises:
                fixtest.base.TestInterruptedError:
                fixtest.base.TimeoutError:
        """
        return self.queue.wait_for_message(title=title, timeout=timeout)

    def start_heartbeat(self, enable):
        """ Starts/stops the hearbeat processing.

            Basically starts/stops a Twisted timer callback loop.
            Note that if the loop is already started calling
            start_heartbeat(True) will not do anything.  To change
            the heartbeat interval, it is necessary to call
            start_heartbeat(False) followed by start_heartbeat(True).

            Arguments:
                enable: True if starting the heartbeat processing,
                    False to stop the processing.
        """
        if enable:
            if self.lc_task is None:
                self.lc_task = task.LoopingCall(self.on_timer_tick_received)
                reactor.callFromThread(self.lc_task.start, 1, now=False)
        else:
            if self.lc_task is not None:
                self.lc_task.stop()
                self.lc_task = None

    def on_timer_tick_received(self):
        """ This is the timer callback received from Twisted.
            Forwards this call onto the protocol.
        """
        self.protocol.on_timer_tick_received()

    def client_success(self, result, *args, **kwargs):
        """ This is called from Twisted upon connection """
        # pylint: disable=unused-argument
        client = args[0]
        client['connected'] = 'success'
        log_text(
            self._logger.info, __name__,
            'client:{0} connected to {1}:{2}'.format(client['name'],
                                                     client['host'],
                                                     client['port']))

    def client_failure(self, error, *args, **kwargs):
        """ This is called from Twisted upon an error """
        # pylint: disable=unused-argument
        client = args[0]
        client['error'] = error
        log_text(
            self._logger.error, __name__,
            'client:{0} failed to start: {1}'.format(args[0]['name'], error))
        return ConnectionError(str(error))
Example #4
0
class FIXTransport(internet.protocol.Protocol):
    """ This class is the interface between the FIXProtocol and
        the actual Twisted transport.

        Attributes:
            name: The descriptive name for the connection.
                Used mainly when logging.
            protocol: The protocol object that does the
                decoding of messages.
            queue: The queue used to read messages from.
            lc_task: The Twisted looping call task.
            sender_compid:
            target_compid:
    """

    # pylint: disable=too-many-instance-attributes

    def __init__(self, name, link_config):
        self.name = name
        self.protocol = None
        self.queue = MessageQueue(name)
        self.lc_task = None
        self.sender_compid = link_config["sender_compid"]
        self.target_compid = link_config["target_compid"]
        self._orderid_no = 0

        self._logger = logging.getLogger(__name__)

    def get_next_orderid(self):
        """ Generates a valid orderID.
            This uses a combination of the transport name,
            the current date, and an internal counter.

            Returns: a new orderID string
        """
        self._orderid_no += 1
        return "{0}/{1}/{2}".format(self.name, datetime.datetime.now().strftime("%Y%m%d"), self._orderid_no)

    def connectionMade(self):
        log_text(self._logger.info, self.name, "Connection made")

    def connectionLost(self, reason=None):
        # pylint: disable=unused-argument
        log_text(self._logger.info, self.name, "Connection lost")

    def dataReceived(self, data):
        """ This is the callback from Twisted.
        """
        self.protocol.on_data_received(data)

    def on_message_received(self, message):
        """ This is the callback from the protocol.
        """
        log_message(self._logger.info, self.name, message, "message received")

        # forward the message to the queue only if not a
        # heartbeat/testrequest
        if message.msg_type() not in {FIX.HEARTBEAT, FIX.TEST_REQUEST}:
            self.queue.add(message)

    def send_message(self, message):
        """ This is the callback from the protocol.  Send the
            message onto through the transport.
        """
        self.protocol.prepare_send_message(message)
        data = message.to_binary()
        log_message(self._logger.info, self.name, message, "message sent")

        if self.transport is not None:
            reactor.callFromThread(self.transport.write, data)

    def cancel(self):
        """ Cancel any remaining operations.
        """
        self.queue.cancel()

    def wait_for_message(self, title="", timeout=10):
        """ Waits until a message has been received.

            Basically, this checks the queue until a message
            has been received.  The purpose of this is to
            provide a synchronous interface on an asynchronous
            interface.

            Arguments:
                title: This is used for logging, to indicate
                    what we are waiting for.
                timeout: The timeout in secs.  (Default: 10)

            Returns: A message

            Raises:
                fixtest.base.TestInterruptedError:
                fixtest.base.TimeoutError:
        """
        return self.queue.wait_for_message(title=title, timeout=timeout)

    def start_heartbeat(self, enable):
        """ Starts/stops the hearbeat processing.

            Basically starts/stops a Twisted timer callback loop.
            Note that if the loop is already started calling
            start_heartbeat(True) will not do anything.  To change
            the heartbeat interval, it is necessary to call
            start_heartbeat(False) followed by start_heartbeat(True).

            Arguments:
                enable: True if starting the heartbeat processing,
                    False to stop the processing.
        """
        if enable:
            if self.lc_task is None:
                self.lc_task = task.LoopingCall(self.on_timer_tick_received)
                reactor.callFromThread(self.lc_task.start, 1, now=False)
        else:
            if self.lc_task is not None:
                self.lc_task.stop()
                self.lc_task = None

    def on_timer_tick_received(self):
        """ This is the timer callback received from Twisted.
            Forwards this call onto the protocol.
        """
        self.protocol.on_timer_tick_received()

    def client_success(self, result, *args, **kwargs):
        """ This is called from Twisted upon connection """
        # pylint: disable=unused-argument
        client = args[0]
        client["connected"] = "success"
        log_text(
            self._logger.info,
            __name__,
            "client:{0} connected to {1}:{2}".format(client["name"], client["host"], client["port"]),
        )

    def client_failure(self, error, *args, **kwargs):
        """ This is called from Twisted upon an error """
        # pylint: disable=unused-argument
        client = args[0]
        client["error"] = error
        log_text(self._logger.error, __name__, "client:{0} failed to start: {1}".format(args[0]["name"], error))
        return ConnectionError(str(error))