from cis_interface.drivers.Driver import Driver
from cis_interface.communication import new_comm
DEBUG_SLEEPS = True
[docs]class CommDriver(Driver):
r"""Base driver for any driver that does communication.
Args:
name (str): The name of the message queue that the driver should
connect to.
**kwargs: Additional keyword arguments are passed to the parent and comm
classes.
Attributes:
comm_name (str): Name of communication class.
comm (CommBase): Instance of communication class.
state (str): Description of the last operation performed by the driver.
numSent (int): The number of messages sent to the queue.
numReceived (int): The number of messages received from the queue.
"""
def __init__(self, name, **kwargs):
super(CommDriver, self).__init__(name, **kwargs)
self.debug('')
self.state = 'Started'
self.numSent = 0
self.numReceived = 0
kwargs.setdefault('reverse_names', True)
self.comm = None
self.comm = new_comm(name, dont_open=True, **kwargs)
self.comm_name = self.comm.comm_class
for k, v in self.comm.opp_comms.items():
self.env[k] = v
self.debug(".env: %s", self.env)
@property
def maxMsgSize(self):
r"""int: Maximum message size."""
return self.comm.maxMsgSize
@property
def is_valid(self):
r"""bool: Returns True if the connection is open and the parent class
is valid."""
with self.lock:
return (super(CommDriver, self).is_valid and self.is_comm_open)
@property
def is_comm_open(self):
r"""bool: Returns True if the connection is open."""
with self.lock:
return self.comm.is_open
@property
def is_comm_closed(self):
r"""bool: Returns True if the connection is closed."""
with self.lock:
return self.comm.is_closed
@property
def n_msg(self):
r"""int: The number of messages in the queue."""
with self.lock:
return self.comm.n_msg
[docs] def open_comm(self):
r"""Open the queue."""
self.debug('')
with self.lock:
self.comm.open()
self.debug('Returning')
[docs] def close_comm(self):
r"""Close the queue."""
self.debug('')
if self.comm is not None:
with self.lock:
self.comm.close()
self.debug('Returning')
[docs] def start(self):
r"""Open connection before running."""
if self.comm_name != 'CommBase':
self.open_comm()
Tout = self.start_timeout()
while (not self.is_comm_open) and (not Tout.is_out):
self.sleep()
self.stop_timeout()
if not self.is_comm_open:
raise Exception("Connection never finished opening.")
super(CommDriver, self).start()
[docs] def graceful_stop(self, timeout=None, **kwargs):
r"""Stop the CommDriver, first draining the message queue.
Args:
timeout (float, optional): Max time that should be waited. Defaults
to None and is set to attribute timeout. If 0, it will never
timeout.
\*\*kwargs: Additional keyword arguments are passed to the parent
class's graceful_stop method.
"""
self.debug('')
T = self.start_timeout(timeout)
try:
while (self.n_msg > 0) and (not T.is_out): # pragma: debug
if DEBUG_SLEEPS:
self.debug('Draining %d messages', self.n_msg)
self.sleep()
except Exception as e: # pragma: debug
self.raise_error(e)
self.stop_timeout()
super(CommDriver, self).graceful_stop()
self.debug('Returning')
[docs] def do_terminate(self):
r"""Stop the CommDriver by closing the comm."""
self.debug('')
self.close_comm()
super(CommDriver, self).do_terminate()
[docs] def cleanup(self):
r"""Ensure that the queues are removed."""
self.debug('')
self.close_comm()
super(CommDriver, self).cleanup()
[docs] def printStatus(self, beg_msg='', end_msg=''):
r"""Print information on the status of the CommDriver.
Arguments:
beg_msg (str, optional): Additional message to print at beginning.
end_msg (str, optional): Additional message to print at end.
"""
msg = beg_msg
msg += '%-30s' % (self.__module__ + '(' + self.name + ')')
msg += '%-30s' % ('last action: ' + self.state)
msg += '%-15s' % (str(self.numSent) + ' delivered, ')
msg += '%-15s' % (str(self.numReceived) + ' accepted, ')
msg += '%-15s' % (str(self.n_msg) + ' ready')
msg += end_msg
print(msg)
[docs] def send(self, data, *args, **kwargs):
r"""Send a message smaller than maxMsgSize.
Args:
str: The message to be sent.
*args: All arguments are passed to comm send method.
**kwargs: All keywords arguments are passed to comm send method.
Returns:
bool: Success or failure of send.
"""
with self.lock:
self.state = 'deliver'
ret = self.comm.send(data, *args, **kwargs)
if ret:
self.state = 'delivered'
self.numSent = self.numSent + 1
else:
self.state = 'delivery failed'
return ret
[docs] def recv(self, *args, **kwargs):
r"""Receive a message smaller than maxMsgSize.
Args:
*args: All arguments are passed to comm recv method.
**kwargs: All keywords arguments are passed to comm recv method.
Returns:
tuple (bool, str): The success or failure of receiving and the
received message.
"""
with self.lock:
self.state = 'receiving'
ret = self.comm.recv(*args, **kwargs)
if ret[0]:
self.state = 'received'
self.numReceived += 1
else:
self.state = 'received failed'
return ret
[docs] def send_nolimit(self, data, *args, **kwargs):
r"""Send a message larger than maxMsgSize in multiple parts.
Args:
str: The message to be sent.
*args: All arguments are passed to comm send_nolimit method.
**kwargs: All keywords arguments are passed to comm send_nolimit
method.
Returns:
bool: Success or failure of send.
"""
ret = self.comm.send_nolimit(data, *args, **kwargs)
return ret
[docs] def recv_nolimit(self, *args, **kwargs):
r"""Receive a message larger than maxMsgSize in multiple parts.
Args:
*args: All arguments are passed to comm recv_nolimit method.
**kwargs: All keywords arguments are passed to comm recv_nolimit
method.
Returns:
tuple (bool, str): The success or failure of receiving and the
received message.
"""
ret = self.comm.recv_nolimit(*args, **kwargs)
return ret