[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [nyx/master] Replace ConnectionLine with a namedtuple



commit 75235e25075667f001202c7e1bab6b58097ca9c2
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date:   Fri Sep 18 10:01:07 2015 -0700

    Replace ConnectionLine with a namedtuple
    
    Once the most monsterously large of all our helper classes, and now we can drop
    it entirely! Its final duties are so simple they can be delegated to a
    struct... so much simpler. :P
---
 nyx/connection_panel.py |  172 +++++++++++++++++------------------------------
 1 file changed, 63 insertions(+), 109 deletions(-)

diff --git a/nyx/connection_panel.py b/nyx/connection_panel.py
index d92c7f6..c671781 100644
--- a/nyx/connection_panel.py
+++ b/nyx/connection_panel.py
@@ -44,6 +44,17 @@ UPDATE_RATE = 5  # rate in seconds at which we refresh
 
 Category = enum.Enum('INBOUND', 'OUTBOUND', 'EXIT', 'HIDDEN', 'SOCKS', 'CIRCUIT', 'DIRECTORY', 'CONTROL')
 SortAttr = enum.Enum('CATEGORY', 'UPTIME', 'IP_ADDRESS', 'PORT', 'FINGERPRINT', 'NICKNAME', 'COUNTRY')
+LineType = enum.Enum('CONNECTION', 'CIRCUIT_HEADER', 'CIRCUIT')
+
+Line = collections.namedtuple('Line', [
+  'entry',
+  'line_type',
+  'connection',
+  'circuit',
+  'fingerprint',
+  'nickname',
+  'locale',
+])
 
 
 def conf_handler(key, value):
@@ -114,7 +125,16 @@ class ConnectionEntry(Entry):
 
   @lru_cache()
   def get_lines(self):
-    return [ConnectionLine(self, self._connection)]
+    fingerprint, nickname, locale = None, None, None
+
+    if self.get_type() in (Category.OUTBOUND, Category.CIRCUIT, Category.DIRECTORY, Category.EXIT):
+      fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprints(self._connection.remote_address).get(self._connection.remote_port)
+
+      if fingerprint:
+        nickname = nyx.util.tracker.get_consensus_tracker().get_relay_nickname(fingerprint)
+        locale = tor_controller().get_info('ip-to-country/%s' % connection.remote_address, None)
+
+    return [Line(self, LineType.CONNECTION, self._connection, None, fingerprint, nickname, locale)]
 
   @lru_cache()
   def get_type(self):
@@ -177,7 +197,20 @@ class CircuitEntry(Entry):
 
   @lru_cache()
   def get_lines(self):
-    return [CircHeaderLine(self, self._circuit)] + [CircLine(self, self._circuit, fp) for fp, _ in self._circuit.path]
+    def line(fingerprint, line_type):
+      address, port, nickname, locale = '0.0.0.0', 0, None, None
+      consensus_tracker = nyx.util.tracker.get_consensus_tracker()
+
+      if fingerprint is not None:
+        address, port = consensus_tracker.get_relay_address(fingerprint, ('192.168.0.1', 0))
+        nickname = consensus_tracker.get_relay_nickname(fingerprint)
+        locale = tor_controller().get_info('ip-to-country/%s' % address, None)
+
+      connection = nyx.util.tracker.Connection(to_unix_time(self._circuit.created), False, '127.0.0.1', 0, address, port, 'tcp')
+      return Line(self, line_type, connection, self._circuit, fingerprint, nickname, locale)
+
+    header_line = line(self._circuit.path[-1][0] if self._circuit.status == 'BUILT' else None, LineType.CIRCUIT_HEADER)
+    return [header_line] + [line(fp, LineType.CIRCUIT) for fp, _ in self._circuit.path]
 
   def get_type(self):
     return Category.CIRCUIT
@@ -186,82 +219,6 @@ class CircuitEntry(Entry):
     return False
 
 
-class ConnectionLine(object):
-  """
-  Display component of the ConnectionEntry.
-  """
-
-  def __init__(self, entry, conn):
-    self._entry = entry
-    self.connection = conn
-
-  def get_locale(self, default = None):
-    """
-    Provides the two letter country code for the remote endpoint.
-    """
-
-    return tor_controller().get_info('ip-to-country/%s' % self.connection.remote_address, default)
-
-  def get_fingerprint(self, default = None):
-    """
-    Provides the fingerprint of this relay.
-    """
-
-    if self._entry.get_type() in (Category.OUTBOUND, Category.CIRCUIT, Category.DIRECTORY, Category.EXIT):
-      my_fingerprint = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprints(self.connection.remote_address).get(self.connection.remote_port)
-      return my_fingerprint if my_fingerprint else default
-    else:
-      return default  # inbound connections don't have an ORPort we can resolve
-
-  def get_nickname(self, default = None):
-    """
-    Provides the nickname of this relay.
-    """
-
-    nickname = nyx.util.tracker.get_consensus_tracker().get_relay_nickname(self.get_fingerprint())
-    return nickname if nickname else default
-
-
-class CircHeaderLine(ConnectionLine):
-  """
-  Initial line of a client entry. This has the same basic format as connection
-  lines except that its etc field has circuit attributes.
-  """
-
-  def __init__(self, entry, circ):
-    if circ.status == 'BUILT':
-      self._remote_fingerprint = circ.path[-1][0]
-      exit_address, exit_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(self._remote_fingerprint, ('192.168.0.1', 0))
-      self.is_built = True
-    else:
-      exit_address, exit_port = '0.0.0.0', 0
-      self.is_built = False
-      self._remote_fingerprint = None
-
-    ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, exit_address, exit_port, 'tcp'))
-    self.circuit = circ
-
-  def get_fingerprint(self, default = None):
-    return self._remote_fingerprint if self._remote_fingerprint else ConnectionLine.get_fingerprint(self, default)
-
-
-class CircLine(ConnectionLine):
-  """
-  An individual hop in a circuit. This overwrites the displayed listing, but
-  otherwise makes use of the ConnectionLine attributes (for the detail display,
-  caching, etc).
-  """
-
-  def __init__(self, entry, circ, fingerprint):
-    relay_ip, relay_port = nyx.util.tracker.get_consensus_tracker().get_relay_address(fingerprint, ('192.168.0.1', 0))
-    ConnectionLine.__init__(self, entry, nyx.util.tracker.Connection(to_unix_time(circ.created), False, '127.0.0.1', 0, relay_ip, relay_port, 'tcp'))
-    self.circuit = circ
-    self._fingerprint = fingerprint
-
-  def get_fingerprint(self, default = None):
-    return self._fingerprint
-
-
 class ConnectionPanel(panel.Panel, threading.Thread):
   """
   Listing of connections tor is making, with information correlated against
@@ -377,15 +334,15 @@ class ConnectionPanel(panel.Panel, threading.Thread):
         elif attr == SortAttr.PORT:
           return connection_line.connection.remote_port
         elif attr == SortAttr.FINGERPRINT:
-          return connection_line.get_fingerprint('UNKNOWN')
+          return connection_line.fingerprint if connection_line.fingerprint else 'UNKNOWN'
         elif attr == SortAttr.NICKNAME:
-          return connection_line.get_nickname('z' * 20)
+          return connection_line.nickname if connection_line.nickname else 'z' * 20
         elif attr == SortAttr.CATEGORY:
           return Category.index_of(entry.get_type())
         elif attr == SortAttr.UPTIME:
           return connection_line.connection.start_time
         elif attr == SortAttr.COUNTRY:
-          return '' if entry.is_private() else connection_line.get_locale('')
+          return '' if entry.is_private() else (connection_line.locale if connection_line.locale else '')
         else:
           return ''
 
@@ -459,10 +416,9 @@ class ConnectionPanel(panel.Panel, threading.Thread):
           if not selection:
             break
 
-          color = CONFIG['attr.connection.category_color'].get(selection._entry.get_type(), 'white')
-          fingerprint = selection.get_fingerprint()
+          color = CONFIG['attr.connection.category_color'].get(selection.entry.get_type(), 'white')
           is_close_key = lambda key: key.is_selection() or key.match('d') or key.match('left') or key.match('right')
-          key = nyx.popups.show_descriptor_popup(fingerprint, color, self.max_x, is_close_key)
+          key = nyx.popups.show_descriptor_popup(selection.fingerprint, color, self.max_x, is_close_key)
 
           if not key or key.is_selection() or key.match('d'):
             break  # closes popup
@@ -592,14 +548,14 @@ class ConnectionPanel(panel.Panel, threading.Thread):
     Shows detailed information about the selected connection.
     """
 
