Loading src/main/java/org/torproject/descriptor/NetworkStatusEntry.java +8 −1 Original line number Diff line number Diff line Loading @@ -132,6 +132,14 @@ public interface NetworkStatusEntry extends Serializable { */ SortedMap<String, SortedSet<Long>> getProtocols(); /** * Return the various statistics that an authority has computed for * this relay. Each stats is represented as a key + value. * * @since 2.20.0 */ SortedMap<String, Double> getStats(); /** * Return the bandwidth weight of this server or -1 if the status entry * didn't contain a bandwidth line. Loading Loading @@ -184,4 +192,3 @@ public interface NetworkStatusEntry extends Serializable { */ String getMasterKeyEd25519(); } src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java +0 −1 Original line number Diff line number Diff line Loading @@ -491,4 +491,3 @@ public interface RelayNetworkStatusVote extends Descriptor { */ String getDigestSha1Hex(); } src/main/java/org/torproject/descriptor/impl/Key.java +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ public enum Key { SNOWFLAKE_IPS_TOTAL("snowflake-ips-total"), SNOWFLAKE_IPS_WEBEXT("snowflake-ips-webext"), SNOWFLAKE_STATS_END("snowflake-stats-end"), STATS("stats"), TRANSPORT("transport"), TUNNELLED_DIR_SERVER("tunnelled-dir-server"), UPTIME("uptime"), Loading src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java +35 −2 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { } private Set<Key> atMostOnceKeys = EnumSet.of( Key.S, Key.V, Key.PR, Key.W, Key.P); Key.S, Key.V, Key.PR, Key.W, Key.P, Key.STATS); private void parsedAtMostOnceKey(Key key) throws DescriptorParseException { Loading Loading @@ -122,6 +122,9 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { case ID: this.parseIdLine(line, parts); break; case STATS: this.parseStatsLine(line, parts); break; default: if (this.unrecognizedLines == null) { this.unrecognizedLines = new ArrayList<>(); Loading Loading @@ -197,12 +200,36 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { } } /** * In the following methods `line` is passed twice in the function call * parseProtocolVersions(line, lineNoOpt, partsNoOpt) and * parseStats(line, lineNoOpt, partsNoOpt) * This is because line and lineNoOpt may represent slightly different * versions of the same string. * * <p>The line argument is the original string that the function is parsing, * while the lineNoOpt argument is a modified version of line that has any * optional parts removed. * The function checks whether an entry for the lineNoOpt key already exists * in the parsed map before parsing the line. * If an entry exists, the function immediately returns the * corresponding SortedMap without re-parsing the line. * By passing both line and lineNoOpt to the function, the caller ensures that * the function can distinguish between different versions of the same string * and correctly handle cases where the same line is parsed multiple times. */ private void parsePrLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.PR); this.protocols = ParseHelper.parseProtocolVersions(line, line, parts); } private void parseStatsLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.STATS); this.stats = ParseHelper.parseStats(line, line, parts); } private void parseWLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.W); Loading Loading @@ -376,6 +403,13 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { return this.protocols; } private SortedMap<String, Double> stats; @Override public SortedMap<String, Double> getStats() { return this.stats; } private long bandwidth = -1L; @Override Loading Loading @@ -418,4 +452,3 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { return this.masterKeyEd25519; } } src/main/java/org/torproject/descriptor/impl/ParseHelper.java +23 −1 Original line number Diff line number Diff line Loading @@ -537,5 +537,27 @@ public class ParseHelper { } return parsedProtocolVersions.get(lineNoOpt); } private static Map<String, SortedMap<String, Double>> parsedStats = new HashMap<>(); protected static SortedMap<String, Double> parseStats( String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { if (!parsedProtocolVersions.containsKey(lineNoOpt)) { SortedMap<String, Double> parsed = new TreeMap<>(); try { for (int i = 1; i < partsNoOpt.length; i++) { String[] part = partsNoOpt[i].split("="); Double stats = Double.parseDouble(part[1]); parsed.put(part[0], stats); } } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { throw new DescriptorParseException("Invalid line '" + line + "'.", e); } parsedStats.put(lineNoOpt, Collections.unmodifiableSortedMap(parsed)); } return parsedStats.get(lineNoOpt); } } Loading
src/main/java/org/torproject/descriptor/NetworkStatusEntry.java +8 −1 Original line number Diff line number Diff line Loading @@ -132,6 +132,14 @@ public interface NetworkStatusEntry extends Serializable { */ SortedMap<String, SortedSet<Long>> getProtocols(); /** * Return the various statistics that an authority has computed for * this relay. Each stats is represented as a key + value. * * @since 2.20.0 */ SortedMap<String, Double> getStats(); /** * Return the bandwidth weight of this server or -1 if the status entry * didn't contain a bandwidth line. Loading Loading @@ -184,4 +192,3 @@ public interface NetworkStatusEntry extends Serializable { */ String getMasterKeyEd25519(); }
src/main/java/org/torproject/descriptor/RelayNetworkStatusVote.java +0 −1 Original line number Diff line number Diff line Loading @@ -491,4 +491,3 @@ public interface RelayNetworkStatusVote extends Descriptor { */ String getDigestSha1Hex(); }
src/main/java/org/torproject/descriptor/impl/Key.java +1 −0 Original line number Diff line number Diff line Loading @@ -176,6 +176,7 @@ public enum Key { SNOWFLAKE_IPS_TOTAL("snowflake-ips-total"), SNOWFLAKE_IPS_WEBEXT("snowflake-ips-webext"), SNOWFLAKE_STATS_END("snowflake-stats-end"), STATS("stats"), TRANSPORT("transport"), TUNNELLED_DIR_SERVER("tunnelled-dir-server"), UPTIME("uptime"), Loading
src/main/java/org/torproject/descriptor/impl/NetworkStatusEntryImpl.java +35 −2 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { } private Set<Key> atMostOnceKeys = EnumSet.of( Key.S, Key.V, Key.PR, Key.W, Key.P); Key.S, Key.V, Key.PR, Key.W, Key.P, Key.STATS); private void parsedAtMostOnceKey(Key key) throws DescriptorParseException { Loading Loading @@ -122,6 +122,9 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { case ID: this.parseIdLine(line, parts); break; case STATS: this.parseStatsLine(line, parts); break; default: if (this.unrecognizedLines == null) { this.unrecognizedLines = new ArrayList<>(); Loading Loading @@ -197,12 +200,36 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { } } /** * In the following methods `line` is passed twice in the function call * parseProtocolVersions(line, lineNoOpt, partsNoOpt) and * parseStats(line, lineNoOpt, partsNoOpt) * This is because line and lineNoOpt may represent slightly different * versions of the same string. * * <p>The line argument is the original string that the function is parsing, * while the lineNoOpt argument is a modified version of line that has any * optional parts removed. * The function checks whether an entry for the lineNoOpt key already exists * in the parsed map before parsing the line. * If an entry exists, the function immediately returns the * corresponding SortedMap without re-parsing the line. * By passing both line and lineNoOpt to the function, the caller ensures that * the function can distinguish between different versions of the same string * and correctly handle cases where the same line is parsed multiple times. */ private void parsePrLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.PR); this.protocols = ParseHelper.parseProtocolVersions(line, line, parts); } private void parseStatsLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.STATS); this.stats = ParseHelper.parseStats(line, line, parts); } private void parseWLine(String line, String[] parts) throws DescriptorParseException { this.parsedAtMostOnceKey(Key.W); Loading Loading @@ -376,6 +403,13 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { return this.protocols; } private SortedMap<String, Double> stats; @Override public SortedMap<String, Double> getStats() { return this.stats; } private long bandwidth = -1L; @Override Loading Loading @@ -418,4 +452,3 @@ public class NetworkStatusEntryImpl implements NetworkStatusEntry { return this.masterKeyEd25519; } }
src/main/java/org/torproject/descriptor/impl/ParseHelper.java +23 −1 Original line number Diff line number Diff line Loading @@ -537,5 +537,27 @@ public class ParseHelper { } return parsedProtocolVersions.get(lineNoOpt); } private static Map<String, SortedMap<String, Double>> parsedStats = new HashMap<>(); protected static SortedMap<String, Double> parseStats( String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { if (!parsedProtocolVersions.containsKey(lineNoOpt)) { SortedMap<String, Double> parsed = new TreeMap<>(); try { for (int i = 1; i < partsNoOpt.length; i++) { String[] part = partsNoOpt[i].split("="); Double stats = Double.parseDouble(part[1]); parsed.put(part[0], stats); } } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { throw new DescriptorParseException("Invalid line '" + line + "'.", e); } parsedStats.put(lineNoOpt, Collections.unmodifiableSortedMap(parsed)); } return parsedStats.get(lineNoOpt); } }