i2psnark: Enhancements to support RPC plugin

This commit is contained in:
zzz
2017-03-20 16:41:04 +00:00
parent 05aef9bd59
commit 95b6bd36e5
6 changed files with 117 additions and 6 deletions

View File

@ -70,6 +70,7 @@ public class I2PSnarkUtil {
private boolean _areFilesPublic;
private List<String> _openTrackers;
private DHT _dht;
private long _startedTime;
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
@ -260,6 +261,8 @@ public class I2PSnarkUtil {
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
if (_manager != null)
_startedTime = _context.clock().now();
_connecting = false;
}
if (_shouldUseDHT && _manager != null && _dht == null)
@ -295,6 +298,7 @@ public class I2PSnarkUtil {
_dht.stop();
_dht = null;
}
_startedTime = 0;
I2PSocketManager mgr = _manager;
// FIXME this can cause race NPEs elsewhere
_manager = null;
@ -310,6 +314,16 @@ public class I2PSnarkUtil {
_tmpDir.mkdirs();
}
/**
* When did we connect to the network?
* For RPC
* @return 0 if not connected
* @since 0.9.30
*/
public long getStartedTime() {
return _startedTime;
}
/** connect to the given destination */
I2PSocket connect(PeerID peer) throws IOException {
I2PSocketManager mgr = _manager;

View File

@ -89,6 +89,7 @@ public class Peer implements Comparable<Peer>
*/
//private static final long OPTION_AZMP = 0x1000000000000000l;
private long options;
private final boolean _isIncoming;
/**
* Outgoing connection.
@ -103,6 +104,7 @@ public class Peer implements Comparable<Peer>
this.infohash = infohash;
this.metainfo = metainfo;
_id = __id.incrementAndGet();
_isIncoming = false;
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
}
@ -130,6 +132,16 @@ public class Peer implements Comparable<Peer>
_id = __id.incrementAndGet();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Creating a new peer " + peerID.toString(), new Exception("creating " + _id));
_isIncoming = true;
}
/**
* Is this an incoming connection?
* For RPC
* @since 0.9.30
*/
public boolean isIncoming() {
return _isIncoming;
}
/**

View File

@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PServerSocket;
@ -238,7 +239,8 @@ public class Snark
// String indicating main activity
private volatile String activity = "Not started";
private final long savedUploaded;
private static final AtomicInteger __RPCID = new AtomicInteger();
private final int _rpcID = __RPCID.incrementAndGet();
/**
* from main() via parseArguments() single torrent
@ -1364,4 +1366,13 @@ public class Snark
long limit = 1024l * _util.getMaxUpBW();
return total > limit;
}
/**
* A unique ID for this torrent, useful for RPC
* @return positive value unless you wrap around
* @since 0.9.30
*/
public int getRPCID() {
return _rpcID;
}
}

View File

@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
@ -51,7 +53,7 @@ import org.klomp.snark.dht.KRPC;
/**
* Manage multiple snarks
*/
public class SnarkManager implements CompleteListener {
public class SnarkManager implements CompleteListener, ClientApp {
/**
* Map of (canonical) filename of the .torrent file to Snark instance.
@ -246,6 +248,13 @@ public class SnarkManager implements CompleteListener {
*/
public void start() {
_running = true;
if ("i2psnark".equals(_contextName)) {
// Register with the ClientAppManager so the rpc plugin can find us
// only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null)
cmgr.register(this);
}
_peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
@ -315,6 +324,12 @@ public class SnarkManager implements CompleteListener {
_connectionAcceptor.halt();
_idleChecker.cancel();
stopAllTorrents(true);
if ("i2psnark".equals(_contextName)) {
// only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null)
cmgr.unregister(this);
}
if (_log.shouldWarn())
_log.warn("Snark stop() end");
}
@ -322,6 +337,46 @@ public class SnarkManager implements CompleteListener {
/** @since 0.9.1 */
public boolean isStopping() { return _stopping; }
/**
* ClientApp method. Does nothing.
* Doesn't matter, we are only registering.
* @since 0.9.30
*/
public void startup() {}
/**
* ClientApp method. Does nothing.
* Doesn't matter, we are only registering.
* @since 0.9.30
*/
public void shutdown(String[] args) {}
/**
* ClientApp method.
* Doesn't matter, we are only registering.
* @return INITIALIZED always.
* @since 0.9.30
*/
public ClientAppState getState() {
return ClientAppState.INITIALIZED;
}
/**
* ClientApp method.
* @since 0.9.30
*/
public String getName() {
return "i2psnark";
}
/**
* ClientApp method.
* @since 0.9.30
*/
public String getDisplayName() {
return "i2psnark: " + _contextPath;
}
/** hook to I2PSnarkUtil for the servlet */
public I2PSnarkUtil util() { return _util; }
@ -440,6 +495,14 @@ public class SnarkManager implements CompleteListener {
return f;
}
/**
* For RPC
* @since 0.9.30
*/
public File getConfigDir() {
return _configDir;
}
/**
* Migrate the old flat config file to the new config dir
* containing the config file minus the per-torrent entries,
@ -1526,9 +1589,9 @@ public class SnarkManager implements CompleteListener {
* Called from servlet. This is only for the 'create torrent' form.
*
* @param metainfo the metainfo for the torrent
* @param bitfield the current completion status of the torrent
* @param bitfield the current completion status of the torrent, or null
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent", which is also the name of the torrent
* Must be a filesystem-safe name.
* Must be a filesystem-safe name. If null, will generate a name from the metainfo.
* @param baseFile may be null, if so look in rootDataDir
* @throws RuntimeException via Snark.fatal()
* @return success
@ -1542,10 +1605,18 @@ public class SnarkManager implements CompleteListener {
if (snark != null) {
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return false;
} else {
} else if (bitfield != null) {
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
}
// so addTorrent won't recheck
if (filename == null) {
File f = new File(getDataDir(), Storage.filterName(metainfo.getName()) + ".torrent");
if (f.exists()) {
addMessage(_t("Failed to copy torrent file to {0}", f.getAbsolutePath()));
_log.error("Torrent file already exists: " + f);
}
filename = f.getAbsolutePath();
}
try {
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
// hold the lock for a long time