diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index 02d92dcf0..eebf1625c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -33,6 +33,7 @@ public class UpdateHandler { private DecimalFormat _pct = new DecimalFormat("00.0%"); private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; + private static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress"; public UpdateHandler() { this(ContextHelper.getContext(null)); @@ -67,21 +68,27 @@ public class UpdateHandler { } public void update() { + // don't block waiting for the other one to finish + if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) { + _log.error("Update already running"); + return; + } synchronized (UpdateHandler.class) { if (_updateRunner == null) _updateRunner = new UpdateRunner(); if (_updateRunner.isRunning()) { return; } else { - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true"); + System.setProperty(PROP_UPDATE_IN_PROGRESS, "true"); I2PThread update = new I2PThread(_updateRunner, "Update"); update.start(); } } - } public String getStatus() { + if (_updateRunner == null) + return ""; return _updateRunner.getStatus(); } @@ -89,22 +96,21 @@ public class UpdateHandler { private boolean _isRunning; private String _status; private long _startedOn; - private long _written; public UpdateRunner() { _isRunning = false; - _status = "Updating
"; + _status = "Updating"; } public boolean isRunning() { return _isRunning; } public String getStatus() { return _status; } public void run() { _isRunning = true; update(); - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"); + System.setProperty(PROP_UPDATE_IN_PROGRESS, "false"); _isRunning = false; } private void update() { _startedOn = -1; - _status = "Updating
"; + _status = "Updating"; String updateURL = selectUpdateURL(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Selected update URL: " + updateURL); @@ -115,64 +121,65 @@ public class UpdateHandler { try { proxyPort = Integer.parseInt(port); } catch (NumberFormatException nfe) { - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"); + System.setProperty(PROP_UPDATE_IN_PROGRESS, "false"); return; } try { EepGet get = null; if (shouldProxy) - get = new EepGet(_context, proxyHost, proxyPort, 10, SIGNED_UPDATE_FILE, updateURL, false); + get = new EepGet(_context, proxyHost, proxyPort, 20, SIGNED_UPDATE_FILE, updateURL, false); else - get = new EepGet(_context, 10, SIGNED_UPDATE_FILE, updateURL, false); + get = new EepGet(_context, 1, SIGNED_UPDATE_FILE, updateURL, false); get.addStatusListener(UpdateRunner.this); _startedOn = _context.clock().now(); get.fetch(); } catch (Throwable t) { _context.logManager().getLog(UpdateHandler.class).error("Error updating", t); - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"); + System.setProperty(PROP_UPDATE_IN_PROGRESS, "false"); } } public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Attempt failed on " + url, cause); - _written = 0; // ignored } public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) { - _written += currentWrite; StringBuffer buf = new StringBuffer(64); buf.append("Updating "); - double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining); + double pct = ((double)alreadyTransferred + (double)currentWrite) / + ((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining); synchronized (_pct) { buf.append(_pct.format(pct)); } - buf.append(":
\n").append(_written+alreadyTransferred); - buf.append(" transferred
"); + buf.append(":
\n" + (currentWrite + alreadyTransferred)); + buf.append(" transferred"); _status = buf.toString(); } public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { - _status = "Update downloaded
"; + _status = "Update downloaded"; TrustedUpdate up = new TrustedUpdate(_context); boolean ok = up.migrateVerified(RouterVersion.VERSION, SIGNED_UPDATE_FILE, "i2pupdate.zip"); File f = new File(SIGNED_UPDATE_FILE); f.delete(); if (ok) { _log.log(Log.CRIT, "Update was VERIFIED, restarting to install it"); - _status = "Update verified
Restarting
"; + _status = "Update verified
Restarting"; restart(); } else { - _log.log(Log.CRIT, "Update was INVALID - signing key is not trusted!"); - _status = "Update signing key invalid
"; - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"); + // One other possibility, the version in the file is not sufficient + // Perhaps need an int return code - but version problem unlikely? + _log.log(Log.CRIT, "Update was INVALID - signing key is not trusted or file is corrupt from " + url); + _status = "Update signing key invalid or file is corrupt from " + url + ""; + System.setProperty(PROP_UPDATE_IN_PROGRESS, "false"); } } public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) { _log.log(Log.CRIT, "Update from " + url + " did not download completely (" + bytesTransferred + " with " + bytesRemaining + " after " + currentAttempt + " tries)"); - _status = "Transfer failed
"; - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"); + _status = "Transfer failed"; + System.setProperty(PROP_UPDATE_IN_PROGRESS, "false"); } public void headerReceived(String url, int attemptNum, String key, String val) {} public void attempting(String url) {} diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index 38dfe207b..634b362ae 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -27,7 +27,11 @@ if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %> " /> + <% if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) { %> + Update In Progress

