From 8b2889e31764c4766503de0d919fa72e64bd341d Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 21 Oct 2012 17:14:54 +0000
Subject: [PATCH] - Only fail after all URLs are tried - Move registration from
 servlet to manager and delay - Fix plugin updates - More logging

---
 .../src/org/klomp/snark/SnarkManager.java     | 25 ++++++++++++
 .../src/org/klomp/snark/UpdateHandler.java    |  2 +-
 .../org/klomp/snark/web/I2PSnarkServlet.java  | 13 -------
 .../router/update/ConsoleUpdateManager.java   | 38 +++++++++++++------
 .../router/update/PluginUpdateHandler.java    |  7 ++--
 .../i2p/router/update/PluginUpdateRunner.java |  2 +
 .../net/i2p/router/update/UpdateRunner.java   |  7 +++-
 .../i2p/router/web/ConfigClientsHandler.java  | 11 ++++--
 8 files changed, 69 insertions(+), 36 deletions(-)

diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 8bae58b52b..4399b5f232 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -27,6 +27,7 @@ import java.util.concurrent.LinkedBlockingQueue;
 import net.i2p.I2PAppContext;
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
+import net.i2p.update.*;
 import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.FileUtil;
 import net.i2p.util.I2PAppThread;
@@ -65,6 +66,8 @@ public class SnarkManager implements CompleteListener {
     private volatile boolean _running;
     private volatile boolean _stopping;
     private final Map<String, Tracker> _trackerMap;
+    private UpdateManager _umgr;
+    private UpdateHandler _uhandler;
     
     public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
     public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
@@ -149,10 +152,28 @@ public class SnarkManager implements CompleteListener {
         _connectionAcceptor = new ConnectionAcceptor(_util);
         _monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
         _monitor.start();
+        // delay until UpdateManager is there
+        _context.simpleScheduler().addEvent(new Register(), 4*60*1000);
         // Not required, Jetty has a shutdown hook
         //_context.addShutdownTask(new SnarkManagerShutdown());
     }
 
+    /** @since 0.9.4 */
+    private class Register implements SimpleTimer.TimedEvent {
+        public void timeReached() {
+            if (!_running)
+                return;
+            _umgr = _context.updateManager();
+            if (_umgr != null) {
+                _uhandler = new UpdateHandler(_context, _umgr, SnarkManager.this);
+                _umgr.register(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT, 10);
+                _log.warn("Registering with update manager");
+            } else {
+                _log.warn("No update manager to register with");
+            }
+        }
+    }
+    
     /*
      *  Called by the webapp at Jetty shutdown.
      *  Stops all torrents. Does not close the tunnel, so the announces have a chance.
@@ -160,6 +181,10 @@ public class SnarkManager implements CompleteListener {
      *  Runs inline.
      */
     public void stop() {
+        if (_umgr != null && _uhandler != null) {
+            //_uhandler.shutdown();
+            _umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
+        }
         _running = false;
         _monitor.interrupt();
         _connectionAcceptor.halt();
diff --git a/apps/i2psnark/java/src/org/klomp/snark/UpdateHandler.java b/apps/i2psnark/java/src/org/klomp/snark/UpdateHandler.java
index 7bb41bc2fe..ecb27c55d0 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/UpdateHandler.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/UpdateHandler.java
@@ -21,7 +21,7 @@ import net.i2p.update.*;
  *
  * @since 0.9.4
  */
-public class UpdateHandler implements Updater {
+class UpdateHandler implements Updater {
     private final I2PAppContext _context;
     private final UpdateManager _umgr;
     private final SnarkManager _smgr;
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 459652e690..e96eefe0b2 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -30,7 +30,6 @@ import javax.servlet.http.HttpServletResponse;
 import net.i2p.I2PAppContext;
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
-import net.i2p.update.*;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 
@@ -43,7 +42,6 @@ import org.klomp.snark.SnarkManager;
 import org.klomp.snark.Storage;
 import org.klomp.snark.Tracker;
 import org.klomp.snark.TrackerClient;
-import org.klomp.snark.UpdateHandler;
 import org.klomp.snark.dht.DHT;
 
 import org.mortbay.jetty.servlet.DefaultServlet;
@@ -59,8 +57,6 @@ public class I2PSnarkServlet extends DefaultServlet {
     private I2PAppContext _context;
     private Log _log;
     private SnarkManager _manager;
-    private UpdateManager _umgr;
-    private UpdateHandler _uhandler;
     private static long _nonce;
     private Resource _resourceBase;
     private String _themePath;
@@ -80,11 +76,6 @@ public class I2PSnarkServlet extends DefaultServlet {
             configFile = "i2psnark.config";
         _manager.loadConfig(configFile);
         _manager.start();
-        _umgr = _context.updateManager();
-        if (_umgr != null) {
-            _uhandler = new UpdateHandler(_context, _umgr, _manager);
-            _umgr.register(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT, 10);
-        }
         try {
             _resourceBase = Resource.newResource(_manager.getDataDir().getAbsolutePath());
         } catch (IOException ioe) {}
@@ -95,10 +86,6 @@ public class I2PSnarkServlet extends DefaultServlet {
     public void destroy() {
         if (_manager != null)
             _manager.stop();
-        if (_umgr != null && _uhandler != null) {
-            //_uhandler.shutdown();
-            _umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
-        }
         super.destroy();
     }
 
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 1f680fbf6d..5386554954 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java
@@ -62,7 +62,7 @@ public class ConsoleUpdateManager implements UpdateManager {
     /** active updating tasks, pointing to the next ones to try */
     private final Map<UpdateTask, List<RegisteredUpdater>> _downloaders;
     /** as reported by checkers */
-    private final Map<UpdateItem, VersionAvailable> _available;
+    private final ConcurrentHashMap<UpdateItem, VersionAvailable> _available;
     /** downloaded but NOT installed */
     private final Map<UpdateItem, Version> _downloaded;
     /** downloaded AND installed */
@@ -406,15 +406,19 @@ public class ConsoleUpdateManager implements UpdateManager {
     /**
      *  Install a plugin. Non-blocking.
      *  If returns true, then call isUpdateInProgress() in a loop
+     *  @param name if null, a new install
      *  @return true if task started
      */
-    public boolean installPlugin(URI uri) {
-        String fakeName = Long.toString(_context.random().nextLong());
+    public boolean installPlugin(String name, URI uri) {
+        if (name == null)
+            name = Long.toString(_context.random().nextLong());
         List<URI> uris = Collections.singletonList(uri);
-        UpdateItem fake = new UpdateItem(PLUGIN_INSTALL, fakeName);
+        UpdateItem item = new UpdateItem(PLUGIN_INSTALL, name);
         VersionAvailable va = new VersionAvailable("", "", HTTP, uris);
-        _available.put(fake, va);
-        return update(PLUGIN_INSTALL, fakeName);
+        _available.putIfAbsent(item, va);
+        if (_log.shouldLog(Log.WARN))
+            _log.warn("Install plugin: " + name + ' ' + va);
+        return update(PLUGIN_INSTALL, name);
     }
 
     /**
@@ -479,8 +483,11 @@ public class ConsoleUpdateManager implements UpdateManager {
         List<URI> updateSources = null;
         UpdateItem ui = new UpdateItem(type, id);
         VersionAvailable va = _available.get(ui);
-        if (va == null)
+        if (va == null) {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("No version available for: " + type + ' ' + id);
             return false;
+        }
         List<RegisteredUpdater> sorted = new ArrayList(_registeredUpdaters);
         Collections.sort(sorted);
         return retry(ui, va.sourceMap, sorted, maxTime) != null;
@@ -505,14 +512,21 @@ public class ConsoleUpdateManager implements UpdateManager {
                     if (t != null) {
                         // race window here
                         //  store the remaining ones for retrying
-                         if (_log.shouldLog(Log.INFO))
-                             _log.info("Starting " + r);
+                        if (_log.shouldLog(Log.INFO))
+                            _log.info("Starting " + r);
                         _downloaders.put(t, toTry);
                         return t;
+                    } else {
+                        if (_log.shouldLog(Log.WARN))
+                            _log.warn("Updater refused: " + r + " for " + meth + ' ' + e.getValue());
                     }
                 }
             }
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Nothing left to try for: " + r);
         }
+        if (_log.shouldLog(Log.WARN))
+            _log.warn("Nothing left to try for: " + ui);
         return null;
     }
 
@@ -1097,7 +1111,7 @@ public class ConsoleUpdateManager implements UpdateManager {
 
         @Override
         public String toString() {
-            return "RegisteredUpdater " + updater.getClass().getSimpleName() + " for " + type + ' ' + method + " @pri " + priority;
+            return "RegisteredUpdater " + updater.getClass() + " for " + type + ' ' + method + " @pri " + priority;
         }
     }
 
@@ -1138,7 +1152,7 @@ public class ConsoleUpdateManager implements UpdateManager {
 
         @Override
         public String toString() {
-            return "RegisteredChecker " + checker.getClass().getSimpleName() + " for " + type + ' ' + method + " @pri " + priority;
+            return "RegisteredChecker " + checker.getClass() + " for " + type + ' ' + method + " @pri " + priority;
         }
     }
 
@@ -1206,7 +1220,7 @@ public class ConsoleUpdateManager implements UpdateManager {
 
         @Override
         public String toString() {
-            return "VersionAvailable " + version + ' ' + sourceMap;
+            return "VersionAvailable \"" + version + "\" " + sourceMap;
         }
     }
 }
diff --git a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateHandler.java
index 59a2edc417..3f38724efd 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateHandler.java
@@ -70,10 +70,9 @@ class PluginUpdateHandler implements Checker, Updater {
             return null;
         Properties props = PluginStarter.pluginProperties(_context, appName);
         String oldVersion = props.getProperty("version");
-        String xpi2pURL = props.getProperty("updateURL");
-        if (oldVersion == null || xpi2pURL == null) {
-            //updateStatus("<b>" + _("Cannot check, plugin {0} is not installed", appName) + "</b>");
-            return null;
+        if (oldVersion == null) {
+            // assume new install
+            oldVersion = "0";
         }
 
         UpdateRunner update = new PluginUpdateRunner(_context, _mgr, updateSources, appName, oldVersion);
diff --git a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
index 03e385abe1..ddf4a75a3b 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java
@@ -111,6 +111,8 @@ class PluginUpdateRunner extends UpdateRunner {
                     _log.error("Error downloading plugin", t);
                 }
             }
+            if (!_updated)
+                _mgr.notifyTaskFailed(this, "", null);
         }
 
         @Override
diff --git a/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java
index bf9b2d4de9..813713220c 100644
--- a/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java
+++ b/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java
@@ -167,6 +167,7 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Attempt failed on " + url, cause);
         // ignored
+        _mgr.notifyAttemptFailed(this, url, null);
     }
 
     /** subclasses should override */
@@ -204,10 +205,12 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
     /** subclasses should override */
     public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
         // don't display bytesTransferred as it is meaningless
-        _log.error("Update from " + url + " did not download completely (" +
+        if (_log.shouldLog(Log.WARN))
+            _log.warn("Update from " + url + " did not download completely (" +
                            bytesRemaining + " remaining after " + currentAttempt + " tries)");
         updateStatus("<b>" + _("Transfer failed from {0}", linkify(url)) + "</b>");
-        _mgr.notifyTaskFailed(this, "", null);
+        _mgr.notifyAttemptFailed(this, url, null);
+        // update() will call notifyTaskFailed() after last URL
     }
 
     public void headerReceived(String url, int attemptNum, String key, String val) {}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java
index 06f87e377f..038d61d1bc 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java
@@ -322,7 +322,7 @@ public class ConfigClientsHandler extends FormHandler {
             addFormError(_("No plugin URL specified."));
             return;
         }
-        installPlugin(url);
+        installPlugin(null, url);
     }
 
     private void updatePlugin(String app) {
@@ -332,7 +332,7 @@ public class ConfigClientsHandler extends FormHandler {
             addFormError(_("No update URL specified for {0}",app));
             return;
         }
-        installPlugin(url);
+        installPlugin(app, url);
     }
 
     /** @since 0.8.13 */
@@ -349,7 +349,10 @@ public class ConfigClientsHandler extends FormHandler {
         } catch (InterruptedException ie) {}
     }
 
-    private void installPlugin(String url) {
+    /**
+     *  @param app null for a new install
+     */
+    private void installPlugin(String app, String url) {
         ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
         if (mgr == null) {
             addFormError("Update manager not registered, cannot install");
@@ -366,7 +369,7 @@ public class ConfigClientsHandler extends FormHandler {
             addFormError(_("Bad URL {0}", url));
             return;
         }
-        if (mgr.installPlugin(uri))
+        if (mgr.installPlugin(app, uri))
             addFormNotice(_("Downloading plugin from {0}", url));
         else
             addFormError("Cannot install, check logs");
-- 
GitLab