-    attr = (CONFIG['attr.connection.category_color'].get(selected._entry.get_type(), 'white'), curses.A_BOLD)
+    attr = (CONFIG['attr.connection.category_color'].get(selected.entry.get_type(), 'white'), curses.A_BOLD)
 
-    if isinstance(selected, CircHeaderLine) and not selected.is_built:
+    if selected.line_type == LineType.CIRCUIT_HEADER and selected.circuit.status != 'BUILT':
       self.addstr(1, 2, 'Building Circuit...', *attr)
     else:
-      address = '<scrubbed>' if selected._entry.is_private() else selected.connection.remote_address
+      address = '<scrubbed>' if selected.entry.is_private() else selected.connection.remote_address
       self.addstr(1, 2, 'address: %s:%s' % (address, selected.connection.remote_port), *attr)
-      self.addstr(2, 2, 'locale: %s' % ('??' if selected._entry.is_private() else selected.get_locale('??')), *attr)
+      self.addstr(2, 2, 'locale: %s' % ('??' if selected.entry.is_private() else (selected.locale if selected.locale else '??')), *attr)
 
       matches = nyx.util.tracker.get_consensus_tracker().get_relay_fingerprints(selected.connection.remote_address)
 
@@ -649,8 +605,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
       self.addch(DETAILS_HEIGHT + 1, 1, curses.ACS_TTEE)
 
   def _draw_line(self, x, y, line, is_selected, width, current_time):
