[tor-commits] [metrics-lib/master] Support parsing GetTor statistics files.

karsten at torproject.org karsten at torproject.org
Fri Jun 1 11:10:28 UTC 2012


commit a3d89ee7886a18f3bddc1efc66bf47e37c082d53
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Fri Jun 1 11:45:06 2012 +0200

    Support parsing GetTor statistics files.
---
 .../torproject/descriptor/GetTorStatistics.java    |   13 +++
 .../torproject/descriptor/impl/DescriptorImpl.java |    3 +
 .../descriptor/impl/GetTorStatisticsImpl.java      |   78 ++++++++++++++++++++
 .../descriptor/impl/NetworkStatusEntryImpl.java    |    2 +-
 .../torproject/descriptor/impl/ParseHelper.java    |   27 ++++++-
 .../impl/RelayNetworkStatusConsensusImpl.java      |    7 +-
 .../impl/RelayNetworkStatusVoteImpl.java           |    3 +-
 7 files changed, 126 insertions(+), 7 deletions(-)

diff --git a/src/org/torproject/descriptor/GetTorStatistics.java b/src/org/torproject/descriptor/GetTorStatistics.java
new file mode 100644
index 0000000..b6ba1e7
--- /dev/null
+++ b/src/org/torproject/descriptor/GetTorStatistics.java
@@ -0,0 +1,13 @@
+package org.torproject.descriptor;
+
+import java.util.SortedMap;
+
+public interface GetTorStatistics {
+
+  /* Return the date of these GetTor statistics in milliseconds since
+   * 1970-01-01 00:00:00. */
+  public long getDateMillis();
+
+  /* Return the number of downloaded packages. */
+  public SortedMap<String, Integer> getDownloadedPackages();
+}
diff --git a/src/org/torproject/descriptor/impl/DescriptorImpl.java b/src/org/torproject/descriptor/impl/DescriptorImpl.java
index c1c4a9a..98be2d8 100644
--- a/src/org/torproject/descriptor/impl/DescriptorImpl.java
+++ b/src/org/torproject/descriptor/impl/DescriptorImpl.java
@@ -88,6 +88,9 @@ public abstract class DescriptorImpl implements Descriptor {
     } else if (firstLines.startsWith("@type torperf 1.0\n")) {
       parsedDescriptors.addAll(TorperfResultImpl.parseTorperfResults(
           rawDescriptorBytes, failUnrecognizedDescriptorLines));
+    } else if (firstLines.startsWith("@type gettor 1.0\n")) {
+      parsedDescriptors.addAll(GetTorStatisticsImpl.parseGetTorStatistics(
+          rawDescriptorBytes, failUnrecognizedDescriptorLines));
     } else {
       throw new DescriptorParseException("Could not detect descriptor "
           + "type in descriptor starting with '" + firstLines + "'.");
diff --git a/src/org/torproject/descriptor/impl/GetTorStatisticsImpl.java b/src/org/torproject/descriptor/impl/GetTorStatisticsImpl.java
new file mode 100644
index 0000000..202cf03
--- /dev/null
+++ b/src/org/torproject/descriptor/impl/GetTorStatisticsImpl.java
@@ -0,0 +1,78 @@
+/* Copyright 2012 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.torproject.descriptor.Descriptor;
+import org.torproject.descriptor.GetTorStatistics;
+
+public class GetTorStatisticsImpl extends DescriptorImpl
+    implements GetTorStatistics {
+
+  public static List<Descriptor> parseGetTorStatistics(
+      byte[] rawDescriptorBytes, boolean failUnrecognizedDescriptorLines)
+      throws DescriptorParseException {
+    if (rawDescriptorBytes.length == 0) {
+      throw new DescriptorParseException("Descriptor is empty.");
+    }
+    List<Descriptor> parsedDescriptors = new ArrayList<Descriptor>();
+    String descriptorString = new String(rawDescriptorBytes);
+    Scanner s = new Scanner(descriptorString).useDelimiter("\n");
+    while (s.hasNext()) {
+      String line = s.next();
+      if (line.startsWith("@type gettor ")) {
+        String[] parts = line.split(" ");
+        if (parts.length != 3) {
+          throw new DescriptorParseException("Illegal line '" + line
+              + "'.");
+        }
+        String version = parts[2];
+        if (!version.startsWith("1.")) {
+          throw new DescriptorParseException("Unsupported version in "
+              + " line '" + line + "'.");
+        }
+      } else {
+        parsedDescriptors.add(new GetTorStatisticsImpl(line.getBytes(),
+            failUnrecognizedDescriptorLines));
+      }
+    }
+    return parsedDescriptors;
+  }
+
+  protected GetTorStatisticsImpl(byte[] rawDescriptorBytes,
+      boolean failUnrecognizedDescriptorLines)
+      throws DescriptorParseException {
+    super(rawDescriptorBytes, failUnrecognizedDescriptorLines, false);
+    this.parseGetTorStatisticsLine(new String(rawDescriptorBytes));
+  }
+
+  private void parseGetTorStatisticsLine(String line)
+      throws DescriptorParseException {
+    if (line.isEmpty()) {
+      throw new DescriptorParseException("Blank lines are not allowed.");
+    }
+    String[] parts = line.split(" ");
+    if (parts.length < 3) {
+      throw new DescriptorParseException("Illegal GetTor statistics line "
+          + "'" + line + "'.");
+    }
+    this.dateMillis = ParseHelper.parseDateAtIndex(line, parts, 0);
+    this.downloadedPackages = ParseHelper.parseKeyValuePairs(line, parts,
+        2, ":");
+  }
+
+  private long dateMillis;
+  public long getDateMillis() {
+    return this.dateMillis;
+  }
+
+  private SortedMap<String, Integer> downloadedPackages;
+  public SortedMap<String, Integer> getDownloadedPackages() {
+    return new TreeMap<String, Integer>(this.downloadedPackages);
+  }
+}
diff --git a/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java b/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
index 108d563..423e21e 100644
--- a/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
+++ b/src/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java
@@ -151,7 +151,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry {
       throws DescriptorParseException {
     this.parsedAtMostOnceKeyword("w");
     SortedMap<String, Integer> pairs = ParseHelper.parseKeyValuePairs(
-        line, parts, 1);
+        line, parts, 1, "=");
     if (pairs.isEmpty()) {
       throw new DescriptorParseException("Illegal line '" + line + "'.");
     }
diff --git a/src/org/torproject/descriptor/impl/ParseHelper.java b/src/org/torproject/descriptor/impl/ParseHelper.java
index a3f907d..61d1eb0 100644
--- a/src/org/torproject/descriptor/impl/ParseHelper.java
+++ b/src/org/torproject/descriptor/impl/ParseHelper.java
@@ -149,6 +149,28 @@ public class ParseHelper {
     return result;
   }
 
+  public static long parseDateAtIndex(String line, String[] parts,
+      int dateIndex) throws DescriptorParseException {
+    if (dateIndex >= parts.length) {
+      throw new DescriptorParseException("Line '" + line + "' does not "
+          + "contain a date at the expected position.");
+    }
+    long result = -1L;
+    try {
+      SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+      dateFormat.setLenient(false);
+      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+      result = dateFormat.parse(parts[dateIndex]).getTime();
+    } catch (ParseException e) {
+      /* Leave result at -1L. */
+    }
+    if (result < 0L || result / 1000L > (long) Integer.MAX_VALUE) {
+      throw new DescriptorParseException("Illegal date format in line '"
+          + line + "'.");
+    }
+    return result;
+  }
+
   private static Pattern twentyByteHexPattern =
       Pattern.compile("^[0-9a-fA-F]{40}$");
   public static String parseTwentyByteHexString(String line,
@@ -161,11 +183,12 @@ public class ParseHelper {
   }
 
   public static SortedMap<String, Integer> parseKeyValuePairs(String line,
-      String[] parts, int startIndex) throws DescriptorParseException {
+      String[] parts, int startIndex, String separatorString)
+      throws DescriptorParseException {
     SortedMap<String, Integer> result = new TreeMap<String, Integer>();
     for (int i = startIndex; i < parts.length; i++) {
       String pair = parts[i];
-      String[] pairParts = pair.split("=");
+      String[] pairParts = pair.split(separatorString);
       if (pairParts.length != 2) {
         throw new DescriptorParseException("Illegal key-value pair in "
             + "line '" + line + "'.");
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
index f296fa6..35cb316 100644
--- a/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
+++ b/src/org/torproject/descriptor/impl/RelayNetworkStatusConsensusImpl.java
@@ -257,13 +257,14 @@ public class RelayNetworkStatusConsensusImpl extends NetworkStatusImpl
 
   private void parseParamsLine(String line, String[] parts)
       throws DescriptorParseException {
-    this.consensusParams = ParseHelper.parseKeyValuePairs(line, parts, 1);
+    this.consensusParams = ParseHelper.parseKeyValuePairs(line, parts, 1,
+        "=");
   }
 
   private void parseBandwidthWeightsLine(String line, String[] parts)
       throws DescriptorParseException {
-    this.bandwidthWeights = ParseHelper.parseKeyValuePairs(line, parts,
-        1);
+    this.bandwidthWeights = ParseHelper.parseKeyValuePairs(line, parts, 1,
+        "=");
   }
 
   private String consensusDigest;
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
index d5b87c1..3695074 100644
--- a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
+++ b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
@@ -249,7 +249,8 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
 
   private void parseParamsLine(String line, String[] parts)
       throws DescriptorParseException {
-    this.consensusParams = ParseHelper.parseKeyValuePairs(line, parts, 1);
+    this.consensusParams = ParseHelper.parseKeyValuePairs(line, parts, 1,
+        "=");
   }
 
   private void parseDirSourceLine(String line, String[] parts)



More information about the tor-commits mailing list