""" Parse connection status from Foolscap. Ported to Python 3. """ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals from future.utils import PY2 if PY2: from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401 import time from zope.interface import implementer from ..interfaces import IConnectionStatus @implementer(IConnectionStatus) class ConnectionStatus(object): def __init__(self, connected, summary, non_connected_statuses, last_connection_time, last_received_time): self.connected = connected self.summary = summary self.non_connected_statuses = non_connected_statuses self.last_connection_time = last_connection_time self.last_received_time = last_received_time @classmethod def unstarted(cls): """ Create a ``ConnectionStatus`` representing a connection for which no attempts have yet been made. """ return cls( connected=False, summary=u"unstarted", non_connected_statuses=[], last_connection_time=None, last_received_time=None, ) def _hint_statuses(which, handlers, statuses): non_connected_statuses = {} for hint in which: handler = handlers.get(hint) handler_dsc = " via %s" % handler if handler else "" dsc = statuses[hint] non_connected_statuses["%s%s" % (hint, handler_dsc)] = dsc return non_connected_statuses def from_foolscap_reconnector(rc, last_received): ri = rc.getReconnectionInfo() # See foolscap/reconnector.py, ReconnectionInfo, for details about possible # states. The returned result is a native string, it seems, so convert to # unicode. state = ri.state if isinstance(state, bytes): # Python 2 state = str(state, "ascii") if state == "unstarted": return ConnectionStatus.unstarted() ci = ri.connectionInfo connected = False last_connected = None others = set(ci.connectorStatuses.keys()) summary = None if state == "connected": connected = True if ci.winningHint: others.remove(ci.winningHint) summary = "Connected to %s via %s" % ( ci.winningHint, ci.connectionHandlers[ci.winningHint]) else: summary = "Connected via listener (%s)" % ci.listenerStatus[0] last_connected = ci.establishedAt elif state == "connecting": # ci describes the current in-progress attempt summary = "Trying to connect" elif state == "waiting": now = time.time() elapsed = now - ri.lastAttempt delay = ri.nextAttempt - now summary = "Reconnecting in %d seconds (last attempt %ds ago)" % \ (delay, elapsed) # ci describes the previous (failed) attempt non_connected_statuses = _hint_statuses(others, ci.connectionHandlers, ci.connectorStatuses) cs = ConnectionStatus(connected, summary, non_connected_statuses, last_connected, last_received) return cs