commit 35206a3a09979f6321aa8e9ce97728b4b1ccf92c
Author: Damian Johnson <atagar(a)torproject.org>
Date: Thu Jul 2 09:57:13 2015 -0700
Rewrite port count dialog
Revising the dialog that shows aggregated counts for entry or exit connections
(locales if a guard, or port usage if an exit). This is a pretty small popup
and code got even smaller with the cleanup, so moving it into popups.py.
---
nyx/connections/__init__.py | 1 -
nyx/connections/conn_panel.py | 19 +++++--
nyx/connections/count_popup.py | 107 ----------------------------------------
nyx/popups.py | 51 +++++++++++++++++++
4 files changed, 67 insertions(+), 111 deletions(-)
diff --git a/nyx/connections/__init__.py b/nyx/connections/__init__.py
index 447adf6..c7e90a9 100644
--- a/nyx/connections/__init__.py
+++ b/nyx/connections/__init__.py
@@ -6,7 +6,6 @@ __all__ = [
'circ_entry',
'conn_entry',
'conn_panel',
- 'count_popup',
'descriptor_popup',
'entries',
]
diff --git a/nyx/connections/conn_panel.py b/nyx/connections/conn_panel.py
index c555a38..0a27721 100644
--- a/nyx/connections/conn_panel.py
+++ b/nyx/connections/conn_panel.py
@@ -10,7 +10,7 @@ import threading
import nyx.popups
import nyx.util.tracker
-from nyx.connections import count_popup, descriptor_popup, entries, conn_entry, circ_entry
+from nyx.connections import descriptor_popup, entries, conn_entry, circ_entry
from nyx.util import panel, tor_controller, tracker, ui_tools
from stem.control import State
@@ -24,6 +24,8 @@ DETAILS_HEIGHT = 7
Listing = enum.Enum(('IP_ADDRESS', 'IP Address'), 'HOSTNAME', 'FINGERPRINT', 'NICKNAME')
+EXIT_USAGE_WIDTH = 15
+
def conf_handler(key, value):
if key == 'features.connection.listing_type':
@@ -335,9 +337,20 @@ class ConnectionPanel(panel.Panel, threading.Thread):
self.set_title_visible(True)
self.redraw(True)
elif key.match('c') and self.is_clients_allowed():
- count_popup.showCountDialog(count_popup.CountType.CLIENT_LOCALE, self._client_locale_usage)
+ nyx.popups.show_count_dialog('Client Locales', self._client_locale_usage)
elif key.match('e') and self.is_exits_allowed():
- count_popup.showCountDialog(count_popup.CountType.EXIT_PORT, self._exit_port_usage)
+ counts = {}
+ key_width = max(map(len, self._exit_port_usage.keys()))
+
+ for k, v in self._exit_port_usage.items():
+ usage = connection.port_usage(k)
+
+ if usage:
+ k = k.ljust(key_width + 3) + usage.ljust(EXIT_USAGE_WIDTH)
+
+ counts[k] = v
+
+ nyx.popups.show_count_dialog('Exiting Port Usage', counts)
else:
return False
diff --git a/nyx/connections/count_popup.py b/nyx/connections/count_popup.py
deleted file mode 100644
index e61dc26..0000000
--- a/nyx/connections/count_popup.py
+++ /dev/null
@@ -1,107 +0,0 @@
-"""
-Provides a dialog with client locale or exiting port counts.
-"""
-
-import curses
-import operator
-
-import nyx.controller
-import nyx.popups
-
-from stem.util import connection, enum, log
-
-CountType = enum.Enum('CLIENT_LOCALE', 'EXIT_PORT')
-EXIT_USAGE_WIDTH = 15
-
-
-def showCountDialog(count_type, counts):
- """
- Provides a dialog with bar graphs and percentages for the given set of
- counts. Pressing any key closes the dialog.
-
- Arguments:
- count_type - type of counts being presented
- counts - mapping of labels to counts
- """
-
- is_no_stats = not counts
- no_stats_msg = "Usage stats aren't available yet, press any key..."
-
- if is_no_stats:
- height, width = 3, len(no_stats_msg) + 4
- else:
- height, width = 4 + max(1, len(counts)), 80
-
- with nyx.popups.popup_window(height, width) as (popup, height, width):
- if popup:
- control = nyx.controller.get_controller()
-
- popup.win.box()
-
- # dialog title
-
- if count_type == CountType.CLIENT_LOCALE:
- title = 'Client Locales'
- elif count_type == CountType.EXIT_PORT:
- title = 'Exiting Port Usage'
- else:
- title = ''
- log.warn('Unrecognized count type: %s' % count_type)
-
- popup.addstr(0, 0, title, curses.A_STANDOUT)
-
- if is_no_stats:
- popup.addstr(1, 2, no_stats_msg, curses.A_BOLD, 'cyan')
- else:
- sorted_counts = sorted(counts.iteritems(), key=operator.itemgetter(1))
- sorted_counts.reverse()
-
- # constructs string formatting for the max key and value display width
-
- key_width, val_width, value_total = 3, 1, 0
-
- for k, v in sorted_counts:
- key_width = max(key_width, len(k))
- val_width = max(val_width, len(str(v)))
- value_total += v
-
- # extra space since we're adding usage informaion
-
- if count_type == CountType.EXIT_PORT:
- key_width += EXIT_USAGE_WIDTH
-
- label_format = '%%-%is %%%ii (%%%%%%-2i)' % (key_width, val_width)
-
- for i in range(height - 4):
- k, v = sorted_counts[i]
-
- # includes a port usage column
-
- if count_type == CountType.EXIT_PORT:
- usage = connection.port_usage(k)
-
- if usage:
- key_format = '%%-%is %%s' % (key_width - EXIT_USAGE_WIDTH)
- k = key_format % (k, usage[:EXIT_USAGE_WIDTH - 3])
-
- label = label_format % (k, v, v * 100 / value_total)
- popup.addstr(i + 1, 2, label, curses.A_BOLD, 'green')
-
- # All labels have the same size since they're based on the max widths.
- # If this changes then this'll need to be the max label width.
-
- label_width = len(label)
-
- # draws simple bar graph for percentages
-
- fill_width = v * (width - 4 - label_width) / value_total
-
- for j in range(fill_width):
- popup.addstr(i + 1, 3 + label_width + j, ' ', curses.A_STANDOUT, 'red')
-
- popup.addstr(height - 2, 2, 'Press any key...')
-
- popup.win.refresh()
-
- curses.cbreak()
- control.key_input()
diff --git a/nyx/popups.py b/nyx/popups.py
index 38eade0..351467f 100644
--- a/nyx/popups.py
+++ b/nyx/popups.py
@@ -3,12 +3,15 @@ Functions for displaying popups in the interface.
"""
import curses
+import operator
import nyx.controller
from nyx import __version__, __release_date__
from nyx.util import panel, ui_tools
+NO_STATS_MSG = "Usage stats aren't available yet, press any key..."
+
def popup_window(height = -1, width = -1, top = 0, left = 0, below_static = True):
"""
@@ -199,6 +202,54 @@ def show_about_popup():
control.key_input()
+def show_count_dialog(title, counts):
+ """
+ Provides a dialog with bar graphs and percentages for the given set of
+ counts. Pressing any key closes the dialog.
+
+ :param str title: dialog title
+ :param dict counts: mapping of labels to their value
+ """
+
+ if not counts:
+ height, width = 3, len(NO_STATS_MSG) + 4
+ else:
+ height, width = 4 + max(1, len(counts)), 80
+
+ with nyx.popups.popup_window(height, width) as (popup, width, height):
+ if not popup:
+ return
+
+ if not counts:
+ popup.addstr(1, 2, NO_STATS_MSG, curses.A_BOLD, 'cyan')
+ else:
+ key_width, val_width, value_total = 3, 1, 0
+
+ for k, v in counts.items():
+ key_width = max(key_width, len(k))
+ val_width = max(val_width, len(str(v)))
+ value_total += v
+
+ sorted_counts = sorted(counts.iteritems(), key = operator.itemgetter(1), reverse = True)
+ graph_width = width - key_width - val_width - 11 # border, extra spaces, and percentage column
+
+ for y, (k, v) in enumerate(sorted_counts):
+ label = '%s %s (%-2i%%)' % (k.ljust(key_width), str(v).rjust(val_width), v * 100 / value_total)
+ x = popup.addstr(y + 1, 2, label, curses.A_BOLD, 'green')
+
+ for j in range(graph_width * v / value_total):
+ popup.addstr(y + 1, x + j + 1, ' ', curses.A_STANDOUT, 'red')
+
+ popup.addstr(height - 2, 2, 'Press any key...')
+
+ popup.win.box()
+ popup.addstr(0, 0, title, curses.A_STANDOUT)
+ popup.win.refresh()
+
+ curses.cbreak()
+ nyx.controller.get_controller().key_input()
+
+
def show_sort_dialog(title, options, old_selection, option_colors):
"""
Displays a sorting dialog of the form: