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

[or-cvs] r23693: {arm} Adding a simple panel for config settings (in arm/trunk: . src/interface)



Author: atagar
Date: 2010-10-27 16:41:20 +0000 (Wed, 27 Oct 2010)
New Revision: 23693

Added:
   arm/trunk/src/interface/configStatePanel.py
Modified:
   arm/trunk/README
   arm/trunk/src/interface/__init__.py
   arm/trunk/src/interface/configFilePanel.py
   arm/trunk/src/interface/controller.py
Log:
Adding a simple panel for config settings



Modified: arm/trunk/README
===================================================================
--- arm/trunk/README	2010-10-27 12:20:16 UTC (rev 23692)
+++ arm/trunk/README	2010-10-27 16:41:20 UTC (rev 23693)
@@ -126,7 +126,8 @@
       connPanel.py           - (page 2) displays information on tor connections
       descriptorPopup.py     - (popup) displays connection descriptor data
       
-      confPanel.py           - (page 3) displays torrc and performs validation
+      configFilePanel.py     - (page 3) displays torrc/armrc and validation
+      configStatePanel.py    - editor panel for the tor and arm config states
     
     util/
       __init__.py

Modified: arm/trunk/src/interface/__init__.py
===================================================================
--- arm/trunk/src/interface/__init__.py	2010-10-27 12:20:16 UTC (rev 23692)
+++ arm/trunk/src/interface/__init__.py	2010-10-27 16:41:20 UTC (rev 23693)
@@ -2,5 +2,5 @@
 Panels, popups, and handlers comprising the arm user interface.
 """
 
-__all__ = ["confPanel", "connPanel", "controller", "descriptorPopup", "fileDescriptorPopup", "headerPanel", "logPanel"]
+__all__ = ["configFilePanel", "configStatePanel", "connPanel", "controller", "descriptorPopup", "fileDescriptorPopup", "headerPanel", "logPanel"]
 

Modified: arm/trunk/src/interface/configFilePanel.py
===================================================================
--- arm/trunk/src/interface/configFilePanel.py	2010-10-27 12:20:16 UTC (rev 23692)
+++ arm/trunk/src/interface/configFilePanel.py	2010-10-27 16:41:20 UTC (rev 23693)
@@ -20,7 +20,7 @@
   """
   
   def __init__(self, stdscr, configType, config=None):
-    panel.Panel.__init__(self, stdscr, "conf", 0)
+    panel.Panel.__init__(self, stdscr, "confFile", 0)
     
     self._config = dict(DEFAULT_CONFIG)
     if config:

Added: arm/trunk/src/interface/configStatePanel.py
===================================================================
--- arm/trunk/src/interface/configStatePanel.py	                        (rev 0)
+++ arm/trunk/src/interface/configStatePanel.py	2010-10-27 16:41:20 UTC (rev 23693)
@@ -0,0 +1,130 @@
+"""
+Panel presenting the configuration state for tor or arm. Options can be edited
+and the resulting configuration files saved.
+"""
+
+import curses
+import threading
+
+from util import conf, panel, torTools, uiTools
+
+DEFAULT_CONFIG = {"torrc.map": {}}
+
+TOR_STATE, ARM_STATE = range(1, 3) # state to be presented
+
+class ConfigEntry():
+  """
+  Configuration option in the panel.
+  """
+  
+  def __init__(self, option, value, type, description = ""):
+    self.option = option
+    self.value = value
+    self.type = type
+    self.description = description
+
+class ConfigStatePanel(panel.Panel):
+  """
+  Renders a listing of the tor or arm configuration state, allowing options to
+  be selected and edited.
+  """
+  
+  def __init__(self, stdscr, configType, config=None):
+    panel.Panel.__init__(self, stdscr, "confState", 0)
+    
+    self._config = dict(DEFAULT_CONFIG)
+    if config: config.update(self._config)
+    
+    self.configType = configType
+    self.confContents = []
+    self.scroll = 0
+    self.valsLock = threading.RLock()
+    
+    # TODO: this will need to be able to listen for SETCONF events (arg!)
+    
+    if self.configType == TOR_STATE:
+      # for all recognized tor config options, provide their current value
+      conn = torTools.getConn()
+      configOptionQuery = conn.getInfo("config/names", "").strip().split("\n")
+      
+      for lineNum in range(len(configOptionQuery)):
+        # lines are of the form "<option> <type>", like:
+        # UseEntryGuards Boolean
+        line = configOptionQuery[lineNum]
+        confOption, confType = line.strip().split(" ", 1)
+        
+        confValue = None
+        if confOption in self._config["torrc.map"]:
+          confMappings = conn.getOptionMap(self._config["torrc.map"][confOption], {})
+          if confOption in confMappings: confValue = confMappings[confOption]
+          fetchConfOption = self._config["torrc.map"][confOption]
+        else:
+          confValue = ", ".join(conn.getOption(confOption, [], True))
+        
+        # provides nicer values for recognized types
+        if not confValue: confValue = "<none>"
+        elif confType == "Boolean" and confValue in ("0", "1"):
+          confValue = "False" if confValue == "0" else "True"
+        elif confType == "DataSize" and confValue.isdigit():
+          confValue = uiTools.getSizeLabel(int(confValue))
+        elif confType == "TimeInterval" and confValue.isdigit():
+          confValue = uiTools.getTimeLabel(int(confValue), isLong = True)
+        
+        self.confContents.append(ConfigEntry(confOption, confValue, confType))
+    elif self.configType == ARM_STATE:
+      # loaded via the conf utility
+      armConf = conf.getConfig("arm")
+      for key in armConf.getKeys():
+        self.confContents.append(ConfigEntry(key, ", ".join(armConf.getValue(key, [], True)), ""))
+      #self.confContents.sort() # TODO: make contents sortable?
+  
+  def handleKey(self, key):
+    self.valsLock.acquire()
+    if uiTools.isScrollKey(key):
+      pageHeight = self.getPreferredSize()[0] - 1
+      newScroll = uiTools.getScrollPosition(key, self.scroll, pageHeight, len(self.confContents))
+      
+      if self.scroll != newScroll:
+        self.scroll = newScroll
+        self.redraw(True)
+  
+  def draw(self, subwindow, width, height):
+    self.valsLock.acquire()
+    
+    # draws the top label
+    sourceLabel = "Tor" if self.configType == TOR_STATE else "Arm"
+    self.addstr(0, 0, "%s Config:" % sourceLabel, curses.A_STANDOUT)
+    
+    # draws left-hand scroll bar if content's longer than the height
+    scrollOffset = 0
+    if len(self.confContents) > height - 1:
+      scrollOffset = 3
+      self.addScrollBar(self.scroll, self.scroll + height - 1, len(self.confContents), 1)
+    
+    # determines the width for the columns
+    optionColWidth, valueColWidth, typeColWidth = 0, 0, 0
+    
+    for entry in self.confContents:
+      optionColWidth = max(optionColWidth, len(entry.option))
+      valueColWidth = max(valueColWidth, len(entry.value))
+      typeColWidth = max(typeColWidth, len(entry.type))
+    
+    # TODO: make the size dynamic between the value and description
+    optionColWidth = min(25, optionColWidth)
+    valueColWidth = min(25, valueColWidth)
+    
+    for lineNum in range(self.scroll, len(self.confContents)):
+      entry = self.confContents[lineNum]
+      drawLine = lineNum + 1 - self.scroll
+      
+      optionLabel = uiTools.cropStr(entry.option, optionColWidth)
+      valueLabel = uiTools.cropStr(entry.value, valueColWidth)
+      
+      self.addstr(drawLine, scrollOffset, optionLabel, curses.A_BOLD | uiTools.getColor("green"))
+      self.addstr(drawLine, scrollOffset + optionColWidth + 1, valueLabel, curses.A_BOLD | uiTools.getColor("green"))
+      self.addstr(drawLine, scrollOffset + optionColWidth + valueColWidth + 2, entry.type, curses.A_BOLD | uiTools.getColor("green"))
+      
+      if drawLine >= height: break
+    
+    self.valsLock.release()
+

