commit e1b2e15dc56f6c3d0d6d032a893159e88e9a2d4f Author: Chris Wacek cwacek@cs.georgetown.edu Date: Wed Dec 12 23:12:06 2012 -0500
Rebuilt the Option class to be a little more usable from the web front-end --- app.py | 71 +++++++++++++++++++++++++++++------------------------------ compass.py | 58 ++++++++++++++++++++++++++++++++++++++----------- util.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 49 deletions(-)
diff --git a/app.py b/app.py index 3a66a79..67f4608 100644 --- a/app.py +++ b/app.py @@ -1,46 +1,45 @@ import os import re import compass -from flask import Flask, request, redirect, render_template, url_for +from util import Result,Boolean,NullFn,Int,Container +from flask import Flask, request, jsonify, render_template
app = Flask(__name__)
class Opt(object): - def __init__(self): - self.by_as = False - self.family = None - self.by_country = False - self.ases = None - self.country = None - self.top = -1 - self.short = None - self.links = None - self.guards_only = None - self.inactive = False - self.almost_fast_exits_only = None - self.exits_only = False - self.download = None - self.fast_exits_only = False - self.fast_exits_only_any_network = False - self.all_relays = False + request_types = { + 'by_as':Boolean, + 'by_country':Boolean, + 'inactive':Boolean, + 'exits_only':Boolean, + 'guards_only': Boolean, + 'links':Boolean, + 'sort':NullFn, + 'sort_reverse':Boolean, + 'top':Int, + 'family':NullFn, + 'ases':NullFn, + 'country':Container, + 'exit_filter':NullFn + }
-class Result(): - def __init__(self): - self.index = None - self.cw = None - self.adv_bw = None - self.p_guard = None - self.p_exit = None - self.p_middle = None - self.nick = None - self.fp = None - self.link = None - self.exit = None - self.guard = None - self.cc = None - self.as_no = None - self.as_name = None - self.as_info = None + @staticmethod + def convert(key,val): + return Opt.request_types[key](val) + + def __str__(self): + return repr(self) + + def __repr__(self): + return str(self.__dict__) + + def __init__(self,request): + + for key in Opt.request_types: + if key in request: + setattr(self,key,Opt.convert(key,request[key])) + else: + setattr(self,key,Opt.convert(key,None))
def parse(output_string, grouping=False, sort_key=None): results = [] diff --git a/compass.py b/compass.py index a62eb98..520a017 100755 --- a/compass.py +++ b/compass.py @@ -18,6 +18,7 @@ ALMOST_FAST_EXIT_PORTS = [80, 443] import json import operator import sys +import util import os from optparse import OptionParser, OptionGroup import urllib @@ -221,15 +222,16 @@ class RelayStats(object): filters.append(ExitFilter()) if options.guards_only: filters.append(GuardFilter()) - if options.fast_exits_only: + if options.exit_filter == 'all_relays': + pass + elif options.exit_filter == 'fast_exits_only': filters.append(SameNetworkFilter(FastExitFilter())) - if options.almost_fast_exits_only: - filters.append( - FastExitFilter(ALMOST_FAST_EXIT_BANDWIDTH_RATE, ALMOST_FAST_EXIT_ADVERTISED_BANDWIDTH, - ALMOST_FAST_EXIT_PORTS)) - filters.append( - InverseFilter(SameNetworkFilter(FastExitFilter()))) - if options.fast_exits_only_any_network: + elif options.exit_filter == 'almost_fast_exits_only': + filters.append(FastExitFilter(ALMOST_FAST_EXIT_BANDWIDTH_RATE, + ALMOST_FAST_EXIT_ADVERTISED_BANDWIDTH, + ALMOST_FAST_EXIT_PORTS)) + filters.append(InverseFilter(SameNetworkFilter(FastExitFilter()))) + elif options.exit_filter == 'fast_exits_only_any_network': filters.append(FastExitFilter()) return filters
@@ -364,6 +366,9 @@ def create_option_parser(): help="select family by fingerprint or nickname (for named relays)") group.add_option("-g", "--guards-only", action="store_true", help="select only relays suitable for guard position") + group.add_option("--exit-filter",type="choice", dest="exit_filter", + choices=["fast_exits_only","almost_fast_exits_only", + "all_relays","fast_exits_only_any_network"]) group.add_option("--fast-exits-only", action="store_true", help="select only fast exits (%d+ Mbit/s, %d+ KB/s, %s, %d- per /24)" % (FAST_EXIT_BANDWIDTH_RATE / (125 * 1024), @@ -404,6 +409,32 @@ def download_details_file(): url.close() details_file.close()
+def fix_exit_filter_options(options): + """ + Translate the old-style exit filter options into + the new format (as received on the front end). + """ + if options.exit_filter != "all_relays": + # We just accept this option's value + return options + + fast_exit_options = 0 + if options.fast_exits_only: + options.exit_filter = "fast_exits_only" + fast_exit_options += 1 + if options.almost_fast_exits_only: + options.exit_filter = "almost_fast_exits_only" + fast_exit_options += 1 + if options.fast_exits_only_any_network: + options.exit_filter = "fast_exits_only_any_network" + fast_exit_options += 1 + + if fast_exit_options > 1: + raise Exception + + return options + + if '__main__' == __name__: parser = create_option_parser() (options, args) = parser.parse_args() @@ -411,12 +442,12 @@ if '__main__' == __name__: parser.error("Did not understand positional argument(s), use options instead.") if options.family and not re.match(r'^[A-F0-9]{40}$', options.family) and not re.match(r'^[A-Za-z0-9]{1,19}$', options.family): parser.error("Not a valid fingerprint or nickname: %s" % options.family) - fast_exit_options = 0 - if options.fast_exits_only: fast_exit_options += 1 - if options.almost_fast_exits_only: fast_exit_options += 1 - if options.fast_exits_only_any_network: fast_exit_options += 1 - if fast_exit_options > 1: + + try: + fix_exit_filter_options(options) + except: parser.error("Can only filter by one fast-exit option.") + if options.download: download_details_file() print "Downloaded details.json. Re-run without --download option." @@ -430,6 +461,7 @@ if '__main__' == __name__: by_country=options.by_country, by_as_number=options.by_as, links=options.links) + output_string = stats.print_groups(sorted_groups, options.top, by_country=options.by_country, by_as_number=options.by_as, diff --git a/util.py b/util.py new file mode 100644 index 0000000..d5d041e --- /dev/null +++ b/util.py @@ -0,0 +1,59 @@ +import json + +def Container(val): + return json.loads(val) + +def NullFn(val): + return val + +def Int(val): + try: + return int(val) + except: + return None + +def Boolean(val): + if val == True: + return True + + if val in ("false", "False", "FALSE", "F"): + return False + if val in ("true", "True", "TRUE", "T"): + return True + + return False + +class Result(): + WEIGHT_FIELDS = { + 'consensus_weight_fraction': 'cw', + 'advertised_bandwidth_fraction': 'adv_bw', + 'guard_probability': 'p_guard', + 'middle_probability': 'p_middle', + 'exit_probability': 'p_exit', + } + + def __init__(self): + self.index = None + self.cw = None + self.adv_bw = None + self.p_guard = None + self.p_exit = None + self.p_middle = None + self.nick = None + self.fp = None + self.link = None + self.exit = None + self.guard = None + self.cc = None + self.as_no = None + self.as_name = None + self.as_info = None + + def __getitem__(self,prop): + getattr(self,prop) + + def __setitem__(self,prop,val): + setattr(self,prop,val) + + def jsonify(self): + return self.__dict__
tor-commits@lists.torproject.org