- Thread task to open tunnel and improve UI feedback while open is pending

This commit is contained in:
zzz
2012-06-18 21:07:34 +00:00
parent 4dcfe3e434
commit 4b3ccabb44
4 changed files with 124 additions and 23 deletions

View File

@ -55,8 +55,9 @@ public class I2PSnarkUtil {
private String _i2cpHost;
private int _i2cpPort;
private final Map<String, String> _opts;
private I2PSocketManager _manager;
private volatile I2PSocketManager _manager;
private boolean _configured;
private volatile boolean _connecting;
private final Set<Hash> _shitlist;
private int _maxUploaders;
private int _maxUpBW;
@ -198,6 +199,7 @@ public class I2PSnarkUtil {
*/
synchronized public boolean connect() {
if (_manager == null) {
_connecting = true;
// try to find why reconnecting after stop
if (_log.shouldLog(Log.DEBUG))
_log.debug("Connecting to I2P", new Exception("I did it"));
@ -237,6 +239,7 @@ public class I2PSnarkUtil {
if (opts.getProperty("i2p.streaming.maxConnsPerHour") == null)
opts.setProperty("i2p.streaming.maxConnsPerHour", "20");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
_connecting = false;
}
// FIXME this only instantiates krpc once, left stuck with old manager
//if (ENABLE_DHT && _manager != null && _dht == null)
@ -252,6 +255,9 @@ public class I2PSnarkUtil {
public boolean connected() { return _manager != null; }
/** @since 0.9.1 */
public boolean isConnecting() { return _manager == null && _connecting; }
/**
* For FetchAndAdd
* @return null if not connected

View File

@ -250,6 +250,7 @@ public class Snark
private String rootDataDir = ".";
private final CompleteListener completeListener;
private boolean stopped;
private boolean starting;
private byte[] id;
private byte[] infoHash;
private String additionalTrackerURL;
@ -509,9 +510,19 @@ public class Snark
}
/**
* Start up contacting peers and querying the tracker
* Start up contacting peers and querying the tracker.
* Blocks if tunnel is not yet open.
*/
public void startTorrent() {
public synchronized void startTorrent() {
starting = true;
try {
x_startTorrent();
} finally {
starting = false;
}
}
private void x_startTorrent() {
boolean ok = _util.connect();
if (!ok) fatal("Unable to connect to I2P");
if (coordinator == null) {
@ -585,7 +596,7 @@ public class Snark
* @param fast if true, limit the life of the unannounce threads
* @since 0.9.1
*/
public void stopTorrent(boolean fast) {
public synchronized void stopTorrent(boolean fast) {
stopped = true;
TrackerClient tc = trackerclient;
if (tc != null)
@ -680,6 +691,22 @@ public class Snark
return stopped;
}
/**
* Startup in progress.
* @since 0.9.1
*/
public boolean isStarting() {
return starting && stopped;
}
/**
* Set startup in progress.
* @since 0.9.1
*/
public void setStarting() {
starting = true;
}
/**
* @since 0.8.4
*/

View File

@ -867,7 +867,7 @@ public class SnarkManager implements Snark.CompleteListener {
torrent.startTorrent();
addMessage(_("Fetching {0}", name));
boolean haveSavedPeers = false;
if ((!util().connected()) && !haveSavedPeers) {
if ((_util.connected()) && !haveSavedPeers) {
addMessage(_("We have no saved peers and no other torrents are running. " +
"Fetch of {0} will not succeed until you start another torrent.", name));
}
@ -1599,6 +1599,81 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
/**
* If not connected, thread it, otherwise inline
* @since 0.9.1
*/
public void startTorrent(byte[] infoHash) {
for (Snark snark : _snarks.values()) {
if (DataHelper.eq(infoHash, snark.getInfoHash())) {
if (snark.isStarting() || !snark.isStopped()) {
addMessage("Torrent already started");
return;
}
boolean connected = _util.connected();
if ((!connected) && !_util.isConnecting())
addMessage(_("Opening the I2P tunnel"));
addMessage(_("Starting up torrent {0}", snark.getBaseName()));
if (connected) {
snark.startTorrent();
} else {
// mark it for the UI
snark.setStarting();
(new I2PAppThread(new ThreadedStarter(snark), "TorrentStarter", true)).start();
try { Thread.sleep(200); } catch (InterruptedException ie) {}
}
return;
}
}
addMessage("Torrent not found?");
}
/**
* If not connected, thread it, otherwise inline
* @since 0.9.1
*/
public void startAllTorrents() {
if (_util.connected()) {
startAll();
} else {
addMessage(_("Opening the I2P tunnel and starting all torrents."));
for (Snark snark : _snarks.values()) {
// mark it for the UI
snark.setStarting();
}
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
try { Thread.sleep(200); } catch (InterruptedException ie) {}
}
}
/**
* Use null constructor param for all
* @since 0.9.1
*/
private class ThreadedStarter implements Runnable {
private final Snark snark;
public ThreadedStarter(Snark s) { snark = s; }
public void run() {
if (snark != null) {
if (snark.isStopped())
snark.startTorrent();
} else {
startAll();
}
}
}
/**
* Inline
* @since 0.9.1
*/
private void startAll() {
for (Snark snark : _snarks.values()) {
if (snark.isStopped())
snark.startTorrent();
}
}
/**
* Stop all running torrents, and close the tunnel after a delay
* to allow for announces.
@ -1631,7 +1706,7 @@ public class SnarkManager implements Snark.CompleteListener {
// Schedule this even for final shutdown, as there's a chance
// that it's just this webapp that is stopping.
SimpleScheduler.getInstance().addEvent(new Disconnector(), 60*1000);
addMessage(_("Closing I2P tunnel after announces to trackers."));
addMessage(_("Closing I2P tunnel after notifying trackers."));
if (finalShutdown) {
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
}

View File

@ -422,7 +422,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("\">");
if (isDegraded)
out.write("</a>");
} else if (!snarks.isEmpty()) {
} else if ((!_manager.util().isConnecting()) && !snarks.isEmpty()) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
else
@ -573,14 +573,7 @@ public class I2PSnarkServlet extends DefaultServlet {
if (torrent != null) {
byte infoHash[] = Base64.decode(torrent);
if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
for (String name : _manager.listTorrentFiles()) {
Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
snark.startTorrent();
_manager.addMessage(_("Starting up torrent {0}", snark.getBaseName()));
break;
}
}
_manager.startTorrent(infoHash);
}
}
} else if (action.startsWith("Remove_")) {
@ -747,13 +740,7 @@ public class I2PSnarkServlet extends DefaultServlet {
} else if ("StopAll".equals(action)) {
_manager.stopAllTorrents(false);
} else if ("StartAll".equals(action)) {
_manager.addMessage(_("Opening the I2P tunnel and starting all torrents."));
List<Snark> snarks = getSortedSnarks(req);
for (int i = 0; i < snarks.size(); i++) {
Snark snark = snarks.get(i);
if (snark.isStopped())
snark.startTorrent();
}
_manager.startAllTorrents();
} else if ("Clear".equals(action)) {
_manager.clearMessages();
} else {
@ -989,6 +976,8 @@ public class I2PSnarkServlet extends DefaultServlet {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
"<br>" + err;
}
} else if (snark.isStarting()) {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Starting");
} else if (remaining == 0 || needed == 0) { // < 0 means no meta size yet
// partial complete or seeding
if (isRunning) {
@ -1141,6 +1130,7 @@ public class I2PSnarkServlet extends DefaultServlet {
if (showPeers)
parameters = parameters + "&p=1";
if (isRunning) {
// Stop Button
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else
@ -1151,7 +1141,8 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("\">");
if (isDegraded)
out.write("</a>");
} else {
} else if (!snark.isStarting()) {
// Start Button
// This works in Opera but it's displayed a little differently, so use noThinsp here too so all 3 icons are consistent
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
@ -1165,6 +1156,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("</a>");
if (isValid) {
// Remove Button
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
@ -1184,6 +1176,7 @@ public class I2PSnarkServlet extends DefaultServlet {
out.write("</a>");
}
// Delete Button
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");