2005-10-19 22:02:37 +00:00
|
|
|
package org.klomp.snark;
|
|
|
|
|
2008-07-16 13:42:54 +00:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
2008-11-15 23:52:40 +00:00
|
|
|
import java.util.ArrayList;
|
2008-07-16 13:42:54 +00:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Iterator;
|
2008-11-15 23:52:40 +00:00
|
|
|
import java.util.List;
|
2008-07-16 13:42:54 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Properties;
|
|
|
|
import java.util.Set;
|
2008-11-15 23:52:40 +00:00
|
|
|
import java.util.StringTokenizer;
|
2008-07-16 13:42:54 +00:00
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
import net.i2p.I2PAppContext;
|
|
|
|
import net.i2p.I2PException;
|
2005-12-16 23:18:56 +00:00
|
|
|
import net.i2p.client.I2PSession;
|
2005-10-19 22:02:37 +00:00
|
|
|
import net.i2p.client.streaming.I2PServerSocket;
|
|
|
|
import net.i2p.client.streaming.I2PSocket;
|
2009-08-26 22:15:32 +00:00
|
|
|
import net.i2p.client.streaming.I2PSocketEepGet;
|
2005-10-19 22:02:37 +00:00
|
|
|
import net.i2p.client.streaming.I2PSocketManager;
|
|
|
|
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
2008-07-16 13:42:54 +00:00
|
|
|
import net.i2p.data.DataFormatException;
|
|
|
|
import net.i2p.data.Destination;
|
|
|
|
import net.i2p.data.Hash;
|
2010-04-12 19:07:53 +00:00
|
|
|
import net.i2p.util.ConcurrentHashSet;
|
2008-07-16 13:42:54 +00:00
|
|
|
import net.i2p.util.EepGet;
|
2009-02-10 02:34:48 +00:00
|
|
|
import net.i2p.util.FileUtil;
|
2005-10-19 22:02:37 +00:00
|
|
|
import net.i2p.util.Log;
|
2009-01-31 14:22:07 +00:00
|
|
|
import net.i2p.util.SimpleScheduler;
|
2006-03-05 17:07:07 +00:00
|
|
|
import net.i2p.util.SimpleTimer;
|
2009-12-09 20:54:10 +00:00
|
|
|
import net.i2p.util.Translate;
|
2005-10-19 22:02:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* I2P specific helpers for I2PSnark
|
2008-11-16 17:11:53 +00:00
|
|
|
* We use this class as a sort of context for i2psnark
|
|
|
|
* so we can run multiple instances of single Snarks
|
|
|
|
* (but not multiple SnarkManagers, it is still static)
|
2005-10-19 22:02:37 +00:00
|
|
|
*/
|
|
|
|
public class I2PSnarkUtil {
|
|
|
|
private I2PAppContext _context;
|
|
|
|
private Log _log;
|
|
|
|
|
|
|
|
private boolean _shouldProxy;
|
|
|
|
private String _proxyHost;
|
|
|
|
private int _proxyPort;
|
|
|
|
private String _i2cpHost;
|
|
|
|
private int _i2cpPort;
|
2005-12-16 03:00:48 +00:00
|
|
|
private Map _opts;
|
2005-10-19 22:02:37 +00:00
|
|
|
private I2PSocketManager _manager;
|
2005-12-16 03:00:48 +00:00
|
|
|
private boolean _configured;
|
2010-04-12 19:07:53 +00:00
|
|
|
private final Set<Hash> _shitlist;
|
2007-03-14 04:06:27 +00:00
|
|
|
private int _maxUploaders;
|
2008-04-07 17:41:58 +00:00
|
|
|
private int _maxUpBW;
|
2008-11-18 02:18:23 +00:00
|
|
|
private int _maxConnections;
|
2009-02-10 02:34:48 +00:00
|
|
|
private File _tmpDir;
|
2005-10-19 22:02:37 +00:00
|
|
|
|
2008-11-15 23:52:40 +00:00
|
|
|
public static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
|
|
|
|
public static final boolean DEFAULT_USE_OPENTRACKERS = true;
|
|
|
|
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
|
|
|
|
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
|
|
|
|
public static final int DEFAULT_MAX_UP_BW = 8; //KBps
|
2008-11-18 02:18:23 +00:00
|
|
|
public static final int MAX_CONNECTIONS = 16; // per torrent
|
2008-11-15 23:52:40 +00:00
|
|
|
|
2008-11-16 17:11:53 +00:00
|
|
|
public I2PSnarkUtil(I2PAppContext ctx) {
|
|
|
|
_context = ctx;
|
2005-10-19 22:02:37 +00:00
|
|
|
_log = _context.logManager().getLog(Snark.class);
|
2005-12-16 03:00:48 +00:00
|
|
|
_opts = new HashMap();
|
2005-10-19 22:02:37 +00:00
|
|
|
setProxy("127.0.0.1", 4444);
|
|
|
|
setI2CPConfig("127.0.0.1", 7654, null);
|
2010-04-12 19:07:53 +00:00
|
|
|
_shitlist = new ConcurrentHashSet();
|
2005-12-16 03:00:48 +00:00
|
|
|
_configured = false;
|
2007-03-14 04:06:27 +00:00
|
|
|
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
|
2008-11-15 23:52:40 +00:00
|
|
|
_maxUpBW = DEFAULT_MAX_UP_BW;
|
2008-11-18 02:18:23 +00:00
|
|
|
_maxConnections = MAX_CONNECTIONS;
|
2009-02-10 02:34:48 +00:00
|
|
|
// This is used for both announce replies and .torrent file downloads,
|
|
|
|
// so it must be available even if not connected to I2CP.
|
|
|
|
// so much for multiple instances
|
Big directory rework.
Eliminate all uses of the current working directory, and
set up multiple directories specified by absolute paths for various uses.
Add a WorkingDir class to create a user config directory and
migrate files to it for new installs.
The directory will be $HOME/.i2p on linux and %APPDIR%\I2P on Windows,
or as specified in the system property -Di2p.dir.config=/path/to/i2pdir
All files except for the base install and temp files will be
in the config directory by default.
Temp files will be in a i2p-xxxxx subdirectory of the system temp directory
specified by the system property java.io.tmpdir.
Convert all file opens in the code to be relative to a specific directory,
as specified in the context. Code and applications should never open
files relative to the current working directory (e.g. new File("foo")).
All files should be accessed in the appropriate context directory,
e.g. new File(_context.getAppDir(), "foo").
The router.config file location may be specified as a system property on the
java command line with -Drouter.configLocation=/path/to/router.config
All directories may be specified as properties in the router.config file.
The migration will copy all files from an existing installation,
except i2psnark/, with the system property -Di2p.dir.migrate=true.
Otherwise it will just set up a new directory with a minimal configuration.
The migration will also create a modified wrapper.config and (on linux only)
a modified i2prouter script, and place them in the config directory.
There are no changes to the installer or the default i2prouter, i2prouter.bat,
i2prouter, wrapper.config, runplain.sh, windows service installer/uninstaller,
etc. in this checkin.
* Directories. These are all set at instantiation and will not be changed by
* subsequent property changes.
* All properties, if set, should be absolute paths.
*
* Name Property Method Files
* ----- -------- ----- -----
* Base i2p.dir.base getBaseDir() lib/, webapps/, docs/, geoip/, licenses/, ...
* Temp i2p.dir.temp getTempDir() Temporary files
* Config i2p.dir.config getConfigDir() *.config, hosts.txt, addressbook/, ...
*
* (the following all default to the same as Config)
*
* Router i2p.dir.router getRouterDir() netDb/, peerProfiles/, router.*, keyBackup/, ...
* Log i2p.dir.log getLogDir() wrapper.log*, logs/
* PID i2p.dir.pid getPIDDir() wrapper *.pid files, router.ping
* App i2p.dir.app getAppDir() eepsite/, ...
*
* Note that we can't control where the wrapper actually puts its files.
All these will be set appropriately in a Router Context.
In an I2P App Context, all except Temp will be the current working directory.
Lightly tested so far, needs much more testing.
2009-06-04 19:14:40 +00:00
|
|
|
_tmpDir = new File(ctx.getTempDir(), "i2psnark");
|
2009-02-10 02:34:48 +00:00
|
|
|
FileUtil.rmdir(_tmpDir, false);
|
|
|
|
_tmpDir.mkdirs();
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Specify what HTTP proxy tracker requests should go through (specify a null
|
|
|
|
* host for no proxying)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public void setProxy(String host, int port) {
|
|
|
|
if ( (host != null) && (port > 0) ) {
|
|
|
|
_shouldProxy = true;
|
|
|
|
_proxyHost = host;
|
|
|
|
_proxyPort = port;
|
|
|
|
} else {
|
|
|
|
_shouldProxy = false;
|
|
|
|
_proxyHost = null;
|
|
|
|
_proxyPort = -1;
|
|
|
|
}
|
2005-12-16 03:00:48 +00:00
|
|
|
_configured = true;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2005-12-16 03:00:48 +00:00
|
|
|
public boolean configured() { return _configured; }
|
|
|
|
|
|
|
|
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
|
2008-11-18 02:18:23 +00:00
|
|
|
if (i2cpHost != null)
|
|
|
|
_i2cpHost = i2cpHost;
|
|
|
|
if (i2cpPort > 0)
|
|
|
|
_i2cpPort = i2cpPort;
|
2009-02-10 02:34:48 +00:00
|
|
|
// can't remove any options this way...
|
2005-10-19 22:02:37 +00:00
|
|
|
if (opts != null)
|
2005-12-16 03:00:48 +00:00
|
|
|
_opts.putAll(opts);
|
|
|
|
_configured = true;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2007-03-14 04:06:27 +00:00
|
|
|
public void setMaxUploaders(int limit) {
|
|
|
|
_maxUploaders = limit;
|
|
|
|
_configured = true;
|
|
|
|
}
|
|
|
|
|
2008-04-07 17:41:58 +00:00
|
|
|
public void setMaxUpBW(int limit) {
|
|
|
|
_maxUpBW = limit;
|
|
|
|
_configured = true;
|
|
|
|
}
|
|
|
|
|
2008-11-18 02:18:23 +00:00
|
|
|
public void setMaxConnections(int limit) {
|
|
|
|
_maxConnections = limit;
|
|
|
|
_configured = true;
|
|
|
|
}
|
|
|
|
|
2005-12-16 03:00:48 +00:00
|
|
|
public String getI2CPHost() { return _i2cpHost; }
|
|
|
|
public int getI2CPPort() { return _i2cpPort; }
|
|
|
|
public Map getI2CPOptions() { return _opts; }
|
|
|
|
public String getEepProxyHost() { return _proxyHost; }
|
|
|
|
public int getEepProxyPort() { return _proxyPort; }
|
|
|
|
public boolean getEepProxySet() { return _shouldProxy; }
|
2007-03-14 04:06:27 +00:00
|
|
|
public int getMaxUploaders() { return _maxUploaders; }
|
2008-04-07 17:41:58 +00:00
|
|
|
public int getMaxUpBW() { return _maxUpBW; }
|
2008-11-18 02:18:23 +00:00
|
|
|
public int getMaxConnections() { return _maxConnections; }
|
2005-12-16 03:00:48 +00:00
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/**
|
|
|
|
* Connect to the router, if we aren't already
|
|
|
|
*/
|
2008-04-12 21:34:25 +00:00
|
|
|
synchronized public boolean connect() {
|
2005-10-19 22:02:37 +00:00
|
|
|
if (_manager == null) {
|
2005-12-16 03:00:48 +00:00
|
|
|
Properties opts = new Properties();
|
|
|
|
if (_opts != null) {
|
|
|
|
for (Iterator iter = _opts.keySet().iterator(); iter.hasNext(); ) {
|
|
|
|
String key = (String)iter.next();
|
|
|
|
opts.setProperty(key, _opts.get(key).toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (opts.getProperty("inbound.nickname") == null)
|
|
|
|
opts.setProperty("inbound.nickname", "I2PSnark");
|
2007-08-11 20:48:14 +00:00
|
|
|
if (opts.getProperty("outbound.nickname") == null)
|
|
|
|
opts.setProperty("outbound.nickname", "I2PSnark");
|
2005-12-21 12:04:54 +00:00
|
|
|
if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
|
2007-11-24 20:22:45 +00:00
|
|
|
opts.setProperty("i2p.streaming.inactivityTimeout", "240000");
|
2005-12-21 12:04:54 +00:00
|
|
|
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
|
2007-11-24 20:22:45 +00:00
|
|
|
opts.setProperty("i2p.streaming.inactivityAction", "1"); // 1 == disconnect, 2 == ping
|
2007-03-07 05:11:45 +00:00
|
|
|
if (opts.getProperty("i2p.streaming.initialWindowSize") == null)
|
|
|
|
opts.setProperty("i2p.streaming.initialWindowSize", "1");
|
|
|
|
if (opts.getProperty("i2p.streaming.slowStartGrowthRateFactor") == null)
|
|
|
|
opts.setProperty("i2p.streaming.slowStartGrowthRateFactor", "1");
|
2006-02-26 21:30:56 +00:00
|
|
|
//if (opts.getProperty("i2p.streaming.writeTimeout") == null)
|
|
|
|
// opts.setProperty("i2p.streaming.writeTimeout", "90000");
|
2005-12-27 13:20:50 +00:00
|
|
|
//if (opts.getProperty("i2p.streaming.readTimeout") == null)
|
|
|
|
// opts.setProperty("i2p.streaming.readTimeout", "120000");
|
2005-12-16 03:00:48 +00:00
|
|
|
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
return (_manager != null);
|
|
|
|
}
|
|
|
|
|
2005-12-16 03:00:48 +00:00
|
|
|
public boolean connected() { return _manager != null; }
|
|
|
|
/**
|
|
|
|
* Destroy the destination itself
|
|
|
|
*/
|
|
|
|
public void disconnect() {
|
|
|
|
I2PSocketManager mgr = _manager;
|
|
|
|
_manager = null;
|
2006-03-05 17:07:07 +00:00
|
|
|
_shitlist.clear();
|
2005-12-16 03:00:48 +00:00
|
|
|
mgr.destroySocketManager();
|
2009-02-10 02:34:48 +00:00
|
|
|
// this will delete a .torrent file d/l in progress so don't do that...
|
|
|
|
FileUtil.rmdir(_tmpDir, false);
|
|
|
|
// in case the user will d/l a .torrent file next...
|
|
|
|
_tmpDir.mkdirs();
|
2005-12-16 03:00:48 +00:00
|
|
|
}
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/** connect to the given destination */
|
|
|
|
I2PSocket connect(PeerID peer) throws IOException {
|
2006-03-05 17:07:07 +00:00
|
|
|
Hash dest = peer.getAddress().calculateHash();
|
2010-04-12 19:07:53 +00:00
|
|
|
if (_shitlist.contains(dest))
|
|
|
|
throw new IOException("Not trying to contact " + dest.toBase64() + ", as they are shitlisted");
|
2005-10-19 22:02:37 +00:00
|
|
|
try {
|
2006-03-05 17:07:07 +00:00
|
|
|
I2PSocket rv = _manager.connect(peer.getAddress());
|
2010-04-12 19:07:53 +00:00
|
|
|
if (rv != null)
|
|
|
|
_shitlist.remove(dest);
|
2006-03-05 17:07:07 +00:00
|
|
|
return rv;
|
2005-10-19 22:02:37 +00:00
|
|
|
} catch (I2PException ie) {
|
2010-04-12 19:07:53 +00:00
|
|
|
_shitlist.add(dest);
|
2009-01-31 14:22:07 +00:00
|
|
|
SimpleScheduler.getInstance().addEvent(new Unshitlist(dest), 10*60*1000);
|
2005-10-19 22:02:37 +00:00
|
|
|
throw new IOException("Unable to reach the peer " + peer + ": " + ie.getMessage());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-05 17:07:07 +00:00
|
|
|
private class Unshitlist implements SimpleTimer.TimedEvent {
|
|
|
|
private Hash _dest;
|
|
|
|
public Unshitlist(Hash dest) { _dest = dest; }
|
2010-04-12 19:07:53 +00:00
|
|
|
public void timeReached() { _shitlist.remove(_dest); }
|
2006-03-05 17:07:07 +00:00
|
|
|
}
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/**
|
|
|
|
* fetch the given URL, returning the file it is stored in, or null on error
|
|
|
|
*/
|
2008-03-25 21:54:54 +00:00
|
|
|
public File get(String url) { return get(url, true, 0); }
|
|
|
|
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
|
2008-03-19 00:20:15 +00:00
|
|
|
public File get(String url, int retries) { return get(url, true, retries); }
|
|
|
|
public File get(String url, boolean rewrite, int retries) {
|
2005-12-13 09:38:51 +00:00
|
|
|
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
2005-10-19 22:02:37 +00:00
|
|
|
File out = null;
|
|
|
|
try {
|
2009-02-10 02:34:48 +00:00
|
|
|
// we could use the system tmp dir but deleteOnExit() doesn't seem to work on all platforms...
|
|
|
|
out = File.createTempFile("i2psnark", null, _tmpDir);
|
2005-10-19 22:02:37 +00:00
|
|
|
} catch (IOException ioe) {
|
|
|
|
ioe.printStackTrace();
|
2008-10-26 18:18:34 +00:00
|
|
|
if (out != null)
|
|
|
|
out.delete();
|
2005-10-19 22:02:37 +00:00
|
|
|
return null;
|
|
|
|
}
|
2008-12-20 02:33:57 +00:00
|
|
|
out.deleteOnExit();
|
2005-12-16 03:00:48 +00:00
|
|
|
String fetchURL = url;
|
|
|
|
if (rewrite)
|
|
|
|
fetchURL = rewriteAnnounce(url);
|
|
|
|
//_log.debug("Rewritten url [" + fetchURL + "]");
|
2009-08-26 22:15:32 +00:00
|
|
|
//EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
|
|
|
// Use our tunnel for announces and .torrent fetches too! Make sure we're connected first...
|
|
|
|
if (!connected()) {
|
|
|
|
if (!connect())
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
2005-10-19 22:02:37 +00:00
|
|
|
if (get.fetch()) {
|
2005-12-13 09:38:51 +00:00
|
|
|
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
2005-10-19 22:02:37 +00:00
|
|
|
return out;
|
|
|
|
} else {
|
2005-12-13 09:38:51 +00:00
|
|
|
_log.warn("Fetch failed [" + url + "]");
|
2005-10-19 22:02:37 +00:00
|
|
|
out.delete();
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-16 03:00:48 +00:00
|
|
|
public I2PServerSocket getServerSocket() {
|
2006-01-26 04:28:15 +00:00
|
|
|
I2PSocketManager mgr = _manager;
|
|
|
|
if (mgr != null)
|
|
|
|
return mgr.getServerSocket();
|
|
|
|
else
|
|
|
|
return null;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
String getOurIPString() {
|
2008-04-07 17:41:58 +00:00
|
|
|
if (_manager == null)
|
|
|
|
return "unknown";
|
2005-12-16 23:18:56 +00:00
|
|
|
I2PSession sess = _manager.getSession();
|
|
|
|
if (sess != null) {
|
|
|
|
Destination dest = sess.getMyDestination();
|
|
|
|
if (dest != null)
|
|
|
|
return dest.toBase64();
|
|
|
|
}
|
|
|
|
return "unknown";
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
2008-11-16 17:11:53 +00:00
|
|
|
|
|
|
|
/** Base64 only - static (no naming service) */
|
|
|
|
static Destination getDestinationFromBase64(String ip) {
|
|
|
|
if (ip == null) return null;
|
|
|
|
if (ip.endsWith(".i2p")) {
|
|
|
|
if (ip.length() < 520)
|
|
|
|
return null;
|
|
|
|
try {
|
|
|
|
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
|
|
|
|
} catch (DataFormatException dfe) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
return new Destination(ip);
|
|
|
|
} catch (DataFormatException dfe) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Base64 Hash or Hash.i2p or name.i2p using naming service */
|
2005-10-19 22:02:37 +00:00
|
|
|
Destination getDestination(String ip) {
|
|
|
|
if (ip == null) return null;
|
|
|
|
if (ip.endsWith(".i2p")) {
|
2008-03-05 14:19:19 +00:00
|
|
|
if (ip.length() < 520) { // key + ".i2p"
|
|
|
|
Destination dest = _context.namingService().lookup(ip);
|
|
|
|
if (dest != null)
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
|
|
|
|
} catch (DataFormatException dfe) {
|
|
|
|
return null;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
return new Destination(ip);
|
|
|
|
} catch (DataFormatException dfe) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-25 21:54:54 +00:00
|
|
|
public String lookup(String name) {
|
|
|
|
Destination dest = getDestination(name);
|
|
|
|
if (dest == null)
|
|
|
|
return null;
|
|
|
|
return dest.toBase64();
|
|
|
|
}
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/**
|
2008-03-25 21:54:54 +00:00
|
|
|
* Given http://KEY.i2p/foo/announce turn it into http://i2p/KEY/foo/announce
|
|
|
|
* Given http://tracker.blah.i2p/foo/announce leave it alone
|
2005-10-19 22:02:37 +00:00
|
|
|
*/
|
|
|
|
String rewriteAnnounce(String origAnnounce) {
|
|
|
|
int destStart = "http://".length();
|
|
|
|
int destEnd = origAnnounce.indexOf(".i2p");
|
2008-03-25 21:54:54 +00:00
|
|
|
if (destEnd < destStart + 516)
|
|
|
|
return origAnnounce;
|
2005-10-19 22:02:37 +00:00
|
|
|
int pathStart = origAnnounce.indexOf('/', destEnd);
|
2005-12-13 09:38:51 +00:00
|
|
|
String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
|
2005-12-15 08:58:30 +00:00
|
|
|
//_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");
|
2005-12-13 09:38:51 +00:00
|
|
|
return rv;
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|
|
|
|
|
2009-10-04 14:06:14 +00:00
|
|
|
/** @param ot non-null */
|
2009-10-02 15:12:24 +00:00
|
|
|
public void setOpenTrackerString(String ot) {
|
|
|
|
_opts.put(PROP_OPENTRACKERS, ot);
|
|
|
|
}
|
|
|
|
|
2008-11-15 23:52:40 +00:00
|
|
|
public String getOpenTrackerString() {
|
|
|
|
String rv = (String) _opts.get(PROP_OPENTRACKERS);
|
|
|
|
if (rv == null)
|
|
|
|
return DEFAULT_OPENTRACKERS;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** comma delimited list open trackers to use as backups */
|
|
|
|
/** sorted map of name to announceURL=baseURL */
|
|
|
|
public List getOpenTrackers() {
|
|
|
|
if (!shouldUseOpenTrackers())
|
|
|
|
return null;
|
|
|
|
List rv = new ArrayList(1);
|
|
|
|
String trackers = getOpenTrackerString();
|
|
|
|
StringTokenizer tok = new StringTokenizer(trackers, ", ");
|
|
|
|
while (tok.hasMoreTokens())
|
|
|
|
rv.add(tok.nextToken());
|
|
|
|
|
2010-05-05 16:51:54 +00:00
|
|
|
if (rv.isEmpty())
|
2008-11-15 23:52:40 +00:00
|
|
|
return null;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean shouldUseOpenTrackers() {
|
|
|
|
String rv = (String) _opts.get(PROP_USE_OPENTRACKERS);
|
|
|
|
if (rv == null)
|
|
|
|
return DEFAULT_USE_OPENTRACKERS;
|
|
|
|
return Boolean.valueOf(rv).booleanValue();
|
|
|
|
}
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/** hook between snark's logger and an i2p log */
|
2008-11-16 17:11:53 +00:00
|
|
|
void debug(String msg, int snarkDebugLevel) {
|
|
|
|
debug(msg, snarkDebugLevel, null);
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
void debug(String msg, int snarkDebugLevel, Throwable t) {
|
2005-12-18 05:39:52 +00:00
|
|
|
if (t instanceof OutOfMemoryError) {
|
|
|
|
try { Thread.sleep(100); } catch (InterruptedException ie) {}
|
|
|
|
try {
|
|
|
|
t.printStackTrace();
|
|
|
|
} catch (Throwable tt) {}
|
|
|
|
try {
|
|
|
|
System.out.println("OOM thread: " + Thread.currentThread().getName());
|
|
|
|
} catch (Throwable tt) {}
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
switch (snarkDebugLevel) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
_log.error(msg, t);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
_log.warn(msg, t);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
_log.info(msg, t);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
default:
|
|
|
|
_log.debug(msg, t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-12-09 20:54:10 +00:00
|
|
|
|
2009-12-10 02:12:18 +00:00
|
|
|
private static final String BUNDLE_NAME = "org.klomp.snark.web.messages";
|
2009-12-09 20:54:10 +00:00
|
|
|
|
|
|
|
/** lang in routerconsole.lang property, else current locale */
|
|
|
|
public String getString(String key) {
|
|
|
|
return Translate.getString(key, _context, BUNDLE_NAME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* translate a string with a parameter
|
|
|
|
* This is a lot more expensive than getString(s, ctx), so use sparingly.
|
|
|
|
*
|
|
|
|
* @param s string to be translated containing {0}
|
|
|
|
* The {0} will be replaced by the parameter.
|
|
|
|
* Single quotes must be doubled, i.e. ' -> '' in the string.
|
|
|
|
* @param o parameter, not translated.
|
|
|
|
* To tranlslate parameter also, use _("foo {0} bar", _("baz"))
|
|
|
|
* Do not double the single quotes in the parameter.
|
|
|
|
* Use autoboxing to call with ints, longs, floats, etc.
|
|
|
|
*/
|
|
|
|
public String getString(String s, Object o) {
|
|
|
|
return Translate.getString(s, o, _context, BUNDLE_NAME);
|
|
|
|
}
|
2009-12-10 18:08:50 +00:00
|
|
|
|
|
|
|
/** {0} and {1} */
|
|
|
|
public String getString(String s, Object o, Object o2) {
|
|
|
|
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
|
|
|
}
|
2005-10-19 22:02:37 +00:00
|
|
|
}
|