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 __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__)
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))
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))