[tor-commits] [metrics-web/master] Turn home page into table of metrics.

karsten at torproject.org karsten at torproject.org
Tue Mar 17 22:03:56 UTC 2015


commit a364fca14475272be7b9572f900fe3fb8264521d
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Mon Mar 16 16:46:10 2015 +0100

    Turn home page into table of metrics.
---
 .../org/torproject/metrics/web/IndexServlet.java   |  326 +++++++++++++++++++-
 website/web/WEB-INF/index.jsp                      |  133 ++++----
 2 files changed, 384 insertions(+), 75 deletions(-)

diff --git a/website/src/org/torproject/metrics/web/IndexServlet.java b/website/src/org/torproject/metrics/web/IndexServlet.java
index c42b0e9..7b2c91c 100644
--- a/website/src/org/torproject/metrics/web/IndexServlet.java
+++ b/website/src/org/torproject/metrics/web/IndexServlet.java
@@ -1,24 +1,340 @@
-/* Copyright 2011, 2012 The Tor Project
+/* Copyright 2011--2015 The Tor Project
  * See LICENSE for licensing information */
 package org.torproject.metrics.web;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+ at SuppressWarnings("serial")
 public class IndexServlet extends HttpServlet {
 
-  private static final long serialVersionUID = 7871368999788994664L;
+  private static final String[][] knownTags = new String[][] {
+    { "cl", "Clients" },
+    { "rl", "Relays" },
+    { "br", "Bridges" },
+    { "pt", "Pluggable transports" },
+    { "hs", "Hidden services" },
+    { "bw", "Bandwidth" },
+    { "pf", "Performance" },
+    { "dv", "Diversity" }
+  };
+  private static final String[] defaultTags =
+      new String[] { "cl", "rl", "br", "pt", "hs", "bw", "pf", "dv" };
+
+  private static final String[][] knownTypes = new String[][] {
+    { "gr", "Graph" },
+    { "tb", "Table" },
+    { "ln", "Link" },
+    { "dt", "Data" }
+  };
+  private static final String[] defaultTypes =
+      new String[] { "gr", "tb", "ln", "dt" };
+
+  private static final String[][] knownLevels = new String[][] {
+    { "bs", "Basic" },
+    { "ad", "Advanced" }
+  };
+  private static final String[] defaultLevels = new String[] { "bs" };
+
+  private static final String[][] knownOrders = new String[][] {
+    { "name", "Name" },
+    { "tags", "Tags" },
+    { "type", "Type" },
+    { "level", "Level" },
+    { "shuffle", "None (shuffle)" }
+  };
+  private static final String[] defaultOrders = new String[] { "type" };
+
+  private final static List<Metric> availableMetrics;
+  static {
+    availableMetrics = new ArrayList<Metric>();
+    availableMetrics.add(new Metric("networksize.html",
+        "Relays and bridges in the network",
+        new String[] { "Relays", "Bridges" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("relayflags.html",
+        "Relays with Exit, Fast, Guard, Stable, and HSDir flags",
+        new String[] { "Relays" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("versions.html",
+        "Relays by version", new String[] { "Relays", "Diversity" },
+        "Graph", "Basic"));
+    availableMetrics.add(new Metric("platforms.html",
+        "Relays by platform", new String[] { "Relays", "Diversity" },
+        "Graph", "Basic"));
+    availableMetrics.add(new Metric("cloudbridges.html",
+        "Tor Cloud bridges", new String[] { "Bridges" }, "Graph",
+        "Basic"));
+    availableMetrics.add(new Metric("servers-data.html",
+        "Number of relays and bridges",
+        new String[] { "Relays", "Bridges", "Diversity" }, "Data",
+        "Advanced"));
+    availableMetrics.add(new Metric("bandwidth.html",
+        "Total relay bandwidth in the network",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("bwhist-flags.html",
+        "Relay bandwidth by Exit and/or Guard flags",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("bandwidth-flags.html",
+        "Advertised bandwidth and bandwidth history by relay flags",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("dirbytes.html",
+        "Number of bytes spent on answering directory requests",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("advbwdist-perc.html",
+        "Advertised bandwidth distribution",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("advbwdist-relay.html",
+        "Advertised bandwidth of n-th fastest relays",
+        new String[] { "Relays", "Bandwidth" }, "Graph", "Basic"));
+    availableMetrics.add(new Metric("bandwidth-data.html",
+        "Bandwidth provided and consumed by relays",
+        new String[] { "Relays", "Bandwidth" }, "Data", "Advanced"));
+    availableMetrics.add(new Metric("advbwdist-data.html",
+        "Advertised bandwidth distribution and n-th fastest relays",
+        new String[] { "Relays", "Bandwidth" }, "Data", "Advanced"));
+    availableMetrics.add(new Metric("bubbles.html",
+        "Network bubble graphs", new String[] { "Relays", "Diversity" },
+        "Graph", "Basic"));
+    availableMetrics.add(new Metric("userstats-relay-country.html",
+        "Direct users by country", new String[] { "Clients" }, "Graph",
+        "Basic"));
+    availableMetrics.add(new Metric("userstats-relay-table.html",
+        "Top-10 countries by directly connecting users",
+        new String[] { "Clients" }, "Table", "Basic"));
+    availableMetrics.add(new Metric("userstats-censorship-events.html",
+        "Top-10 countries by possible censorship events",
+        new String[] { "Clients" }, "Table", "Basic"));
+    availableMetrics.add(new Metric("userstats-bridge-country.html",
+        "Bridge users by country", new String[] { "Clients" }, "Graph",
+        "Basic"));
+    availableMetrics.add(new Metric("userstats-bridge-table.html",
+        "Top-10 countries by bridge users", new String[] { "Clients" },
+        "Table", "Basic"));
+    availableMetrics.add(new Metric("userstats-bridge-transport.html",
+        "Bridge users by transport",
+        new String[] { "Clients", "Pluggable transports" }, "Graph",
+        "Basic"));
+    availableMetrics.add(new Metric("userstats-bridge-version.html",
+        "Bridge users by IP version", new String[] { "Clients" }, "Graph",
+        "Basic"));
+    availableMetrics.add(new Metric("oxford-anonymous-internet.html",
+        "Tor users as percentage of larger Internet population",
+        new String[] { "Clients" }, "Link", "Basic"));
+    availableMetrics.add(new Metric("clients-data.html",
+        "Estimated number of clients in the Tor network",
+        new String[] { "Clients", "Pluggable transports" }, "Data",
+        "Advanced"));
+    availableMetrics.add(new Metric("torperf.html",
+        "Time to download files over Tor", new String[] { "Performance" },
+        "Graph", "Basic"));
+    availableMetrics.add(new Metric("torperf-failures.html",
+        "Timeouts and failures of downloading files over Tor",
+        new String[] { "Performance" }, "Graph", "Advanced"));
+    availableMetrics.add(new Metric("connbidirect.html",
+        "Fraction of connections used uni-/bidirectionally",
+        new String[] { "Performance" }, "Graph", "Advanced"));
+    availableMetrics.add(new Metric("torperf-data.html",
+        "Performance of downloading static files over Tor",
+        new String[] { "Performance" }, "Data", "Advanced"));
+    availableMetrics.add(new Metric("connbidirect-data.html",
+        "Fraction of connections used uni-/bidirectionally",
+        new String[] { "Performance" }, "Data", "Advanced"));
+    availableMetrics.add(new Metric("hidserv-dir-onions-seen.html",
+        "Unique .onion addresses", new String[] { "Hidden services" },
+        "Graph", "Basic"));
+    availableMetrics.add(new Metric("hidserv-data.html",
+        "Hidden-service statistics", new String[] { "Hidden services" },
+        "Data", "Advanced"));
+  }
 
   public void doGet(HttpServletRequest request,
       HttpServletResponse response) throws IOException, ServletException {
-
-    /* Forward the request to the JSP that does all the hard work. */
+    @SuppressWarnings("rawtypes")
+    Map parameterMap = request.getParameterMap();
+    BitSet requestedTags = this.parseParameter(
+        (String[]) parameterMap.get("tag"), knownTags, defaultTags);
+    BitSet requestedTypes = this.parseParameter(
+        (String[]) parameterMap.get("type"), knownTypes, defaultTypes);
+    BitSet requestedLevels = this.parseParameter(
+        (String[]) parameterMap.get("level"), knownLevels, defaultLevels);
+    BitSet requestedOrder = this.parseParameter(
+        (String[]) parameterMap.get("order"), knownOrders, defaultOrders);
+    request.setAttribute("tags", this.formatParameter(knownTags,
+        requestedTags));
+    request.setAttribute("types", this.formatParameter(knownTypes,
+        requestedTypes));
+    request.setAttribute("levels", this.formatParameter(knownLevels,
+        requestedLevels));
+    request.setAttribute("order", this.formatParameter(knownOrders,
+        requestedOrder));
+    List<Metric> filteredAndOrderedMetrics = this.filterMetrics(
+        requestedTags, requestedTypes, requestedLevels);
+    this.orderMetrics(filteredAndOrderedMetrics, requestedOrder);
+    request.setAttribute("results", this.formatMetrics(
+        filteredAndOrderedMetrics));
     request.getRequestDispatcher("WEB-INF/index.jsp").forward(request,
         response);
   }
-}
 
+  private BitSet parseParameter(String[] unparsedValues,
+      String[][] knownValues, String[] defaultValues) {
+    BitSet result = new BitSet();
+    if (unparsedValues == null || unparsedValues.length == 0 ||
+        unparsedValues.length > knownValues.length) {
+      unparsedValues = defaultValues;
+    }
+    Set<String> requestedValues =
+        new HashSet<String>(Arrays.asList(unparsedValues));
+    for (int i = 0; i < knownValues.length; i++) {
+      if (requestedValues.contains(knownValues[i][0])) {
+        result.set(i);
+      }
+    }
+    return result;
+  }
+
+  private String[][] formatParameter(String[][] strings, BitSet bitSet) {
+    String[][] formattedParameter = new String[strings.length][];
+    for (int i = 0; i < formattedParameter.length; i++) {
+      String[] formatted = new String[] { strings[i][0], strings[i][1],
+          "" };
+      if (bitSet.get(i)) {
+        formatted[2] = " checked";
+      }
+      formattedParameter[i] = formatted;
+    }
+    return formattedParameter;
+  }
+
+  private static class Metric {
+    private String url;
+    private String name;
+    private BitSet tags;
+    private BitSet type;
+    private BitSet level;
+    private Metric(String url, String name, String[] tagStrings,
+        String typeString, String levelString) {
+      this.url = url;
+      this.name = name;
+      this.tags = this.convertStringsToBitSet(knownTags, tagStrings);
+      this.type = this.convertStringToBitSet(knownTypes, typeString);
+      this.level = this.convertStringToBitSet(knownLevels, levelString);
+    }
+    private BitSet convertStringsToBitSet(String[][] knownKeysAndValues,
+        String[] givenKeyStrings) {
+      BitSet result = new BitSet(knownKeysAndValues.length);
+      Set<String> keys = new HashSet<String>(Arrays.asList(
+          givenKeyStrings));
+      for (int i = 0; i < knownKeysAndValues.length; i++) {
+        if (keys.contains(knownKeysAndValues[i][1])) {
+          result.set(i);
+        }
+      }
+      if (result.cardinality() != givenKeyStrings.length) {
+        throw new RuntimeException("Unknown key(s): " + keys);
+      }
+      return result;
+    }
+    private BitSet convertStringToBitSet(String[][] knownKeysAndValues,
+        String givenKeyString) {
+      return this.convertStringsToBitSet(knownKeysAndValues,
+          new String[] { givenKeyString });
+    }
+    private String[] toStrings() {
+      return new String[] { this.url, this.name,
+          this.convertBitSetToString(knownTags, this.tags),
+          this.convertBitSetToString(knownTypes, this.type),
+          this.convertBitSetToString(knownLevels, this.level) };
+    }
+    private String convertBitSetToString(String[][] knownKeysAndValues,
+        BitSet bitSet) {
+      StringBuilder sb = new StringBuilder();
+      int i = -1;
+      while ((i = bitSet.nextSetBit(i + 1)) >= 0) {
+        sb.append(", " + knownKeysAndValues[i][1]);
+      }
+      return sb.substring(Math.min(sb.length(), 2));
+    }
+  }
+
+  private List<Metric> filterMetrics(BitSet requestedTags,
+      BitSet requestedTypes, BitSet requestedLevels) {
+    List<Metric> filteredMetrics = new ArrayList<Metric>();
+    for (Metric metric : availableMetrics) {
+      if (requestedTags.intersects(metric.tags) &&
+          requestedTypes.intersects(metric.type) &&
+          requestedLevels.intersects(metric.level)) {
+        filteredMetrics.add(metric);
+      }
+    }
+    return filteredMetrics;
+  }
+
+  private void orderMetrics(List<Metric> resultMetrics,
+      BitSet requestedOrder) {
+    switch (requestedOrder.nextSetBit(0)) {
+    case 0:
+      Collections.sort(resultMetrics, new Comparator<Metric>() {
+        public int compare(Metric a, Metric b) {
+          return a.name.compareTo(b.name);
+        }
+      });
+      break;
+    case 1:
+      Collections.sort(resultMetrics, new Comparator<Metric>() {
+        public int compare(Metric a, Metric b) {
+          return compareTwoBitSets(a.tags, b.tags);
+        }
+      });
+      break;
+    case 2:
+      Collections.sort(resultMetrics, new Comparator<Metric>() {
+        public int compare(Metric a, Metric b) {
+          return compareTwoBitSets(a.type, b.type);
+        }
+      });
+      break;
+    case 3:
+      Collections.sort(resultMetrics, new Comparator<Metric>() {
+        public int compare(Metric a, Metric b) {
+          return compareTwoBitSets(a.level, b.level);
+        }
+      });
+      break;
+    default:
+      Collections.shuffle(resultMetrics);
+      break;
+    }
+  }
+
+  private int compareTwoBitSets(BitSet a, BitSet b) {
+    if (a.equals(b)) {
+      return 0;
+    }
+    BitSet xor = (BitSet) a.clone();
+    xor.xor(b);
+    return xor.length() == b.length() ? -1 : 1;
+  }
+
+  private String[][] formatMetrics(
+      List<Metric> filteredAndOrderedMetrics) {
+    String[][] formattedMetrics =
+        new String[filteredAndOrderedMetrics.size()][];
+    for (int i = 0; i < formattedMetrics.length; i++) {
+      formattedMetrics[i] = filteredAndOrderedMetrics.get(i).toStrings();
+    }
+    return formattedMetrics;
+  }
+}
diff --git a/website/web/WEB-INF/index.jsp b/website/web/WEB-INF/index.jsp
index 182935b..9ea7e00 100644
--- a/website/web/WEB-INF/index.jsp
+++ b/website/web/WEB-INF/index.jsp
@@ -1,3 +1,5 @@
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 <html>
 <head>
@@ -21,77 +23,68 @@
         <a href="https://www.torproject.org/about/contact.html.en">let us
         know</a>.</small></p>
 
-        <h3>Servers</h3>
-        <p>How many relays and bridges are in the network?
-        How many of them permit exiting?</p>
-<ul>
-<li><a href="networksize.html">Graph: Relays and bridges in the network</a></li>
-<li><a href="relayflags.html">Graph: Relays with Exit, Fast, Guard, Stable, and HSDir flags</a></li>
-<li><a href="versions.html">Graph: Relays by version</a></li>
-<li><a href="platforms.html">Graph: Relays by platform</a></li>
-<li><a href="cloudbridges.html">Graph: Tor Cloud bridges</a></li>
-<li><a href="servers-data.html">Data: Number of relays and bridges</a></li>
-</ul>
+<div>
+<div style="border:1px solid gray;border-radius:10px;padding:10px;float:left;overflow:hidden;margin-right:20px;">
+<form action="/">
+<p>
+<label for="tag"><b>Tags</b></label><br>
+<c:forEach var="row" items="${tags}">
+<input name="tag" type="checkbox" value="${row[0]}" <c:if test="${fn:length(row[2]) > 0}"> checked</c:if>> ${row[1]}</br>
+</c:forEach>
+</p>
+<p>
+<label for="type"><b>Type</b></label></br>
+<c:forEach var="row" items="${types}">
+<input name="type" type="checkbox" value="${row[0]}" <c:if test="${fn:length(row[2]) > 0}"> checked</c:if>> ${row[1]}</br>
+</c:forEach>
+</p>
+<p>
+<label for="level"><b>Level</b></label></br>
+<c:forEach var="row" items="${levels}">
+<input name="level" type="checkbox" value="${row[0]}" <c:if test="${fn:length(row[2]) > 0}"> checked</c:if>> ${row[1]}</br>
+</c:forEach>
+</p>
+<p>
+<label for="sort"><b>Order</b></label></br>
+<c:forEach var="row" items="${order}">
+<input name="order" type="radio" value="${row[0]}" <c:if test="${fn:length(row[2]) > 0}"> checked</c:if>> ${row[1]}</br>
+</c:forEach>
+</p>
+<p>
+<input type="reset" value="Reset">
+<input type="submit" value="Update">
+</p>
+</form>
+</div>
 
-        <h3>Bandwidth</h3>
-        <p>How much bandwidth do relays advertise?
-        And how much of that is actually consumed?</p>
-
-<ul>
-<li><a href="bandwidth.html">Graph: Total relay bandwidth in the network</a></li>
-<li><a href="bwhist-flags.html">Graph: Relay bandwidth by Exit and/or Guard flags</a></li>
-<li><a href="bandwidth-flags.html">Graph: Advertised bandwidth and bandwidth history by relay flags</a></li>
-<li><a href="dirbytes.html">Graph: Number of bytes spent on answering directory requests</a></li>
-<li><a href="advbwdist-perc.html">Graph: Advertised bandwidth distribution</a></li>
-<li><a href="advbwdist-relay.html">Graph: Advertised bandwidth of n-th fastest relays</a></li>
-<li><a href="bandwidth-data.html">Data: Bandwidth provided and consumed by relays</a></li>
-<li><a href="advbwdist-data.html">Data: Advertised bandwidth distribution and n-th fastest relays</a></li>
-</ul>
-
-        <h3>Diversity</h3>
-        <p>How diverse is the network?
-        In which countries are relays located?</p>
-
-<ul>
-<li><a href="bubbles.html">Graph: Network bubble graphs</a></li>
-</ul>
-
-        <h3>Users</h3>
-        <p>Where do users come from?
-        What transports and IP versions are they using?</p>
-
-<ul>
-<li><a href="userstats-relay-country.html">Graph: Direct users by country</a></li>
-<li><a href="userstats-relay-table.html">Table: Top-10 countries by directly connecting users</a></li>
-<li><a href="userstats-censorship-events.html">Table: Top-10 countries by possible censorship events</a></li>
-<li><a href="userstats-bridge-country.html">Graph: Bridge users by country</a></li>
-<li><a href="userstats-bridge-table.html">Table: Top-10 countries by bridge users</a></li>
-<li><a href="userstats-bridge-transport.html">Graph: Bridge users by transport</a></li>
-<li><a href="userstats-bridge-version.html">Graph: Bridge users by IP version</a></li>
-<li><a href="oxford-anonymous-internet.html">Link: Tor users as percentage of larger Internet population</a></li>
-<li><a href="clients-data.html">Data: Estimated number of clients in the Tor network</a></li>
-</ul>
-
-        <h3>Performance</h3>
-        <p>How long does it take to download a megabyte of data over Tor?
-        How about five?</p>
-
-<ul>
-<li><a href="torperf.html">Graph: Time to download files over Tor</a></li>
-<li><a href="torperf-failures.html">Graph: Timeouts and failures of downloading files over Tor</a></li>
-<li><a href="connbidirect.html">Graph: Fraction of connections used uni-/bidirectionally</a></li>
-<li><a href="torperf-data.html">Data: Performance of downloading static files over Tor</a></li>
-<li><a href="connbidirect-data.html">Data: Fraction of connections used uni-/bidirectionally</a></li>
-</ul>
-
-        <h3>Hidden services</h3>
-        <p>How many hidden services are there in the network, and how much
-        traffic do they handle?</p>
-
-<ul>
-<li><a href="hidserv-dir-onions-seen.html">Graph: Unique .onion addresses</a></li>
-<li><a href="hidserv-data.html">Data: Hidden-service statistics</a></li>
-</ul>
+<div style="overflow:hidden;">
+<style>
+table {
+  border-spacing: 10px;
+}
+</style>
+<table>
+<thead>
+<tr>
+<th>Name</th>
+<th>Tags</th>
+<th>Type</th>
+<th>Level</th>
+</tr>
+</thead>
+<tbody>
+<c:forEach var="row" items="${results}">
+<tr>
+<td><a href="${row[0]}">${row[1]}</a></td>
+<td>${row[2]}</td>
+<td>${row[3]}</td>
+<td>${row[4]}</td>
+</tr>
+</c:forEach>
+</tbody>
+</table>
+</div>
+</div>
 
     </div>
   </div>





More information about the tor-commits mailing list