+ <% } else { %>

+ <% } %> News URL: ">
Refresh frequency: diff --git a/apps/routerconsole/jsp/summary.jsp b/apps/routerconsole/jsp/summary.jsp index cf61e3f4a..475dd60c8 100644 --- a/apps/routerconsole/jsp/summary.jsp +++ b/apps/routerconsole/jsp/summary.jsp @@ -16,8 +16,9 @@ Now: <% if (helper.updateAvailable()) { + // display all the time so we display the final failure message + out.print("
" + update.getStatus()); if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) { - out.print("
" + update.getStatus()); } else { long nonce = new java.util.Random().nextLong(); String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce"); diff --git a/core/java/src/net/i2p/util/EepGet.java b/core/java/src/net/i2p/util/EepGet.java index 86533fed8..111372330 100644 --- a/core/java/src/net/i2p/util/EepGet.java +++ b/core/java/src/net/i2p/util/EepGet.java @@ -215,6 +215,20 @@ public class EepGet { } public static interface StatusListener { + /** + * alreadyTransferred - total of all attempts, not including currentWrite + * If nonzero on the first call, a partial file of that length was found + * To track _actual_ transfer if the output file could already exist, + * the listener should keep its own counter, + * or subtract the initial alreadyTransferred value. + * currentWrite - since last call to the listener + * bytesTransferred - includes headers, retries, redirects, ... + * bytesRemaining - on this attempt only, currentWrite already subtracted - + * or -1 if chunked encoding or server does not return a length + * + * Total length should be == alreadyTransferred + currentWrite + bytesRemaining for all calls + * + */ public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url); public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified); public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause); @@ -227,7 +241,9 @@ public class EepGet { private int _lineSize; private long _startedOn; private long _written; + private long _previousWritten; private long _lastComplete; + private boolean _firstTime; private DecimalFormat _pct = new DecimalFormat("00.0%"); private DecimalFormat _kbps = new DecimalFormat("###,000.00"); public CLIStatusListener() { @@ -237,10 +253,19 @@ public class EepGet { _markSize = markSize; _lineSize = lineSize; _written = 0; + _previousWritten = 0; _lastComplete = _context.clock().now(); _startedOn = _lastComplete; + _firstTime = true; } public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) { + if (_firstTime) { + if (alreadyTransferred > 0) { + _previousWritten = alreadyTransferred; + System.out.println("File found with length " + alreadyTransferred + ", resuming"); + } + _firstTime = false; + } for (int i = 0; i < currentWrite; i++) { _written++; if ( (_markSize > 0) && (_written % _markSize == 0) ) { @@ -253,13 +278,14 @@ public class EepGet { StringBuffer buf = new StringBuffer(50); buf.append(" "); if ( bytesRemaining > 0 ) { - double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining); + double pct = ((double)_written + _previousWritten) / + ((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining); synchronized (_pct) { buf.append(_pct.format(pct)); } buf.append(": "); } - buf.append(_written+alreadyTransferred); + buf.append(_written); buf.append(" @ "); double lineKBytes = ((double)_markSize * (double)_lineSize)/1024.0d; double kbps = lineKBytes/((double)timeToSend/1000.0d); @@ -270,7 +296,7 @@ public class EepGet { buf.append(" / "); long lifetime = _context.clock().now() - _startedOn; - double lifetimeKBps = (1000.0d*(double)(_written+alreadyTransferred)/((double)lifetime*1024.0d)); + double lifetimeKBps = (1000.0d*(double)(_written)/((double)lifetime*1024.0d)); synchronized (_kbps) { buf.append(_kbps.format(lifetimeKBps)); } @@ -283,32 +309,40 @@ public class EepGet { } } public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { + long transferred; + if (_firstTime) + transferred = 0; + else + transferred = alreadyTransferred - _previousWritten; System.out.println(); System.out.println("== " + new Date()); if (notModified) { System.out.println("== Source not modified since last download"); } else { if ( bytesRemaining > 0 ) { - System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred) - + " and " + (bytesRemaining - bytesTransferred) + " remaining"); - System.out.println("== Output saved to " + outputFile); + System.out.println("== Transfer of " + url + " completed with " + transferred + + " transferred and " + (bytesRemaining - bytesTransferred) + " remaining"); } else { - System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred) + System.out.println("== Transfer of " + url + " completed with " + transferred + " bytes transferred"); - System.out.println("== Output saved to " + outputFile); } + if (transferred > 0) + System.out.println("== Output saved to " + outputFile + " (" + alreadyTransferred + " bytes)"); } long timeToSend = _context.clock().now() - _startedOn; System.out.println("== Transfer time: " + DataHelper.formatDuration(timeToSend)); - System.out.println("== ETag: " + _etag); - StringBuffer buf = new StringBuffer(50); - buf.append("== Transfer rate: "); - double kbps = (1000.0d*(double)(_written)/((double)timeToSend*1024.0d)); - synchronized (_kbps) { - buf.append(_kbps.format(kbps)); + if (_etag != null) + System.out.println("== ETag: " + _etag); + if (transferred > 0) { + StringBuffer buf = new StringBuffer(50); + buf.append("== Transfer rate: "); + double kbps = (1000.0d*(double)(transferred)/((double)timeToSend*1024.0d)); + synchronized (_kbps) { + buf.append(_kbps.format(kbps)); + } + buf.append("KBps"); + System.out.println(buf.toString()); } - buf.append("KBps"); - System.out.println(buf.toString()); } public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) { System.out.println(); @@ -499,13 +533,8 @@ public class EepGet { timeout.resetTimer(); _out.write(buf, 0, read); _bytesTransferred += read; - // This seems necessary to properly resume a partial download into a stream, - // as nothing else increments _alreadyTransferred, and there's no file length to check. - // Hopefully this won't break compatibility with existing status listeners - // (cause them to behave weird, or show weird numbers). - _alreadyTransferred += read; - if ((_maxSize > -1) && (_alreadyTransferred > _maxSize)) // could transfer a little over maxSize - throw new IOException("Bytes transferred " + _alreadyTransferred + " violates maximum of " + _maxSize + " bytes"); + if ((_maxSize > -1) && (_alreadyTransferred + read > _maxSize)) // could transfer a little over maxSize + throw new IOException("Bytes transferred " + (_alreadyTransferred + read) + " violates maximum of " + _maxSize + " bytes"); remaining -= read; if (remaining==0 && _encodingChunked) { int char1 = _proxyIn.read(); @@ -528,7 +557,9 @@ public class EepGet { } } timeout.resetTimer(); - if (read > 0) + if (_bytesRemaining >= read) // else chunked? + _bytesRemaining -= read; + if (read > 0) { for (int i = 0; i < _listeners.size(); i++) ((StatusListener)_listeners.get(i)).bytesTransferred( _alreadyTransferred, @@ -536,6 +567,11 @@ public class EepGet { _bytesTransferred, _encodingChunked?-1:_bytesRemaining, _url); + // This seems necessary to properly resume a partial download into a stream, + // as nothing else increments _alreadyTransferred, and there's no file length to check. + // Do this after calling the listeners to keep the total correct + _alreadyTransferred += read; + } } if (_out != null) diff --git a/history.txt b/history.txt index d76613f61..45477f9f3 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,16 @@ +2008-03-10 zzz + * EepGet: Fix byte count for bytesTransferred status listeners + (fixes command line status) + * UpdateHandler: + - Fix byte count display + - Display final status on router console + - Don't allow multiple update jobs to queue up + - Increase max retries + - Code cleanup + - Don't show 'check for update' button when update in progress + - Enhance error messages + * NetDb: Comment out published netDb stats disabled for .32 + 2008-03-08 zzz * ClientPeerSelector: Implement strict ordering of peers, based on XOR distance from a random hash diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index e8a28a99e..7c973ae33 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -17,7 +17,7 @@ import net.i2p.CoreVersion; public class RouterVersion { public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $"; public final static String VERSION = "0.6.1.32"; - public final static long BUILD = 2; + public final static long BUILD = 3; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID);