forked from I2P_Developers/i2p.i2p
* Added multitorrent support to I2PSnark, accessible currently by running
"i2psnark.jar --config i2psnark.config" (which may or may not exist).
It then joins the swarm for any torrents in ./i2psnark/*.torrent, saving
their data in that directory as well. Removing the .torrent file stops
participation, and it is currently set to seed indefinitely. Completion
is logged to the logger and standard output, with further UI interaction
left to the (work in progress) web UI.
174 lines
5.3 KiB
Java
174 lines
5.3 KiB
Java
package org.klomp.snark;
|
|
|
|
import net.i2p.I2PAppContext;
|
|
import net.i2p.I2PException;
|
|
import net.i2p.util.EepGet;
|
|
import net.i2p.data.Base64;
|
|
import net.i2p.data.DataFormatException;
|
|
import net.i2p.data.Destination;
|
|
import net.i2p.client.streaming.I2PServerSocket;
|
|
import net.i2p.client.streaming.I2PSocket;
|
|
import net.i2p.client.streaming.I2PSocketManager;
|
|
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
|
import net.i2p.util.Log;
|
|
|
|
import java.io.*;
|
|
import java.util.Properties;
|
|
|
|
/**
|
|
* I2P specific helpers for I2PSnark
|
|
*/
|
|
public class I2PSnarkUtil {
|
|
private I2PAppContext _context;
|
|
private Log _log;
|
|
private static I2PSnarkUtil _instance = new I2PSnarkUtil();
|
|
public static I2PSnarkUtil instance() { return _instance; }
|
|
|
|
private boolean _shouldProxy;
|
|
private String _proxyHost;
|
|
private int _proxyPort;
|
|
private String _i2cpHost;
|
|
private int _i2cpPort;
|
|
private Properties _opts;
|
|
private I2PSocketManager _manager;
|
|
|
|
private I2PSnarkUtil() {
|
|
_context = I2PAppContext.getGlobalContext();
|
|
_log = _context.logManager().getLog(Snark.class);
|
|
setProxy("127.0.0.1", 4444);
|
|
setI2CPConfig("127.0.0.1", 7654, null);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
public void setI2CPConfig(String i2cpHost, int i2cpPort, Properties opts) {
|
|
_i2cpHost = i2cpHost;
|
|
_i2cpPort = i2cpPort;
|
|
if (opts != null)
|
|
_opts = opts;
|
|
}
|
|
|
|
/**
|
|
* Connect to the router, if we aren't already
|
|
*/
|
|
boolean connect() {
|
|
if (_manager == null) {
|
|
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, _opts);
|
|
}
|
|
return (_manager != null);
|
|
}
|
|
|
|
/** connect to the given destination */
|
|
I2PSocket connect(PeerID peer) throws IOException {
|
|
try {
|
|
return _manager.connect(peer.getAddress());
|
|
} catch (I2PException ie) {
|
|
throw new IOException("Unable to reach the peer " + peer + ": " + ie.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* fetch the given URL, returning the file it is stored in, or null on error
|
|
*/
|
|
File get(String url) {
|
|
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
|
|
File out = null;
|
|
try {
|
|
out = File.createTempFile("i2psnark", "url");
|
|
} catch (IOException ioe) {
|
|
ioe.printStackTrace();
|
|
out.delete();
|
|
return null;
|
|
}
|
|
String fetchURL = rewriteAnnounce(url);
|
|
_log.debug("Rewritten url [" + fetchURL + "]");
|
|
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, 1, out.getAbsolutePath(), fetchURL);
|
|
if (get.fetch()) {
|
|
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
|
return out;
|
|
} else {
|
|
_log.warn("Fetch failed [" + url + "]");
|
|
out.delete();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
I2PServerSocket getServerSocket() {
|
|
return _manager.getServerSocket();
|
|
}
|
|
|
|
String getOurIPString() {
|
|
return _manager.getSession().getMyDestination().toBase64();
|
|
}
|
|
Destination getDestination(String ip) {
|
|
if (ip == null) return null;
|
|
if (ip.endsWith(".i2p")) {
|
|
Destination dest = _context.namingService().lookup(ip);
|
|
if (dest != null) {
|
|
return dest;
|
|
} else {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given http://blah.i2p/foo/announce turn it into http://i2p/blah/foo/announce
|
|
*/
|
|
String rewriteAnnounce(String origAnnounce) {
|
|
int destStart = "http://".length();
|
|
int destEnd = origAnnounce.indexOf(".i2p");
|
|
int pathStart = origAnnounce.indexOf('/', destEnd);
|
|
String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
|
|
//_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");
|
|
return rv;
|
|
}
|
|
|
|
/** hook between snark's logger and an i2p log */
|
|
void debug(String msg, int snarkDebugLevel, Throwable t) {
|
|
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;
|
|
}
|
|
}
|
|
}
|