-    if isinstance(line, CircLine):
-      if line.circuit.path[-1][0] == line.get_fingerprint():
+    if line.line_type == LineType.CIRCUIT:
+      if line.circuit.path[-1][0] == line.fingerprint:
         prefix = (ord(' '), curses.ACS_LLCORNER, curses.ACS_HLINE, ord(' '))
       else:
         prefix = (ord(' '), curses.ACS_VLINE, ord(' '), ord(' '))
@@ -658,27 +614,27 @@ class ConnectionPanel(panel.Panel, threading.Thread):
       for char in prefix:
         x = self.addch(y, x, char)
 
-    entry_type = line._entry.get_type()
+    entry_type = line.entry.get_type()
     attr = nyx.util.ui_tools.get_color(CONFIG['attr.connection.category_color'].get(entry_type, 'white'))
     attr |= curses.A_STANDOUT if is_selected else curses.A_NORMAL
 
     def get_destination_label(line, width):
-      output = '<scrubbed>' if line._entry.is_private() else line.connection.remote_address
+      output = '<scrubbed>' if line.entry.is_private() else line.connection.remote_address
       output += ':%s' % line.connection.remote_port
       space_available = width - len(output) - 3
 
-      if line._entry.get_type() == Category.EXIT and space_available >= 5:
+      if line.entry.get_type() == Category.EXIT and space_available >= 5:
         purpose = connection.port_usage(line.connection.remote_port)
 
         if purpose:
           output += ' (%s)' % str_tools.crop(purpose, space_available)
-      elif space_available >= 2 and not tor_controller().is_geoip_unavailable() and not line._entry.is_private():
-        output += ' (%s)' % line.get_locale('??')
+      elif space_available >= 2 and not tor_controller().is_geoip_unavailable() and not line.entry.is_private():
+        output += ' (%s)' % (line.locale if line.locale else '??')
 
       return output[:width]
 
     def get_etc_content(line, width):
