diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index f23765b21ec8407f0fc7698a7b3764628fb80151..ddead3a58f87fa3cc951d5c64b2a94cb720facfd 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -1002,9 +1002,9 @@ public class Storage // TODO alternative - check hash on the fly as we write to the file, // to save another I/O pass boolean correctHash = metainfo.checkPiece(pp); - if (listener != null) - listener.storageChecked(this, piece, correctHash); if (!correctHash) { + if (listener != null) + listener.storageChecked(this, piece, false); return false; } @@ -1066,6 +1066,9 @@ public class Storage complete = needed == 0; } } + // tell listener after counts are updated + if (listener != null) + listener.storageChecked(this, piece, true); if (complete) { // do we also need to close all of the files and reopen @@ -1228,7 +1231,8 @@ public class Storage String hex = DataHelper.toString(meta.getInfoHash()); System.out.println("Created: " + file); System.out.println("InfoHash: " + hex); - String magnet = MagnetURI.MAGNET_FULL + hex; + String basename = base.getName().replace(" ", "%20"); + String magnet = MagnetURI.MAGNET_FULL + hex + "&dn=" + basename; if (announce != null) magnet += "&tr=" + announce; System.out.println("Magnet: " + magnet); diff --git a/apps/i2psnark/java/src/org/klomp/snark/UpdateRunner.java b/apps/i2psnark/java/src/org/klomp/snark/UpdateRunner.java index 759026edca967e9bd8fd23fb1e94c1dde870a5af..63d9670f177c251f31557d20fc76c35e0509e16d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/UpdateRunner.java +++ b/apps/i2psnark/java/src/org/klomp/snark/UpdateRunner.java @@ -33,6 +33,7 @@ class UpdateRunner implements UpdateTask, CompleteListener { private static final long MAX_LENGTH = 30*1024*1024; private static final long METAINFO_TIMEOUT = 30*60*1000; private static final long COMPLETE_TIMEOUT = 3*60*60*1000; + private static final long CHECK_INTERVAL = 3*60*1000; public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr, List<URI> uris, String newVersion) { @@ -92,6 +93,12 @@ class UpdateRunner implements UpdateTask, CompleteListener { if (storage != null && storage.complete()) processComplete(_snark); } + if (!_isComplete) { + if (_snark.isStopped() && !_snark.isStarting()) + _snark.startTorrent(); + // we aren't a listener so we must poll + new Watcher(); + } break; } String name = magnet.getName(); @@ -142,6 +149,36 @@ class UpdateRunner implements UpdateTask, CompleteListener { } } + /** + * Rarely used - only if the user added the torrent, so + * we aren't a complete listener. + * This will periodically until the complete timeout. + */ + private class Watcher extends SimpleTimer2.TimedEvent { + private final long _start = _context.clock().now(); + + public Watcher() { + super(_context.simpleTimer2(), CHECK_INTERVAL); + } + + public void timeReached() { + if (_hasMetaInfo && _snark.getRemainingLength() == 0 && !_isComplete) + processComplete(_snark); + if (_isComplete || !_isRunning) + return; + if (_context.clock().now() - _start >= METAINFO_TIMEOUT && !_hasMetaInfo) { + fatal("Metainfo timeout"); + return; + } + if (_context.clock().now() - _start >= COMPLETE_TIMEOUT) { + fatal("Complete timeout"); + return; + } + notifyProgress(); + reschedule(CHECK_INTERVAL); + } + } + private void fatal(String error) { if (_snark != null) { if (_hasMetaInfo) { @@ -183,6 +220,15 @@ class UpdateRunner implements UpdateTask, CompleteListener { _isComplete = true; } + private void notifyProgress() { + if (_hasMetaInfo) { + long total = _snark.getTotalLength(); + long remaining = _snark.getRemainingLength(); + String status = "<b>" + _smgr.util().getString("Updating") + "</b>"; + _umgr.notifyProgress(this, status, total - remaining, total); + } + } + //////// begin CompleteListener methods //////// all pass through to SnarkManager @@ -217,6 +263,7 @@ class UpdateRunner implements UpdateTask, CompleteListener { return null; } _hasMetaInfo = true; + notifyProgress(); return _smgr.gotMetaInfo(snark); } @@ -230,12 +277,7 @@ class UpdateRunner implements UpdateTask, CompleteListener { } public void gotPiece(Snark snark) { - if (_hasMetaInfo) { - long total = snark.getTotalLength(); - long remaining = snark.getRemainingLength(); - String status = "<b>" + _smgr.util().getString("Updating") + "</b>"; - _umgr.notifyProgress(this, status, total - remaining, total); - } + notifyProgress(); _smgr.gotPiece(snark); } diff --git a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java index 846ee90b9263954afaca80cd7c3b5cf1bfac7e27..3aed6631533b7853db7c07b8a312d6311eea2f7d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java @@ -111,8 +111,10 @@ public class ConsoleUpdateManager implements UpdateManager { _context.registerUpdateManager(this); DummyHandler dh = new DummyHandler(_context, this); - register((Checker)dh, TYPE_DUMMY, HTTP, 0); - register((Updater)dh, TYPE_DUMMY, HTTP, 0); + register((Checker)dh, TYPE_DUMMY, METHOD_DUMMY, 0); + register((Updater)dh, TYPE_DUMMY, METHOD_DUMMY, 0); + VersionAvailable dummyVA = new VersionAvailable("", "", METHOD_DUMMY, Collections.EMPTY_LIST); + _available.put(new UpdateItem(TYPE_DUMMY, ""), dummyVA); // register news before router, so we don't fire off an update // right at instantiation if the news is already indicating a new version Checker c = new NewsHandler(_context, this); @@ -120,6 +122,9 @@ public class ConsoleUpdateManager implements UpdateManager { register(c, ROUTER_SIGNED, HTTP, 0); // news is an update checker for the router Updater u = new UpdateHandler(_context, this); register(u, ROUTER_SIGNED, HTTP, 0); + // TODO see NewsFetcher + //register(u, ROUTER_SIGNED, HTTPS_CLEARNET, -5); + //register(u, ROUTER_SIGNED, HTTP_CLEARNET, -10); UnsignedUpdateHandler uuh = new UnsignedUpdateHandler(_context, this); register((Checker)uuh, ROUTER_UNSIGNED, HTTP, 0); register((Updater)uuh, ROUTER_UNSIGNED, HTTP, 0); @@ -735,6 +740,7 @@ public class ConsoleUpdateManager implements UpdateManager { /** * Not necessarily the end if there are more URIs to try. + * @param task checker or updater * @param t may be null */ public void notifyAttemptFailed(UpdateTask task, String reason, Throwable t) { @@ -744,6 +750,7 @@ public class ConsoleUpdateManager implements UpdateManager { /** * The task has finished and failed. + * @param task checker or updater * @param t may be null */ public void notifyTaskFailed(UpdateTask task, String reason, Throwable t) { @@ -763,8 +770,9 @@ public class ConsoleUpdateManager implements UpdateManager { } _downloaders.remove(task); _activeCheckers.remove(task); -///// for certain types only - finishStatus("<b>" + _("Transfer failed from {0}", linkify(task.getURI().toString())) + "</b>"); + // any other types that shouldn't display? + if (task.getURI() != null && task.getType() != TYPE_DUMMY) + finishStatus("<b>" + _("Transfer failed from {0}", linkify(task.getURI().toString())) + "</b>"); } /** @@ -775,7 +783,7 @@ public class ConsoleUpdateManager implements UpdateManager { * If the return value is false, caller must call notifyTaskFailed() or notifyComplete() * again. * - * @param must be an Updater, not a Checker + * @param task must be an Updater, not a Checker * @param actualVersion may be higher (or lower?) than the version requested * @param file a valid format for the task's UpdateType, or null if it did the installation itself * @return true if valid, false if corrupt diff --git a/apps/routerconsole/java/src/net/i2p/router/update/DummyHandler.java b/apps/routerconsole/java/src/net/i2p/router/update/DummyHandler.java index 4071efd2ec6cb943dc6adc1aac2e2bb0cc202e5b..8470d0efef6295e3d0294d4e14642fe4ce2f0a21 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/DummyHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/DummyHandler.java @@ -55,6 +55,9 @@ class DummyHandler implements Checker, Updater { @Override public UpdateType getType() { return UpdateType.TYPE_DUMMY; } + @Override + public UpdateMethod getMethod() { return UpdateMethod.METHOD_DUMMY; } + @Override protected void update() { try { diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java index ac9478c06082c5ff98870ec9719d33c0f9ac36dc..530926c50e986a2800c75b3cbf53cd031c6e58e4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java @@ -114,14 +114,23 @@ class NewsFetcher extends UpdateRunner { } } + // Fake XML parsing + // Line must contain this, and full entry must be on one line private static final String VERSION_PREFIX = "<i2p.release "; + // all keys mapped to lower case by parseArgs() private static final String VERSION_KEY = "version"; - private static final String SUD_KEY = "sudmagnet"; - private static final String SU2_KEY = "su2magnet"; + private static final String MIN_VERSION_KEY = "minversion"; + private static final String SUD_KEY = "sudtorrent"; + private static final String SU2_KEY = "su2torrent"; + private static final String CLEARNET_SUD_KEY = "sudclearnet"; + private static final String CLEARNET_SU2_KEY = "su2clearnet"; + private static final String I2P_SUD_KEY = "sudi2p"; + private static final String I2P_SU2_KEY = "su2i2p"; /** * Parse the installed (not the temp) news file for the latest version. * TODO: Real XML parsing + * TODO: Check minVersion, use backup URLs specified */ void checkForUpdates() { FileInputStream in = null; @@ -139,6 +148,9 @@ class NewsFetcher extends UpdateRunner { if (TrustedUpdate.needsUpdate(RouterVersion.VERSION, ver)) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Our version is out of date, update!"); + // TODO if minversion > our version, continue + // and look for a second entry with clearnet URLs + // TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED, "", HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP),