forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head 5d56a7eb371dddb9336e596bda69f99c91294b05)
to branch 'i2p.i2p.str4d.ui' (head 3aeafcdb5c0ffbc9c77f574558f8438d3e81133e)
This commit is contained in:
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
@ -237,8 +238,10 @@ public class Snark
|
||||
private volatile boolean _autoStoppable;
|
||||
// String indicating main activity
|
||||
private volatile String activity = "Not started";
|
||||
private final long savedUploaded;
|
||||
|
||||
private long savedUploaded;
|
||||
private long _startedTime;
|
||||
private static final AtomicInteger __RPCID = new AtomicInteger();
|
||||
private final int _rpcID = __RPCID.incrementAndGet();
|
||||
|
||||
/**
|
||||
* from main() via parseArguments() single torrent
|
||||
@ -542,6 +545,7 @@ public class Snark
|
||||
starting = true;
|
||||
try {
|
||||
x_startTorrent();
|
||||
_startedTime = _util.getContext().clock().now();
|
||||
} finally {
|
||||
starting = false;
|
||||
}
|
||||
@ -633,16 +637,17 @@ public class Snark
|
||||
if (st != null) {
|
||||
// TODO: Cache the config-in-mem to compare vs config-on-disk
|
||||
// (needed for auto-save to not double-save in some cases)
|
||||
//boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
|
||||
boolean changed = true;
|
||||
if (changed && completeListener != null)
|
||||
completeListener.updateStatus(this);
|
||||
long nowUploaded = getUploaded();
|
||||
boolean changed = storage.isChanged() || nowUploaded != savedUploaded;
|
||||
try {
|
||||
storage.close();
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Error closing " + torrent);
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
savedUploaded = nowUploaded;
|
||||
if (changed && completeListener != null)
|
||||
completeListener.updateStatus(this);
|
||||
}
|
||||
if (fast)
|
||||
// HACK: See above if(!fast)
|
||||
@ -1285,8 +1290,12 @@ public class Snark
|
||||
|
||||
allChecked = true;
|
||||
checking = false;
|
||||
if (storage.isChanged() && completeListener != null)
|
||||
if (storage.isChanged() && completeListener != null) {
|
||||
completeListener.updateStatus(this);
|
||||
// this saved the status, so reset the variables
|
||||
storage.clearChanged();
|
||||
savedUploaded = getUploaded();
|
||||
}
|
||||
}
|
||||
|
||||
public void storageCompleted(Storage storage)
|
||||
@ -1295,8 +1304,12 @@ public class Snark
|
||||
_log.info("Completely received " + torrent);
|
||||
//storage.close();
|
||||
//System.out.println("Completely received: " + torrent);
|
||||
if (completeListener != null)
|
||||
if (completeListener != null) {
|
||||
completeListener.torrentComplete(this);
|
||||
// this saved the status, so reset the variables
|
||||
savedUploaded = getUploaded();
|
||||
storage.clearChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setWantedPieces(Storage storage)
|
||||
@ -1364,4 +1377,23 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* When did we start this torrent
|
||||
* For RPC
|
||||
* @return 0 if not started before. Not cleared when stopped.
|
||||
* @since 0.9.30
|
||||
*/
|
||||
public long getStartedTime() {
|
||||
return _startedTime;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -305,6 +305,14 @@ public class Storage implements Closeable
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the storage changed variable
|
||||
* @since 0.9.30
|
||||
*/
|
||||
void clearChanged() {
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* File checking in progress.
|
||||
* @since 0.9.3
|
||||
|
@ -106,11 +106,11 @@ class NodeInfo extends SimpleDataStructure {
|
||||
if (parts.length != 4)
|
||||
throw new DataFormatException("Bad format");
|
||||
byte[] nid = Base64.decode(parts[0]);
|
||||
if (nid == null)
|
||||
if (nid == null || nid.length != NID.HASH_LENGTH)
|
||||
throw new DataFormatException("Bad NID");
|
||||
nID = new NID(nid);
|
||||
byte[] h = Base64.decode(parts[1]);
|
||||
if (h == null)
|
||||
if (h == null || h.length != Hash.HASH_LENGTH)
|
||||
throw new DataFormatException("Bad hash");
|
||||
//hash = new Hash(h);
|
||||
hash = Hash.create(h);
|
||||
|
@ -1803,6 +1803,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
client = "Vuze" + getAzVersion(pid.getID());
|
||||
else if ("CwsL".equals(ch))
|
||||
client = "I2PSnarkXL";
|
||||
else if ("LVhE".equals(ch))
|
||||
client = "XD" + getAzVersion(pid.getID());
|
||||
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
|
||||
client = "Robert" + getRobtVersion(pid.getID());
|
||||
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
||||
|
Reference in New Issue
Block a user