-      if isinstance(line, CircHeaderLine):
+      if line.line_type == LineType.CIRCUIT_HEADER:
         etc_attr = ['Purpose: %s' % line.circuit.purpose.capitalize(), 'Circuit ID: %s' % line.circuit.id]
 
         for i in range(len(etc_attr), -1, -1):
@@ -691,8 +647,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
       else:
         # for applications show the command/pid
 
-        if line._entry.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
-          port = line.connection.local_port if line._entry.get_type() == Category.HIDDEN else line.connection.remote_port
+        if line.entry.get_type() in (Category.SOCKS, Category.HIDDEN, Category.CONTROL):
+          port = line.connection.local_port if line.entry.get_type() == Category.HIDDEN else line.connection.remote_port
 
           try:
             process = nyx.util.tracker.get_port_usage_tracker().fetch(port)
@@ -714,14 +670,14 @@ class ConnectionPanel(panel.Panel, threading.Thread):
         if width > used_space + 42:
           # show fingerprint (column width: 42 characters)
 
-          etc += '%-40s  ' % line.get_fingerprint('UNKNOWN')
+          etc += '%-40s  ' % (line.fingerprint if line.fingerprint else 'UNKNOWN')
           used_space += 42
 
         if width > used_space + 10:
           # show nickname (column width: remainder)
 
           nickname_space = width - used_space
-          nickname_label = str_tools.crop(line.get_nickname('UNKNOWN'), nickname_space, 0)
+          nickname_label = str_tools.crop(line.nickname if line.nickname else 'UNKNOWN', nickname_space, 0)
           etc += ('%%-%is  ' % nickname_space) % nickname_label
           used_space += nickname_space + 2
 
@@ -729,14 +685,14 @@ class ConnectionPanel(panel.Panel, threading.Thread):
 
     self.addstr(y, x, ' ' * (width - x), attr)
 
-    if not isinstance(line, CircLine):
+    if line.line_type != LineType.CIRCUIT:
       subsection_width = width - x - 19
 
-      include_port = not isinstance(line, CircHeaderLine)
+      include_port = line.line_type != LineType.CIRCUIT_HEADER
       src = tor_controller().get_info('address', line.connection.local_address)
       src += ':%s' % line.connection.local_port if include_port else ''
 
-      if isinstance(line, CircHeaderLine) and not line.is_built:
+      if line.line_type == LineType.CIRCUIT_HEADER and line.circuit.status != 'BUILT':
         dst = 'Building...'
       else:
         dst = get_destination_label(line, 26)
@@ -755,11 +711,11 @@ class ConnectionPanel(panel.Panel, threading.Thread):
       x = self.addstr(y, x, ')', attr)
     else:
       self.addstr(y, x, get_destination_label(line, 25), attr)
-      self.addstr(y, x + 25, str_tools.crop(line.get_nickname('UNKNOWN'), 25, 0), attr)
+      self.addstr(y, x + 25, str_tools.crop(line.nickname if line.nickname else 'UNKNOWN', 25, 0), attr)
       self.addstr(y, x + 53, get_etc_content(line, width - x - 19 - 53), attr)
 
       circ_path = [path_entry[0] for path_entry in line.circuit.path]
-      circ_index = circ_path.index(line.get_fingerprint())
+      circ_index = circ_path.index(line.fingerprint)
 
       if circ_index == len(circ_path) - 1:
         placement_type = 'Exit' if line.circuit.status == 'BUILT' else 'Extending'
@@ -810,10 +766,8 @@ class ConnectionPanel(panel.Panel, threading.Thread):
 
         if entry.is_private():
           if entry.get_type() == Category.INBOUND:
-            client_locale = entry_line.get_locale(None)
-
-            if client_locale:
-              self._client_locale_usage[client_locale] = self._client_locale_usage.get(client_locale, 0) + 1
+            if entry_line.locale:
+              self._client_locale_usage[entry_line.locale] = self._client_locale_usage.get(entry_line.locale, 0) + 1
           elif entry.get_type() == Category.EXIT:
             exit_port = entry_line.connection.remote_port
             self._exit_port_usage[exit_port] = self._exit_port_usage.get(exit_port, 0) + 1



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits