- Refactor tracker map

This commit is contained in:
zzz
2012-05-22 18:19:52 +00:00
parent 10872f751e
commit 0f321f1597
5 changed files with 107 additions and 59 deletions

View File

@ -8,6 +8,7 @@ import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
@ -18,7 +19,6 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -58,7 +58,7 @@ public class SnarkManager implements Snark.CompleteListener {
private ConnectionAcceptor _connectionAcceptor; private ConnectionAcceptor _connectionAcceptor;
private Thread _monitor; private Thread _monitor;
private volatile boolean _running; private volatile boolean _running;
private final Map<String, String> _trackerMap; private final Map<String, Tracker> _trackerMap;
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
@ -130,7 +130,7 @@ public class SnarkManager implements Snark.CompleteListener {
_configFile = new File(CONFIG_FILE); _configFile = new File(CONFIG_FILE);
if (!_configFile.isAbsolute()) if (!_configFile.isAbsolute())
_configFile = new File(_context.getConfigDir(), CONFIG_FILE); _configFile = new File(_context.getConfigDir(), CONFIG_FILE);
_trackerMap = Collections.synchronizedMap(new TreeMap(new IgnoreCaseComparator())); _trackerMap = new ConcurrentHashMap(4);
loadConfig(null); loadConfig(null);
} }
@ -1404,40 +1404,67 @@ public class SnarkManager implements Snark.CompleteListener {
} }
/** /**
* Sorted map of name to announceURL=baseURL * Unsorted map of name to Tracker object
* Modifiable, not a copy * Modifiable, not a copy
* @since 0.9.1
*/ */
public Map<String, String> getTrackers() { public Map<String, Tracker> getTrackerMap() {
return _trackerMap; return _trackerMap;
} }
/**
* Unsorted, do not modify
*/
public Collection<Tracker> getTrackers() {
return _trackerMap.values();
}
/**
* Sorted copy
* @since 0.9.1
*/
public List<Tracker> getSortedTrackers() {
List<Tracker> rv = new ArrayList(_trackerMap.values());
Collections.sort(rv, new IgnoreCaseComparator());
return rv;
}
/** @since 0.9 */ /** @since 0.9 */
private void initTrackerMap() { private void initTrackerMap() {
String trackers = _config.getProperty(PROP_TRACKERS); String trackers = _config.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) ) if ( (trackers == null) || (trackers.trim().length() <= 0) )
trackers = _context.getProperty(PROP_TRACKERS); trackers = _context.getProperty(PROP_TRACKERS);
_trackerMap.clear();
if ( (trackers == null) || (trackers.trim().length() <= 0) ) { if ( (trackers == null) || (trackers.trim().length() <= 0) ) {
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) setDefaultTrackerMap(true);
_trackerMap.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]);
} else { } else {
String[] toks = trackers.split(","); String[] toks = trackers.split(",");
for (int i = 0; i < toks.length; i += 2) { for (int i = 0; i < toks.length; i += 2) {
String name = toks[i].trim().replace("&#44;", ","); String name = toks[i].trim().replace("&#44;", ",");
String url = toks[i+1].trim().replace("&#44;", ","); String url = toks[i+1].trim().replace("&#44;", ",");
if ( (name.length() > 0) && (url.length() > 0) ) if ( (name.length() > 0) && (url.length() > 0) ) {
_trackerMap.put(name, url); String urls[] = DEFAULT_TRACKERS[i+1].split("=", 2);
String url2 = urls.length > 1 ? urls[1] : null;
_trackerMap.put(name, new Tracker(name, urls[0], url2));
}
} }
} }
} }
/** @since 0.9 */ /** @since 0.9 */
public void setDefaultTrackerMap() { public void setDefaultTrackerMap() {
setDefaultTrackerMap(true);
}
/** @since 0.9.1 */
private void setDefaultTrackerMap(boolean save) {
_trackerMap.clear(); _trackerMap.clear();
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) { for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) {
_trackerMap.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); String name = DEFAULT_TRACKERS[i];
String urls[] = DEFAULT_TRACKERS[i+1].split("=", 2);
String url2 = urls.length > 1 ? urls[1] : null;
_trackerMap.put(name, new Tracker(name, urls[0], url2));
} }
if (_config.remove(PROP_TRACKERS) != null) { if (save && _config.remove(PROP_TRACKERS) != null) {
saveConfig(); saveConfig();
} }
} }
@ -1446,12 +1473,15 @@ public class SnarkManager implements Snark.CompleteListener {
public void saveTrackerMap() { public void saveTrackerMap() {
StringBuilder buf = new StringBuilder(2048); StringBuilder buf = new StringBuilder(2048);
boolean comma = false; boolean comma = false;
for (Map.Entry<String, String> e : _trackerMap.entrySet()) { for (Map.Entry<String, Tracker> e : _trackerMap.entrySet()) {
if (comma) if (comma)
buf.append(','); buf.append(',');
else else
comma = true; comma = true;
buf.append(e.getKey().replace(",", "&#44;")).append(',').append(e.getValue().replace(",", "&#44;")); Tracker t = e.getValue();
buf.append(e.getKey().replace(",", "&#44;")).append(',').append(t.announceURL.replace(",", "&#44;"));
if (t.baseURL != null)
buf.append('=').append(t.baseURL);
} }
_config.setProperty(PROP_TRACKERS, buf.toString()); _config.setProperty(PROP_TRACKERS, buf.toString());
saveConfig(); saveConfig();
@ -1481,9 +1511,9 @@ public class SnarkManager implements Snark.CompleteListener {
* ignore case, current locale * ignore case, current locale
* @since 0.9 * @since 0.9
*/ */
private static class IgnoreCaseComparator implements Comparator<String> { private static class IgnoreCaseComparator implements Comparator<Tracker> {
public int compare(String l, String r) { public int compare(Tracker l, Tracker r) {
return l.toLowerCase().compareTo(r.toLowerCase()); return l.name.toLowerCase().compareTo(r.name.toLowerCase());
} }
} }
} }

View File

@ -0,0 +1,28 @@
/*
* Released into the public domain
* with no warranty of any kind, either expressed or implied.
*/
package org.klomp.snark;
/**
* A structure for known trackers
*
* @since 0.9.1
*/
public class Tracker {
public final String name;
public final String announceURL;
public final String baseURL;
public final boolean supportsDetails;
/**
* @param baseURL The web site, may be null
*/
public Tracker(String name, String announceURL, String baseURL) {
this.name = name;
this.announceURL = announceURL;
this.baseURL = baseURL;
this.supportsDetails = name.contains("tracker2.postman.i2p");
}
}

View File

@ -37,6 +37,7 @@ import org.klomp.snark.Peer;
import org.klomp.snark.Snark; import org.klomp.snark.Snark;
import org.klomp.snark.SnarkManager; import org.klomp.snark.SnarkManager;
import org.klomp.snark.Storage; import org.klomp.snark.Storage;
import org.klomp.snark.Tracker;
import org.klomp.snark.TrackerClient; import org.klomp.snark.TrackerClient;
import org.mortbay.jetty.servlet.DefaultServlet; import org.mortbay.jetty.servlet.DefaultServlet;
@ -239,6 +240,7 @@ public class I2PSnarkServlet extends DefaultServlet {
else else
out.write("<body onload=\"initAjax()\">"); out.write("<body onload=\"initAjax()\">");
out.write("<center>"); out.write("<center>");
List<Tracker> sortedTrackers = null;
if (isConfigure) { if (isConfigure) {
out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\""); out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"");
out.write(_("Torrents")); out.write(_("Torrents"));
@ -256,16 +258,11 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write(_("Forum")); out.write(_("Forum"));
out.write("</a>\n"); out.write("</a>\n");
Map trackers = _manager.getTrackers(); sortedTrackers = _manager.getSortedTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { for (Tracker t : sortedTrackers) {
Map.Entry entry = (Map.Entry)iter.next(); if (t.baseURL == null || !t.baseURL.startsWith("http"))
String name = (String)entry.getKey();
String baseURL = (String)entry.getValue();
int e = baseURL.indexOf('=');
if (e < 0)
continue; continue;
baseURL = baseURL.substring(e + 1); out.write(" <a href=\"" + t.baseURL + "\" class=\"snarkRefresh\" target=\"_blank\">" + t.name + "</a>");
out.write(" <a href=\"" + baseURL + "\" class=\"snarkRefresh\" target=\"_blank\">" + name + "</a>");
} }
} }
out.write("</div>\n"); out.write("</div>\n");
@ -286,7 +283,7 @@ public class I2PSnarkServlet extends DefaultServlet {
// end of mainsection div // end of mainsection div
out.write("</div><div id=\"lowersection\">\n"); out.write("</div><div id=\"lowersection\">\n");
writeAddForm(out, req); writeAddForm(out, req);
writeSeedForm(out, req); writeSeedForm(out, req, sortedTrackers);
writeConfigLink(out); writeConfigLink(out);
// end of lowersection div // end of lowersection div
out.write("</div>\n"); out.write("</div>\n");
@ -773,7 +770,7 @@ public class I2PSnarkServlet extends DefaultServlet {
private void processTrackerForm(String action, HttpServletRequest req) { private void processTrackerForm(String action, HttpServletRequest req) {
if (action.equals(_("Delete selected"))) { if (action.equals(_("Delete selected"))) {
boolean changed = false; boolean changed = false;
Map<String, String> trackers = _manager.getTrackers(); Map<String, Tracker> trackers = _manager.getTrackerMap();
Enumeration e = req.getParameterNames(); Enumeration e = req.getParameterNames();
while (e.hasMoreElements()) { while (e.hasMoreElements()) {
Object o = e.nextElement(); Object o = e.nextElement();
@ -800,8 +797,8 @@ public class I2PSnarkServlet extends DefaultServlet {
hurl = hurl.trim(); hurl = hurl.trim();
aurl = aurl.trim().replace("=", "&#61;"); aurl = aurl.trim().replace("=", "&#61;");
if (name.length() > 0 && hurl.startsWith("http://") && aurl.startsWith("http://")) { if (name.length() > 0 && hurl.startsWith("http://") && aurl.startsWith("http://")) {
Map<String, String> trackers = _manager.getTrackers(); Map<String, Tracker> trackers = _manager.getTrackerMap();
trackers.put(name, aurl + '=' + hurl); trackers.put(name, new Tracker(name, aurl, hurl));
_manager.saveTrackerMap(); _manager.saveTrackerMap();
} else { } else {
_manager.addMessage(_("Enter valid tracker name and URLs")); _manager.addMessage(_("Enter valid tracker name and URLs"));
@ -1271,18 +1268,14 @@ public class I2PSnarkServlet extends DefaultServlet {
if (announce != null && (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") || if (announce != null && (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") ||
announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/"))) { announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/"))) {
Map<String, String> trackers = _manager.getTrackers(); for (Tracker t : _manager.getTrackers()) {
for (Map.Entry<String, String> entry : trackers.entrySet()) { String aURL = t.announceURL;
String baseURL = entry.getValue(); if (!(aURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv
if (!(baseURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv (announce.startsWith("http://lnQ6yoBT") && aURL.startsWith("http://tracker2.postman.i2p/")) ||
(announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")) || (announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/") && aURL.startsWith("http://tracker2.postman.i2p/"))))
(announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/") && baseURL.startsWith("http://tracker2.postman.i2p/"))))
continue; continue;
int e = baseURL.indexOf('='); String baseURL = t.baseURL;
if (e < 0) String name = t.name;
continue;
baseURL = baseURL.substring(e + 1);
String name = entry.getKey();
StringBuilder buf = new StringBuilder(128); StringBuilder buf = new StringBuilder(128);
buf.append("<a href=\"").append(baseURL).append("details.php?dllist=1&amp;filelist=1&amp;info_hash=") buf.append("<a href=\"").append(baseURL).append("details.php?dllist=1&amp;filelist=1&amp;info_hash=")
.append(TrackerClient.urlencode(infohash)) .append(TrackerClient.urlencode(infohash))
@ -1336,7 +1329,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("</div></form></div>"); out.write("</div></form></div>");
} }
private void writeSeedForm(PrintWriter out, HttpServletRequest req) throws IOException { private void writeSeedForm(PrintWriter out, HttpServletRequest req, List<Tracker> sortedTrackers) throws IOException {
String baseFile = req.getParameter("baseFile"); String baseFile = req.getParameter("baseFile");
if (baseFile == null || baseFile.trim().length() <= 0) if (baseFile == null || baseFile.trim().length() <= 0)
baseFile = ""; baseFile = "";
@ -1372,13 +1365,9 @@ public class I2PSnarkServlet extends DefaultServlet {
//out.write(_("Open trackers and DHT only")); //out.write(_("Open trackers and DHT only"));
out.write(_("Open trackers only")); out.write(_("Open trackers only"));
out.write("</option>\n"); out.write("</option>\n");
Map<String, String> trackers = _manager.getTrackers(); for (Tracker t : sortedTrackers) {
for (Map.Entry<String, String> entry : trackers.entrySet()) { String name = t.name;
String name = entry.getKey(); String announceURL = t.announceURL.replace("&#61;", "=");
String announceURL = entry.getValue();
int e = announceURL.indexOf('=');
if (e > 0)
announceURL = announceURL.substring(0, e).replace("&#61;", "=");
if (announceURL.equals(_lastAnnounceURL)) if (announceURL.equals(_lastAnnounceURL))
announceURL += "\" selected=\"selected"; announceURL += "\" selected=\"selected";
out.write("\t<option value=\"" + announceURL + "\">" + name + "</option>\n"); out.write("\t<option value=\"" + announceURL + "\">" + name + "</option>\n");
@ -1605,15 +1594,10 @@ public class I2PSnarkServlet extends DefaultServlet {
.append("</th><th>") .append("</th><th>")
.append(_("Announce URL")) .append(_("Announce URL"))
.append("</th></tr>\n"); .append("</th></tr>\n");
Map<String, String> trackers = _manager.getTrackers(); for (Tracker t : _manager.getSortedTrackers()) {
for (Map.Entry<String, String> entry : trackers.entrySet()) { String name = t.name;
String name = entry.getKey(); String homeURL = t.baseURL;
String announceURL = entry.getValue(); String announceURL = t.announceURL.replace("&#61;", "=");
int e = announceURL.indexOf('=');
if (e <= 0)
continue;
String homeURL = announceURL.substring(e + 1);
announceURL = announceURL.substring(0, e).replace("&#61;", "=");
buf.append("<tr><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"delete_") buf.append("<tr><td align=\"center\"><input type=\"checkbox\" class=\"optbox\" name=\"delete_")
.append(name).append("\">" + .append(name).append("\">" +
"</td><td align=\"left\">").append(name) "</td><td align=\"left\">").append(name)

View File

@ -1,3 +1,9 @@
2012-05-22 zzz
* i2psnark:
- Refactor tracker map
- Prevent torrent shutdown when changing file priority to skip
* RoutingKeyModifier: Update after large clock shift
2012-05-20 zzz 2012-05-20 zzz
* Console: Add full file path to thread dump message * Console: Add full file path to thread dump message
* i2psnark: * i2psnark:

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 3; public final static long BUILD = 4;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";