Modified: arm/trunk/src/interface/controller.py
===================================================================
--- arm/trunk/src/interface/controller.py	2010-10-27 12:20:16 UTC (rev 23692)
+++ arm/trunk/src/interface/controller.py	2010-10-27 16:41:20 UTC (rev 23693)
@@ -18,6 +18,7 @@
 import graphing.graphPanel
 import logPanel
 import connPanel
+import configStatePanel
 import configFilePanel
 import descriptorPopup
 import fileDescriptorPopup
@@ -422,7 +423,8 @@
   
   panels["conn"] = connPanel.ConnPanel(stdscr, conn, isBlindMode)
   panels["control"] = ControlPanel(stdscr, isBlindMode)
-  panels["torrc"] = configFilePanel.ConfigFilePanel(stdscr, configFilePanel.TORRC, config)
+  panels["torrc"] = configStatePanel.ConfigStatePanel(stdscr, configStatePanel.TOR_STATE, config)
+  #panels["torrc"] = configFilePanel.ConfigFilePanel(stdscr, configFilePanel.TORRC, config)
   
   # provides error if pid coulnd't be determined (hopefully shouldn't happen...)
   if not torPid: log.log(log.WARN, "Unable to resolve tor pid, abandoning connection listing")
@@ -527,7 +529,8 @@
         if panels["graph"].currentDisplay == "bandwidth":
           panels["graph"].setHeight(panels["graph"].stats["bandwidth"].getContentHeight())
         
-        panels["torrc"].loadConfig()
+        # TODO: should redraw the configFilePanel
+        #panels["torrc"].loadConfig()
         sighupTracker.isReset = False
       
       # gives panels a chance to take advantage of the maximum bounds
@@ -744,11 +747,12 @@
           popup.addfstr(2, 2, "<b>page up</b>: scroll up a page")
           popup.addfstr(2, 41, "<b>page down</b>: scroll down a page")
           
-          strippingLabel = "on" if panels["torrc"].stripComments else "off"
-          popup.addfstr(3, 2, "<b>s</b>: comment stripping (<b>%s</b>)" % strippingLabel)
+          # TODO: reintroduce options for the configFilePanel
+          #strippingLabel = "on" if panels["torrc"].stripComments else "off"
+          #popup.addfstr(3, 2, "<b>s</b>: comment stripping (<b>%s</b>)" % strippingLabel)
           
-          lineNumLabel = "on" if panels["torrc"].showLineNum else "off"
-          popup.addfstr(3, 41, "<b>n</b>: line numbering (<b>%s</b>)" % lineNumLabel)
+          #lineNumLabel = "on" if panels["torrc"].showLineNum else "off"
+          #popup.addfstr(3, 41, "<b>n</b>: line numbering (<b>%s</b>)" % lineNumLabel)
           
           popup.addfstr(4, 2, "<b>r</b>: reload torrc")
           popup.addfstr(4, 41, "<b>x</b>: reset tor (issue sighup)")
@@ -1406,7 +1410,7 @@
         setPauseState(panels, isPaused, page)
       finally:
         panel.CURSES_LOCK.release()
-    elif page == 2 and key == ord('r') or key == ord('R'):
+    elif page == 2 and False and key == ord('r') or key == ord('R'):
       # reloads torrc, providing a notice if successful or not
       loadedTorrc = torrc.getTorrc()
       loadedTorrc.getLock().acquire()