[or-cvs] r19636: {arm} Added command line argument to specify locatoin of TorCtl wi (in arm/trunk: . interface)
atagar at seul.org
atagar at seul.org
Sat Jun 6 17:09:34 UTC 2009
Author: atagar
Date: 2009-06-06 13:09:34 -0400 (Sat, 06 Jun 2009)
New Revision: 19636
Modified:
arm/trunk/arm.py
arm/trunk/interface/logPanel.py
arm/trunk/readme.txt
Log:
Added command line argument to specify locatoin of TorCtl without changing Python path first (feature request by phobos).
Modified: arm/trunk/arm.py
===================================================================
--- arm/trunk/arm.py 2009-06-06 05:25:18 UTC (rev 19635)
+++ arm/trunk/arm.py 2009-06-06 17:09:34 UTC (rev 19636)
@@ -14,14 +14,6 @@
import getpass
import binascii
-try:
- from TorCtl import TorCtl
- from TorCtl import TorUtil
-except ImportError:
- print "Unable to load TorCtl (see readme for instructions)"
- sys.exit()
-
-from interface import controller
from interface import logPanel
DEFAULT_CONTROL_ADDR = "127.0.0.1"
@@ -41,6 +33,7 @@
without terminal echo if not provided
-e, --event=[EVENT FLAGS] event types in message log (default: %s)
%s
+ --path-to-torctl=[PATH] location of TorCtl if not in Python path
-h, --help presents this help
Example:
@@ -49,6 +42,13 @@
arm -e=we -p=nemesis use password 'nemesis' with 'WARN'/'ERR' events
""" % (DEFAULT_CONTROL_ADDR, DEFAULT_CONTROL_PORT, DEFAULT_AUTH_COOKIE, DEFAULT_LOGGED_EVENTS, logPanel.EVENT_LISTING)
+EVENT_LISTING = """ d DEBUG a ADDRMAP l NEWDESC u AUTHDIR_NEWDESCS
+ i INFO b BW m NS v CLIENTS_SEEN
+ n NOTICE c CIRC o ORCONN x STATUS_GENERAL
+ w WARN f DESCCHANGED s STREAM y STATUS_CLIENT
+ e ERR g GUARD t STREAM_BW z STATUS_SERVER
+ Aliases: A All Events U Unknown Events R Runlevels (dinwe)"""
+
class Input:
"Collection of the user's command line input"
@@ -59,6 +59,7 @@
self.authCookieLoc = DEFAULT_AUTH_COOKIE # location of authentication cookie
self.authPassword = "" # authentication password
self.loggedEvents = DEFAULT_LOGGED_EVENTS # flags for event types in message log
+ self.pathAppend = "" # additions to Python path
self.isValid = True # determines if the program should run
self.printHelp = False # prints help then quits
self._parseArgs(args)
@@ -123,6 +124,10 @@
if args[0].startswith("-e="): self.loggedEvents = args[0][3:]
else: self.loggedEvents = args[0][8:]
self._parseArgs(args[1:])
+ elif args[0].startswith("--path-to-torctl="):
+ # appends location to Python path (to help find TorCtl)
+ self.pathAppend = args[0][17:]
+ self._parseArgs(args[1:])
elif args[0] == "-h" or args[0] == "--help":
self.printHelp = True
self._parseArgs(args[1:])
@@ -163,6 +168,20 @@
print HELP_TEXT
sys.exit()
+ # appends appending to Python path
+ if input.pathAppend:
+ sys.path.append(input.pathAppend)
+
+ # tries to load TorCtl
+ try:
+ from TorCtl import TorCtl
+ from TorCtl import TorUtil
+
+ from interface import controller
+ except ImportError:
+ print "Unable to load TorCtl (see readme for instructions)"
+ sys.exit()
+
# validates that cookie authentication path exists
if input.authType == COOKIE_AUTH and not os.path.exists(input.authCookieLoc):
print "Authentication cookie doesn't exist: %s" % input.authCookieLoc
Modified: arm/trunk/interface/logPanel.py
===================================================================
--- arm/trunk/interface/logPanel.py 2009-06-06 05:25:18 UTC (rev 19635)
+++ arm/trunk/interface/logPanel.py 2009-06-06 17:09:34 UTC (rev 19636)
@@ -5,7 +5,6 @@
import time
import curses
from curses.ascii import isprint
-from TorCtl import TorCtl
import util
@@ -58,195 +57,200 @@
if invalidFlags: raise ValueError(invalidFlags)
else: return expandedEvents
-class LogMonitor(TorCtl.PostEventListener, util.Panel):
- """
- Tor event listener, noting messages, the time, and their type in a panel.
- """
+try:
+ from TorCtl import TorCtl
- def __init__(self, lock, loggedEvents):
- TorCtl.PostEventListener.__init__(self)
- util.Panel.__init__(self, lock, -1)
- self.msgLog = [] # tuples of (logText, color)
- self.isPaused = False
- self.pauseBuffer = [] # location where messages are buffered if paused
- self.loggedEvents = loggedEvents # events we're listening to
- self.lastHeartbeat = time.time() # time of last BW event
-
- # Listens for all event types and redirects to registerEvent
- def circ_status_event(self, event):
- optionalParams = ""
- if event.purpose: optionalParams += " PURPOSE: %s" % event.purpose
- if event.reason: optionalParams += " REASON: %s" % event.reason
- if event.remote_reason: optionalParams += " REMOTE_REASON: %s" % event.remote_reason
- self.registerEvent("CIRC", "ID: %-3s STATUS: %-10s PATH: %s%s" % (event.circ_id, event.status, ", ".join(event.path), optionalParams), "yellow")
-
- def stream_status_event(self, event):
- # TODO: not sure how to stimulate event - needs sanity check
- try:
- self.registerEvent("STREAM", "ID: %s STATUS: %s CIRC_ID: %s TARGET: %s:%s REASON: %s REMOTE_REASON: %s SOURCE: %s SOURCE_ADDR: %s PURPOSE: %s" % (event.strm_id, event.status, event.circ_id, event.target_host, event.target_port, event.reason, event.remote_reason, event.source, event.source_addr, event.purpose), "white")
- except TypeError:
- self.registerEvent("STREAM", "DEBUG -> ID: %s STATUS: %s CIRC_ID: %s TARGET: %s:%s REASON: %s REMOTE_REASON: %s SOURCE: %s SOURCE_ADDR: %s PURPOSE: %s" % (type(event.strm_id), type(event.status), type(event.circ_id), type(event.target_host), type(event.target_port), type(event.reason), type(event.remote_reason), type(event.source), type(event.source_addr), type(event.purpose)), "white")
-
- def or_conn_status_event(self, event):
- optionalParams = ""
- if event.age: optionalParams += " AGE: %-3s" % event.age
- if event.read_bytes: optionalParams += " READ: %-4i" % event.read_bytes
- if event.wrote_bytes: optionalParams += " WRITTEN: %-4i" % event.wrote_bytes
- if event.reason: optionalParams += " REASON: %-6s" % event.reason
- if event.ncircs: optionalParams += " NCIRCS: %i" % event.ncircs
- self.registerEvent("ORCONN", "STATUS: %-10s ENDPOINT: %-20s%s" % (event.status, event.endpoint, optionalParams), "white")
-
- def stream_bw_event(self, event):
- # TODO: not sure how to stimulate event - needs sanity check
- try:
- self.registerEvent("STREAM_BW", "ID: %s READ: %i WRITTEN: %i" % (event.strm_id, event.bytes_read, event.bytes_written), "white")
- except TypeError:
- self.registerEvent("STREAM_BW", "DEBUG -> ID: %s READ: %i WRITTEN: %i" % (type(event.strm_id), type(event.bytes_read), type(event.bytes_written)), "white")
-
- def bandwidth_event(self, event):
- self.lastHeartbeat = time.time()
- if "BW" in self.loggedEvents: self.registerEvent("BW", "READ: %i, WRITTEN: %i" % (event.read, event.written), "cyan")
-
- def msg_event(self, event):
- self.registerEvent(event.level, event.msg, RUNLEVEL_EVENT_COLOR[event.level])
-
- def new_desc_event(self, event):
- idlistStr = [str(item) for item in event.idlist]
- self.registerEvent("NEWDESC", ", ".join(idlistStr), "white")
-
- def address_mapped_event(self, event):
- self.registerEvent("ADDRMAP", "%s, %s -> %s" % (event.when, event.from_addr, event.to_addr), "white")
-
- def ns_event(self, event):
- # NetworkStatus params: nickname, idhash, orhash, ip, orport (int), dirport (int), flags, idhex, bandwidth, updated (datetime)
- msg = ""
- for ns in event.nslist:
- msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
- if len(msg) > 1: msg = msg[2:]
- self.registerEvent("NS", "Listed (%i): %s" % (len(event.nslist), msg), "blue")
-
- def new_consensus_event(self, event):
- msg = ""
- for ns in event.nslist:
- msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
- self.registerEvent("NEWCONSENSUS", "Listed (%i): %s" % (len(event.nslist), msg), "magenta")
-
- def unknown_event(self, event):
- if "UNKNOWN" in self.loggedEvents: self.registerEvent("UNKNOWN", event.event_string, "red")
-
- def monitor_event(self, level, msg):
- # events provided by the arm monitor - types use the same as runlevel
- self.registerEvent("ARM-%s" % level, msg, RUNLEVEL_EVENT_COLOR[level])
-
- def registerEvent(self, type, msg, color):
+ class LogMonitor(TorCtl.PostEventListener, util.Panel):
"""
- Notes event and redraws log. If paused it's held in a temporary buffer.
+ Tor event listener, noting messages, the time, and their type in a panel.
"""
- # strips control characters to avoid screwing up the terminal
- msg = "".join([char for char in msg if isprint(char)])
+ def __init__(self, lock, loggedEvents):
+ TorCtl.PostEventListener.__init__(self)
+ util.Panel.__init__(self, lock, -1)
+ self.msgLog = [] # tuples of (logText, color)
+ self.isPaused = False
+ self.pauseBuffer = [] # location where messages are buffered if paused
+ self.loggedEvents = loggedEvents # events we're listening to
+ self.lastHeartbeat = time.time() # time of last BW event
- eventTime = time.localtime()
- msgLine = "%02i:%02i:%02i [%s] %s" % (eventTime[3], eventTime[4], eventTime[5], type, msg)
+ # Listens for all event types and redirects to registerEvent
+ def circ_status_event(self, event):
+ optionalParams = ""
+ if event.purpose: optionalParams += " PURPOSE: %s" % event.purpose
+ if event.reason: optionalParams += " REASON: %s" % event.reason
+ if event.remote_reason: optionalParams += " REMOTE_REASON: %s" % event.remote_reason
+ self.registerEvent("CIRC", "ID: %-3s STATUS: %-10s PATH: %s%s" % (event.circ_id, event.status, ", ".join(event.path), optionalParams), "yellow")
- if self.isPaused:
- self.pauseBuffer.insert(0, (msgLine, color))
- if len(self.pauseBuffer) > MAX_LOG_ENTRIES: del self.pauseBuffer[MAX_LOG_ENTRIES:]
- else:
- self.msgLog.insert(0, (msgLine, color))
- if len(self.msgLog) > MAX_LOG_ENTRIES: del self.msgLog[MAX_LOG_ENTRIES:]
- self.redraw()
-
- def redraw(self):
- """
- Redraws message log. Entries stretch to use available space and may
- contain up to two lines. Starts with newest entries.
- """
+ def stream_status_event(self, event):
+ # TODO: not sure how to stimulate event - needs sanity check
+ try:
+ self.registerEvent("STREAM", "ID: %s STATUS: %s CIRC_ID: %s TARGET: %s:%s REASON: %s REMOTE_REASON: %s SOURCE: %s SOURCE_ADDR: %s PURPOSE: %s" % (event.strm_id, event.status, event.circ_id, event.target_host, event.target_port, event.reason, event.remote_reason, event.source, event.source_addr, event.purpose), "white")
+ except TypeError:
+ self.registerEvent("STREAM", "DEBUG -> ID: %s STATUS: %s CIRC_ID: %s TARGET: %s:%s REASON: %s REMOTE_REASON: %s SOURCE: %s SOURCE_ADDR: %s PURPOSE: %s" % (type(event.strm_id), type(event.status), type(event.circ_id), type(event.target_host), type(event.target_port), type(event.reason), type(event.remote_reason), type(event.source), type(event.source_addr), type(event.purpose)), "white")
- if self.win:
- if not self.lock.acquire(False): return
+ def or_conn_status_event(self, event):
+ optionalParams = ""
+ if event.age: optionalParams += " AGE: %-3s" % event.age
+ if event.read_bytes: optionalParams += " READ: %-4i" % event.read_bytes
+ if event.wrote_bytes: optionalParams += " WRITTEN: %-4i" % event.wrote_bytes
+ if event.reason: optionalParams += " REASON: %-6s" % event.reason
+ if event.ncircs: optionalParams += " NCIRCS: %i" % event.ncircs
+ self.registerEvent("ORCONN", "STATUS: %-10s ENDPOINT: %-20s%s" % (event.status, event.endpoint, optionalParams), "white")
+
+ def stream_bw_event(self, event):
+ # TODO: not sure how to stimulate event - needs sanity check
try:
- self.clear()
-
- # draws label - uses ellipsis if too long, for instance:
- # Events (DEBUG, INFO, NOTICE, WARN...):
- eventsLabel = "Events"
- eventsListing = ", ".join(self.loggedEvents)
-
- firstLabelLen = eventsListing.find(", ")
- if firstLabelLen == -1: firstLabelLen = len(eventsListing)
- else: firstLabelLen += 3
-
- if self.maxX > 10 + firstLabelLen:
- eventsLabel += " ("
- if len(eventsListing) > self.maxX - 11:
- labelBreak = eventsListing[:self.maxX - 12].rfind(", ")
- eventsLabel += "%s..." % eventsListing[:labelBreak]
- else: eventsLabel += eventsListing
- eventsLabel += ")"
- eventsLabel += ":"
-
- self.addstr(0, 0, eventsLabel, util.LABEL_ATTR)
-
- # log entries
- lineCount = 1
-
- for (line, color) in self.msgLog:
- # splits over too lines if too long
- if len(line) < self.maxX:
- self.addstr(lineCount, 0, line, util.getColor(color))
- lineCount += 1
- else:
- (line1, line2) = self._splitLine(line, self.maxX)
- self.addstr(lineCount, 0, line1, util.getColor(color))
- self.addstr(lineCount + 1, 0, line2, util.getColor(color))
- lineCount += 2
-
- if lineCount >= self.maxY: break # further log messages wouldn't fit
- self.refresh()
- finally:
- self.lock.release()
-
- def setPaused(self, isPause):
- """
- If true, prevents message log from being updated with new events.
- """
+ self.registerEvent("STREAM_BW", "ID: %s READ: %i WRITTEN: %i" % (event.strm_id, event.bytes_read, event.bytes_written), "white")
+ except TypeError:
+ self.registerEvent("STREAM_BW", "DEBUG -> ID: %s READ: %i WRITTEN: %i" % (type(event.strm_id), type(event.bytes_read), type(event.bytes_written)), "white")
- if isPause == self.isPaused: return
+ def bandwidth_event(self, event):
+ self.lastHeartbeat = time.time()
+ if "BW" in self.loggedEvents: self.registerEvent("BW", "READ: %i, WRITTEN: %i" % (event.read, event.written), "cyan")
- self.isPaused = isPause
- if self.isPaused: self.pauseBuffer = []
- else:
- self.msgLog = (self.pauseBuffer + self.msgLog)[:MAX_LOG_ENTRIES]
- self.redraw()
-
- def getHeartbeat(self):
- """
- Provides the number of seconds since the last BW event.
- """
+ def msg_event(self, event):
+ self.registerEvent(event.level, event.msg, RUNLEVEL_EVENT_COLOR[event.level])
- return time.time() - self.lastHeartbeat
-
- # divides long message to cover two lines
- def _splitLine(self, message, x):
- # divides message into two lines, attempting to do it on a wordbreak
- lastWordbreak = message[:x].rfind(" ")
- if x - lastWordbreak < 10:
- line1 = message[:lastWordbreak]
- line2 = " %s" % message[lastWordbreak:].strip()
- else:
- # over ten characters until the last word - dividing
- line1 = "%s-" % message[:x - 2]
- line2 = " %s" % message[x - 2:].strip()
+ def new_desc_event(self, event):
+ idlistStr = [str(item) for item in event.idlist]
+ self.registerEvent("NEWDESC", ", ".join(idlistStr), "white")
- # ends line with ellipsis if too long
- if len(line2) > x:
- lastWordbreak = line2[:x - 4].rfind(" ")
+ def address_mapped_event(self, event):
+ self.registerEvent("ADDRMAP", "%s, %s -> %s" % (event.when, event.from_addr, event.to_addr), "white")
+
+ def ns_event(self, event):
+ # NetworkStatus params: nickname, idhash, orhash, ip, orport (int), dirport (int), flags, idhex, bandwidth, updated (datetime)
+ msg = ""
+ for ns in event.nslist:
+ msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
+ if len(msg) > 1: msg = msg[2:]
+ self.registerEvent("NS", "Listed (%i): %s" % (len(event.nslist), msg), "blue")
+
+ def new_consensus_event(self, event):
+ msg = ""
+ for ns in event.nslist:
+ msg += ", %s (%s:%i)" % (ns.nickname, ns.ip, ns.orport)
+ self.registerEvent("NEWCONSENSUS", "Listed (%i): %s" % (len(event.nslist), msg), "magenta")
+
+ def unknown_event(self, event):
+ if "UNKNOWN" in self.loggedEvents: self.registerEvent("UNKNOWN", event.event_string, "red")
+
+ def monitor_event(self, level, msg):
+ # events provided by the arm monitor - types use the same as runlevel
+ self.registerEvent("ARM-%s" % level, msg, RUNLEVEL_EVENT_COLOR[level])
+
+ def registerEvent(self, type, msg, color):
+ """
+ Notes event and redraws log. If paused it's held in a temporary buffer.
+ """
- # doesn't use wordbreak if it's a long word or the whole line is one
- # word (picking up on two space indent to have index 1)
- if x - lastWordbreak > 10 or lastWordbreak == 1: lastWordbreak = x - 4
- line2 = "%s..." % line2[:lastWordbreak]
+ # strips control characters to avoid screwing up the terminal
+ msg = "".join([char for char in msg if isprint(char)])
+
+ eventTime = time.localtime()
+ msgLine = "%02i:%02i:%02i [%s] %s" % (eventTime[3], eventTime[4], eventTime[5], type, msg)
+
+ if self.isPaused:
+ self.pauseBuffer.insert(0, (msgLine, color))
+ if len(self.pauseBuffer) > MAX_LOG_ENTRIES: del self.pauseBuffer[MAX_LOG_ENTRIES:]
+ else:
+ self.msgLog.insert(0, (msgLine, color))
+ if len(self.msgLog) > MAX_LOG_ENTRIES: del self.msgLog[MAX_LOG_ENTRIES:]
+ self.redraw()
- return (line1, line2)
+ def redraw(self):
+ """
+ Redraws message log. Entries stretch to use available space and may
+ contain up to two lines. Starts with newest entries.
+ """
+
+ if self.win:
+ if not self.lock.acquire(False): return
+ try:
+ self.clear()
+
+ # draws label - uses ellipsis if too long, for instance:
+ # Events (DEBUG, INFO, NOTICE, WARN...):
+ eventsLabel = "Events"
+ eventsListing = ", ".join(self.loggedEvents)
+
+ firstLabelLen = eventsListing.find(", ")
+ if firstLabelLen == -1: firstLabelLen = len(eventsListing)
+ else: firstLabelLen += 3
+
+ if self.maxX > 10 + firstLabelLen:
+ eventsLabel += " ("
+ if len(eventsListing) > self.maxX - 11:
+ labelBreak = eventsListing[:self.maxX - 12].rfind(", ")
+ eventsLabel += "%s..." % eventsListing[:labelBreak]
+ else: eventsLabel += eventsListing
+ eventsLabel += ")"
+ eventsLabel += ":"
+
+ self.addstr(0, 0, eventsLabel, util.LABEL_ATTR)
+
+ # log entries
+ lineCount = 1
+
+ for (line, color) in self.msgLog:
+ # splits over too lines if too long
+ if len(line) < self.maxX:
+ self.addstr(lineCount, 0, line, util.getColor(color))
+ lineCount += 1
+ else:
+ (line1, line2) = self._splitLine(line, self.maxX)
+ self.addstr(lineCount, 0, line1, util.getColor(color))
+ self.addstr(lineCount + 1, 0, line2, util.getColor(color))
+ lineCount += 2
+
+ if lineCount >= self.maxY: break # further log messages wouldn't fit
+ self.refresh()
+ finally:
+ self.lock.release()
+
+ def setPaused(self, isPause):
+ """
+ If true, prevents message log from being updated with new events.
+ """
+
+ if isPause == self.isPaused: return
+
+ self.isPaused = isPause
+ if self.isPaused: self.pauseBuffer = []
+ else:
+ self.msgLog = (self.pauseBuffer + self.msgLog)[:MAX_LOG_ENTRIES]
+ self.redraw()
+
+ def getHeartbeat(self):
+ """
+ Provides the number of seconds since the last BW event.
+ """
+
+ return time.time() - self.lastHeartbeat
+
+ # divides long message to cover two lines
+ def _splitLine(self, message, x):
+ # divides message into two lines, attempting to do it on a wordbreak
+ lastWordbreak = message[:x].rfind(" ")
+ if x - lastWordbreak < 10:
+ line1 = message[:lastWordbreak]
+ line2 = " %s" % message[lastWordbreak:].strip()
+ else:
+ # over ten characters until the last word - dividing
+ line1 = "%s-" % message[:x - 2]
+ line2 = " %s" % message[x - 2:].strip()
+
+ # ends line with ellipsis if too long
+ if len(line2) > x:
+ lastWordbreak = line2[:x - 4].rfind(" ")
+
+ # doesn't use wordbreak if it's a long word or the whole line is one
+ # word (picking up on two space indent to have index 1)
+ if x - lastWordbreak > 10 or lastWordbreak == 1: lastWordbreak = x - 4
+ line2 = "%s..." % line2[:lastWordbreak]
+
+ return (line1, line2)
+except ImportError:
+ pass # allows starter to import w/o TorCtl
Modified: arm/trunk/readme.txt
===================================================================
--- arm/trunk/readme.txt 2009-06-06 05:25:18 UTC (rev 19635)
+++ arm/trunk/readme.txt 2009-06-06 17:09:34 UTC (rev 19636)
@@ -9,10 +9,10 @@
Python 2.5
TorCtl - This needs to be in your Python path. In Linux this can be done via:
svn co https://tor-svn.freehaven.net/svn/torctl
- export PYTHONPATH=$PWD/trunk/python/
+ export PYTHONPATH=$PWD/torctl/trunk/python/
Tor is running with an available control port. This means either...
... starting Tor with '--controlport <PORT>'
... or including 'ControlPort <PORT>' in your torrc
-This is started via arm.py (use the '--help' argument for usage).
+This is started via 'arm' (use the '--help' argument for usage).
More information about the tor-commits
mailing list