Changeset e62b76d


Ignore:
Timestamp:
Jun 18, 2012 10:09:45 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
4a1b839
Parents:
273d739
Message:

Big refactor of the router console update subsystem, in preparation for
implementing out-of-console updaters like i2psnark.

  • Add new update interfaces in net.i2p.update
  • All update implementations moved to routerconsole update/
  • Implement an UpdateManager? that registers with the RouterContext?
  • UpdateManager? handles multiple types of things to update (router, plugins, news, …) and methods of updating (HTTP, …)
  • UpdateManager? maintains list of installed, downloaded, and available versions of everything
  • Define Updaters that can check for a new version and/or download an item
  • Individual Updaters register with the UpdateManager? obtained from I2PAppContext, identifying the type of update item and update method they can handle.
  • Updaters need only core libs, no router.jar or routerconsole access required.
  • All checks and updates are initiated via the UpdateManager?.
  • All status on checks and updates in-progress or completed are obtained from the UpdateManager?. No more use of System properties to broadcast update state.
  • All update and checker tasks are intantiated on demand and threaded; no more static references left over.
  • Split out the Runners and Checkers from the Handlers and make the inheritance more sane.
  • No more permanent NewsFetcher? thread; run on the SimpleScheduler? queue and thread a checker task only to fetch the news.
  • No more static NewsFetcher? instance in routerconsole. All helper methods that are still required are moved to NewsHelper?.

The UpdateManager? implements the policy for when to check and download.
All requests go through the UpdateManager?.

For each update type, there's several parts:

  • The xxxUpdateHandler implements the Updater
  • The xxxUpdateChecker implements the UpdateTask? for checking
  • The xxxUpdateRunner implements the UpdateTask? for downloading

New and moved classes:

web/ update/


new ConsoleUpdateManager?.java

new PluginUpdateChecker?.java from PluginUpdateChecker?
PluginUpdateChecker?PluginUpdateHandler?.java
PluginUpdateHandler?.java → PluginUpdateRunner?

new UnsignedUpdateHandler?.java
UnsignedUpdateHandler?UnsignedUpdateRunner?.java
new UnsignedUpdateChecker? from NewsFetcher?

UpdateHandler?.java remains
new UpdateHandler?.java
new UpdateRunner?.java from UpdateHandler?

move NewsHandler? from NewsFetcher?
new NewsFetcher?
new NewsTimerTask?

new DummyHandler?

Initial checkin. Unfinished, untested, unpolished.

Files:
19 added
3 deleted
16 edited
1 moved

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java

    r273d739 re62b76d  
    1 package net.i2p.router.web;
     1package net.i2p.router.update;
    22
    33import java.io.File;
    44import java.io.IOException;
     5import java.net.URI;
     6import java.util.List;
    57import java.util.Map;
    68import java.util.Properties;
     
    1012import net.i2p.data.DataHelper;
    1113import net.i2p.router.RouterContext;
     14import net.i2p.router.web.ConfigClientsHelper;
     15import net.i2p.router.web.ConfigUpdateHandler;
     16import net.i2p.router.web.LogsHelper;
     17import net.i2p.router.web.Messages;
     18import net.i2p.router.web.PluginStarter;
     19import net.i2p.update.*;
    1220import net.i2p.util.EepGet;
    1321import net.i2p.util.FileUtil;
     
    2028import net.i2p.util.VersionComparator;
    2129
     30
    2231/**
    23  * Download and install a plugin.
     32 * Check for an updated version of a plugin.
    2433 * A plugin is a standard .sud file with a 40-byte signature,
    2534 * a 16-byte version, and a .zip file.
    26  * Unlike for router updates, we need not have the public key
    27  * for the signature in advance.
    2835 *
    29  * The zip file must have a standard directory layout, with
    30  * a plugin.config file at the top level.
    31  * The config file contains properties for the package name, version,
    32  * signing public key, and other settings.
    33  * The zip file will typically contain a webapps/ or lib/ dir,
    34  * and a webapps.config and/or clients.config file.
     36 * So we get the current version and update URL for the installed plugin,
     37 * then fetch the first 56 bytes of the URL, extract the version,
     38 * and compare.
    3539 *
    36  * @since 0.7.12
    37  * @author zzz
     40 * Moved from web/ and turned into an UpdateTask.
     41 *
     42 * @since 0.9.2 moved from PluginUpdateHandler
    3843 */
    39 public class PluginUpdateHandler extends UpdateHandler {
    40     private static PluginUpdateRunner _pluginUpdateRunner;
    41     private String _xpi2pURL;
    42     private String _appStatus;
    43     private volatile boolean _updated;
     44class PluginUpdateRunner extends UpdateRunner {
     45
     46    private String _appName;
     47    private final String _oldVersion;
     48    private final URI _uri;
     49    private final String _xpi2pURL;
     50    private boolean _updated;
    4451
    4552    private static final String XPI2P = "app.xpi2p";
    4653    private static final String ZIP = XPI2P + ".zip";
    47     public static final String PLUGIN_DIR = "plugins";
    48 
    49     private static PluginUpdateHandler _instance;
    50     public static final synchronized PluginUpdateHandler getInstance(RouterContext ctx) {
    51         if (_instance != null)
    52             return _instance;
    53         _instance = new PluginUpdateHandler(ctx);
    54         return _instance;
     54    public static final String PLUGIN_DIR = PluginStarter.PLUGIN_DIR;
     55
     56    public PluginUpdateRunner(RouterContext ctx, List<URI> uris, String appName, String oldVersion ) {
     57        super(ctx, uris);
     58        if (uris.isEmpty())
     59            _uri = null;
     60        else
     61            _uri = uris.get(0);
     62        _xpi2pURL = _uri.toString();
     63        _appName = appName;
     64        _oldVersion = oldVersion;
    5565    }
    5666
    57     private PluginUpdateHandler(RouterContext ctx) {
    58         super(ctx);
    59         _appStatus = "";
     67
     68    @Override
     69    public UpdateType getType() {
     70        return _oldVersion.equals("") ? UpdateType.PLUGIN_INSTALL : UpdateType.PLUGIN;
    6071    }
    6172
    62     public void update(String xpi2pURL) {
    63         // don't block waiting for the other one to finish
    64         if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS))) {
    65             _log.error("Update already running");
    66             return;
    67         }
    68         synchronized (UpdateHandler.class) {
    69             if (_pluginUpdateRunner == null)
    70                 _pluginUpdateRunner = new PluginUpdateRunner(_xpi2pURL);
    71             if (_pluginUpdateRunner.isRunning())
    72                 return;
    73             _xpi2pURL = xpi2pURL;
    74             _updateFile = (new File(_context.getTempDir(), "tmp" + _context.random().nextInt() + XPI2P)).getAbsolutePath();
    75             System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
    76             I2PAppThread update = new I2PAppThread(_pluginUpdateRunner, "AppDownload");
    77             update.start();
    78         }
    79     }
    80 
    81     public String getAppStatus() {
    82         return _appStatus;
    83     }
    84 
    85     public boolean isRunning() {
    86         return _pluginUpdateRunner != null && _pluginUpdateRunner.isRunning();
    87     }
    88 
    8973    @Override
    90     public boolean isDone() {
    91         // FIXME
    92         return false;
    93     }
    94 
    95     /** @since 0.8.13 */
    96     public boolean wasUpdateSuccessful() {
    97         return _updated;
    98     }
    99 
    100     private void scheduleStatusClean(String msg) {
    101         SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 20*60*1000);
    102     }
    103 
    104     private class Cleaner implements SimpleTimer.TimedEvent {
    105         private final String _msg;
    106         public Cleaner(String msg) {
    107             _msg = msg;
    108         }
    109         public void timeReached() {
    110             if (_msg.equals(getStatus()))
    111                 updateStatus("");
    112         }
    113     }
    114 
    115     public class PluginUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
    116 
    117         public PluginUpdateRunner(String url) {
    118             super();
    119         }
     74    public URI getURI() { return _uri; }
    12075
    12176        @Override
    12277        protected void update() {
     78
    12379            _updated = false;
    12480            if(_xpi2pURL.startsWith("file://")) {
     
    155111                }
    156112            }
    157         }
    158 
    159         @Override
    160         public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
    161             StringBuilder buf = new StringBuilder(64);
    162             buf.append("<b>").append(_("Downloading plugin")).append(' ');
    163             double pct = ((double)alreadyTransferred + (double)currentWrite) /
    164                          ((double)alreadyTransferred + (double)currentWrite + bytesRemaining);
    165             synchronized (_pct) {
    166                 buf.append(_pct.format(pct));
    167             }
    168             buf.append(": ");
    169             buf.append(_("{0}B transferred", DataHelper.formatSize2(currentWrite + alreadyTransferred)));
    170             buf.append("</b>");
    171             updateStatus(buf.toString());
    172113        }
    173114
     
    469410        private void statusDone(String msg) {
    470411            updateStatus(msg);
    471             scheduleStatusClean(msg);
    472412        }
    473413
    474     }
    475 
    476     @Override
    477     protected void updateStatus(String s) {
    478         super.updateStatus(s);
    479         _appStatus = s;
    480     }
    481414}
    482415
  • apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java

    r273d739 re62b76d  
    5757        // Protected with nonce in css.jsi
    5858        if (val != null)
    59             NewsFetcher.getInstance(_context).showNews(val.equals("1"));
     59            NewsHelper.showNews(_context, val.equals("1"));
    6060    }
    6161
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java

    r273d739 re62b76d  
    22
    33import java.io.File;
     4import java.net.URI;
     5import java.net.URISyntaxException;
    46import java.util.HashMap;
    57import java.util.Iterator;
     
    1315import net.i2p.router.startup.ClientAppConfig;
    1416import net.i2p.router.startup.LoadClientAppsJob;
     17import net.i2p.router.update.ConsoleUpdateManager;
     18import static net.i2p.update.UpdateType.*;
    1519
    1620import org.mortbay.jetty.handler.ContextHandlerCollection;
     
    334338    /** @since 0.8.13 */
    335339    private void updateAllPlugins() {
    336         if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
     340        if (NewsHelper.isAnyUpdateInProgress()) {
    337341            addFormError(_("Plugin or update download already in progress."));
    338342            return;
     
    347351
    348352    private void installPlugin(String url) {
    349         if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
     353        ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
     354        if (mgr == null) {
     355            addFormError("Update manager not registered, cannot install");
     356            return;
     357        }
     358        if (mgr.isUpdateInProgress()) {
    350359            addFormError(_("Plugin or update download already in progress."));
    351360            return;
    352361        }
    353         PluginUpdateHandler puh = PluginUpdateHandler.getInstance(_context);
    354         if (puh.isRunning()) {
    355             addFormError(_("Plugin or update download already in progress."));
    356             return;
    357         }
    358         puh.update(url);
    359         addFormNotice(_("Downloading plugin from {0}", url));
     362        URI uri;
     363        try {
     364            uri = new URI(url);
     365        } catch (URISyntaxException use) {
     366            addFormError(_("Bad URL {0}", url));
     367            return;
     368        }
     369        if (mgr.installPlugin(uri))
     370            addFormNotice(_("Downloading plugin from {0}", url));
     371        else
     372            addFormError("Cannot install, check logs");
    360373        // So that update() will post a status to the summary bar before we reload
    361374        try {
     
    365378
    366379    private void checkPlugin(String app) {
    367         if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
    368             addFormError(_("Plugin or update download already in progress."));
    369             return;
    370         }
    371         PluginUpdateChecker puc = PluginUpdateChecker.getInstance(_context);
    372         if (puc.isRunning()) {
    373             addFormError(_("Plugin or update download already in progress."));
    374             return;
    375         }
    376         puc.update(app);
     380        ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
     381        if (mgr == null) {
     382            addFormError("Update manager not registered, cannot check");
     383            return;
     384        }
     385        mgr.check(PLUGIN, app);
    377386        addFormNotice(_("Checking plugin {0} for updates", app));
    378387        // So that update() will post a status to the summary bar before we reload
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java

    r273d739 re62b76d  
    294294     *  There's a lot worse things a plugin could do but...
    295295     */
    296     static String stripHTML(Properties props, String key) {
     296    public static String stripHTML(Properties props, String key) {
    297297        String orig = props.getProperty(key);
    298298        if (orig == null) return null;
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java

    r273d739 re62b76d  
    77import net.i2p.crypto.TrustedUpdate;
    88import net.i2p.data.DataHelper;
     9import net.i2p.router.update.ConsoleUpdateManager;
     10import static net.i2p.update.UpdateType.*;
    911import net.i2p.util.FileUtil;
    1012import net.i2p.util.PortMapper;
     
    8587     *  @since 0.8.13
    8688     */
    87     static int proxyPort(I2PAppContext ctx) {
     89    public static int proxyPort(I2PAppContext ctx) {
    8890        return ctx.getProperty(PROP_PROXY_PORT,
    8991                               ctx.portMapper().getPort(PortMapper.SVC_HTTP_PROXY, DEFAULT_PROXY_PORT_INT));
     
    9597            return;
    9698        if (_action.equals(_("Check for updates"))) {
    97             NewsFetcher fetcher = NewsFetcher.getInstance(_context);
    98             fetcher.fetchNews();
    99             if (fetcher.shouldFetchUnsigned())
    100                 fetcher.fetchUnsignedHead();
    101             if (fetcher.updateAvailable() || fetcher.unsignedUpdateAvailable()) {
     99            ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
     100            if (mgr == null) {
     101                addFormError("Update manager not registered, cannot check");
     102                return;
     103            }
     104            boolean a1 = mgr.checkAvailable(NEWS, 60*1000) != null;
     105            boolean a2 = false;
     106            if ((!a1) && _updateUnsigned && _zipURL != null && _zipURL.length() > 0)
     107                a2 = mgr.checkAvailable(ROUTER_UNSIGNED, 60*1000) != null;
     108            if (a1 || a2) {
    102109                if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) )
    103110                    addFormNotice(_("Update available, attempting to download now"));
     
    119126            if ( (oldURL == null) || (!_newsURL.equals(oldURL)) ) {
    120127                changes.put(PROP_NEWS_URL, _newsURL);
    121                 NewsFetcher.getInstance(_context).invalidateNews();
     128                // this invalidates the news
     129                changes.put(NewsHelper.PROP_LAST_CHECKED, "0");
    122130                addFormNotice(_("Updating news URL to {0}", _newsURL));
    123131            }
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java

    r273d739 re62b76d  
    1515    public void setContextId(String contextId) {
    1616        super.setContextId(contextId);
    17         _dontInstall = NewsFetcher.getInstance(_context).dontInstall();
     17        _dontInstall = NewsHelper.dontInstall(_context);
    1818    }
    1919
     
    161161
    162162    public String getNewsStatus() {
    163         return NewsFetcher.getInstance(_context).status();
     163        return NewsHelper.status(_context);
    164164    }
    165165}
  • apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java

    r273d739 re62b76d  
    6161
    6262        // plugins
    63         File pluginDir = new File(_context.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR);
     63        File pluginDir = new File(_context.getConfigDir(), PluginStarter.PLUGIN_DIR);
    6464        File[] files = pluginDir.listFiles();
    6565        if (files != null) {
  • apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java

    r273d739 re62b76d  
    2121
    2222    /** @since 0.8.13 */
    23     static String jettyVersion() {
     23    public static String jettyVersion() {
    2424        return Server.getVersion();
    2525    }
  • apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java

    r273d739 re62b76d  
    22
    33import java.io.File;
     4
     5import net.i2p.data.DataHelper;
     6import net.i2p.router.RouterContext;
     7import net.i2p.router.update.ConsoleUpdateManager;
     8import static net.i2p.update.UpdateType.*;
    49
    510/**
     
    1116public class NewsHelper extends ContentHelper {
    1217   
     18    public static final String PROP_LAST_UPDATE_TIME = "router.updateLastDownloaded";
     19    /** @since 0.8.12 */
     20    private static final String PROP_LAST_HIDDEN = "routerconsole.newsLastHidden";
     21    /** @since 0.9.2 */
     22    public static final String PROP_LAST_CHECKED = "routerconsole.newsLastChecked";
     23    /** @since 0.9.2 */
     24    public static final String PROP_LAST_UPDATED = "routerconsole.newsLastUpdated";
     25    public static final String NEWS_FILE = "docs/news.xml";
     26
     27    /**
     28     *  If ANY update is in progress.
     29     *  @since 0.9.2 was stored in system properties
     30     */
     31    public static boolean isAnyUpdateInProgress() {
     32        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     33        if (mgr == null) return false;
     34        return mgr.isUpdateInProgress();
     35    }
     36
     37    /**
     38     *  If a signed or unsigned router update is in progress.
     39     *  Does NOT cover plugins, news, etc.
     40     *  @since 0.9.2 was stored in system properties
     41     */
     42    public static boolean isUpdateInProgress() {
     43        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     44        if (mgr == null) return false;
     45        return mgr.isUpdateInProgress(ROUTER_SIGNED) ||
     46               mgr.isUpdateInProgress(ROUTER_UNSIGNED) ||
     47               mgr.isUpdateInProgress(TYPE_DUMMY);
     48    }
     49
     50    /**
     51     *  @since 0.9.2 moved from NewsFetcher
     52     */
     53    public static boolean isUpdateAvailable() {
     54        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     55        if (mgr == null) return false;
     56        return mgr.getUpdateAvailable(ROUTER_SIGNED) != null;
     57    }
     58
     59    /**
     60     *  @return null if none
     61     *  @since 0.9.2 moved from NewsFetcher
     62     */
     63    public static String updateVersion() {
     64        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     65        if (mgr == null) return null;
     66        return mgr.getUpdateAvailable(ROUTER_SIGNED);
     67    }
     68
     69    /**
     70     *  @since 0.9.2 moved from NewsFetcher
     71     */
     72    public static boolean isUnsignedUpdateAvailable() {
     73        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     74        if (mgr == null) return false;
     75        return mgr.getUpdateAvailable(ROUTER_UNSIGNED) != null;
     76    }
     77
     78    /**
     79     *  @return null if none
     80     *  @since 0.9.2 moved from NewsFetcher
     81     */
     82    public static String unsignedUpdateVersion() {
     83        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     84        if (mgr == null) return null;
     85        return mgr.getUpdateAvailable(ROUTER_UNSIGNED);
     86    }
     87
     88    /**
     89     *  @return "" if none
     90     *  @since 0.9.2 moved from UpdateHelper
     91     */
     92    public static String getUpdateStatus() {
     93        ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
     94        if (mgr == null) return "";
     95        return mgr.getStatus();
     96    }
     97
    1398    @Override
    1499    public String getContent() {
     
    19104    }
    20105
    21     /** @since 0.8.12 */
     106    /**
     107     *  Is the news newer than the last time it was hidden?
     108     *  @since 0.8.12
     109     */
    22110    public boolean shouldShowNews() {
    23         return NewsFetcher.getInstance(_context).shouldShowNews();
     111        return shouldShowNews(_context);
     112    }
     113
     114    /**
     115     *  @since 0.9.2
     116     */
     117    public static boolean shouldShowNews(RouterContext ctx) {
     118         long lastUpdated = lastUpdated(ctx);
     119        if (lastUpdated <= 0)
     120            return true;
     121        String h = ctx.getProperty(PROP_LAST_HIDDEN);
     122        if (h == null)
     123            return true;
     124        long last = 0;
     125        try {
     126            last = Long.parseLong(h);
     127        } catch (NumberFormatException nfe) {}
     128        return lastUpdated > last;
     129    }
     130
     131    /**
     132     *  Save config with the timestamp of the current news to hide, or 0 to show
     133     *  @since 0.8.12
     134     */
     135    public void showNews(boolean yes) {
     136        showNews(_context, yes);
     137    }
     138
     139    /**
     140     *  Save config with the timestamp of the current news to hide, or 0 to show
     141     *  @since 0.9.2
     142     */
     143    public static void showNews(RouterContext ctx, boolean yes) {
     144         long lastUpdated = 0;
     145/////// FIME from props, or from last mod time?
     146        long stamp = yes ? 0 : lastUpdated;
     147        ctx.router().saveConfig(PROP_LAST_HIDDEN, Long.toString(stamp));
     148    }
     149
     150    /**
     151     *  @return HTML
     152     *  @since 0.9.2 moved from NewsFetcher
     153     */
     154    public String status() {
     155        return status(_context);
     156    }
     157
     158    /**
     159     *  @return HTML
     160     *  @since 0.9.2 moved from NewsFetcher
     161     */
     162    public static String status(RouterContext ctx) {
     163         StringBuilder buf = new StringBuilder(128);
     164         long now = ctx.clock().now();
     165         buf.append("<i>");
     166         long lastUpdated = lastUpdated(ctx);
     167         long lastFetch = lastChecked(ctx);
     168         if (lastUpdated > 0) {
     169             buf.append(Messages.getString("News last updated {0} ago.",
     170                                           DataHelper.formatDuration2(now - lastUpdated),
     171                                           ctx))
     172                .append('\n');
     173         }
     174         if (lastFetch > lastUpdated) {
     175             buf.append(Messages.getString("News last checked {0} ago.",
     176                                           DataHelper.formatDuration2(now - lastFetch),
     177                                           ctx));
     178         }
     179         buf.append("</i>");
     180         String consoleNonce = System.getProperty("router.consoleNonce");
     181         if (lastUpdated > 0 && consoleNonce != null) {
     182             if (shouldShowNews(ctx)) {
     183                 buf.append(" <a href=\"/?news=0&amp;consoleNonce=").append(consoleNonce).append("\">")
     184                    .append(Messages.getString("Hide news", ctx));
     185             } else {
     186                 buf.append(" <a href=\"/?news=1&amp;consoleNonce=").append(consoleNonce).append("\">")
     187                    .append(Messages.getString("Show news", ctx));
     188             }
     189             buf.append("</a>");
     190         }
     191         return buf.toString();
     192    }
     193   
     194    /**
     195     *  @since 0.9.2 moved from NewsFetcher
     196     */
     197    public static boolean dontInstall(RouterContext ctx) {
     198        File test = new File(ctx.getBaseDir(), "history.txt");
     199        boolean readonly = ((test.exists() && !test.canWrite()) || (!ctx.getBaseDir().canWrite()));
     200        boolean disabled = ctx.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DISABLED);
     201        return readonly || disabled;
     202    }
     203
     204    /**
     205     *  @since 0.9.2
     206     */
     207    public static long lastChecked(RouterContext ctx) {
     208        String lc = ctx.getProperty(PROP_LAST_CHECKED);
     209        if (lc == null) {
     210            try {
     211                return Long.parseLong(lc);
     212            } catch (NumberFormatException nfe) {}
     213        }
     214        return 0;
     215    }
     216
     217    /**
     218     *  When the news was last downloaded
     219     *  @since 0.9.2
     220     */
     221    public static long lastUpdated(RouterContext ctx) {
     222        String lc = ctx.getProperty(PROP_LAST_UPDATED);
     223        if (lc == null) {
     224            try {
     225                return Long.parseLong(lc);
     226            } catch (NumberFormatException nfe) {}
     227        }
     228        File newsFile = new File(ctx.getRouterDir(), NEWS_FILE);
     229        long rv = newsFile.lastModified();
     230        ctx.router().saveConfig(PROP_LAST_UPDATED, Long.toString(rv));
     231        return rv;
    24232    }
    25233}
  • apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java

    r273d739 re62b76d  
    2626import net.i2p.router.startup.ClientAppConfig;
    2727import net.i2p.router.startup.LoadClientAppsJob;
     28import net.i2p.router.update.ConsoleUpdateManager;
     29import static net.i2p.update.UpdateType.*;
    2830import net.i2p.util.ConcurrentHashSet;
    2931import net.i2p.util.FileUtil;
     
    4648public class PluginStarter implements Runnable {
    4749    protected RouterContext _context;
    48     static final String PREFIX = "plugin.";
    49     static final String ENABLED = ".startOnLoad";
     50    public static final String PREFIX = "plugin.";
     51    public static final String ENABLED = ".startOnLoad";
     52    public static final String PLUGIN_DIR = "plugins";
    5053    private static final String[] STANDARD_WEBAPPS = { "i2psnark", "i2ptunnel", "susidns",
    5154                                                       "susimail", "addressbook", "routerconsole" };
     
    6770    public void run() {
    6871        if (_context.getBooleanPropertyDefaultTrue("plugins.autoUpdate") &&
    69             (!Boolean.valueOf(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS)).booleanValue()) &&
     72            (!NewsHelper.isUpdateInProgress()) &&
    7073            (!RouterVersion.VERSION.equals(_context.getProperty("router.previousVersion"))))
    7174            updateAll(_context, true);
     
    113116        if (toUpdate.isEmpty())
    114117            return;
    115         PluginUpdateChecker puc = PluginUpdateChecker.getInstance(ctx);
    116         if (puc.isRunning())
     118
     119        ConsoleUpdateManager mgr = (ConsoleUpdateManager) ctx.updateManager();
     120        if (mgr == null)
     121            return;
     122        if (mgr.isUpdateInProgress())
    117123            return;
    118124
    119125        if (delay) {
    120126            // wait for proxy
    121             System.setProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS, "true");
    122             puc.setAppStatus(Messages.getString("Checking for plugin updates", ctx));
    123             try {
    124                 Thread.sleep(3*60*1000);
    125             } catch (InterruptedException ie) {}
    126             System.setProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS, "false");
     127            mgr.update(TYPE_DUMMY, 3*60*1000);
     128            mgr.notifyProgress(null, Messages.getString("Checking for plugin updates", ctx));
     129            int loop = 0;
     130            do {
     131                try {
     132                    Thread.sleep(5*1000);
     133                } catch (InterruptedException ie) {}
     134                if (loop++ > 40) break;
     135            } while (mgr.isUpdateInProgress(TYPE_DUMMY));
    127136        }
    128137
     
    133142            if (log.shouldLog(Log.WARN))
    134143                log.warn("Checking for update plugin: " + appName);
    135             puc.update(appName);
     144
     145            // blocking
     146            if (mgr.checkAvailable(PLUGIN, appName, 60*1000) == null) {
     147                if (log.shouldLog(Log.WARN))
     148                    log.warn("No update available for plugin: " + appName);
     149                continue;
     150            }
     151
     152            if (log.shouldLog(Log.WARN))
     153                log.warn("Updating plugin: " + appName);
     154            mgr.update(PLUGIN, appName, 30*60*1000);
     155            int loop = 0;
    136156            do {
    137157                try {
    138158                    Thread.sleep(5*1000);
    139159                } catch (InterruptedException ie) {}
    140             } while (puc.isRunning());
    141             if (!puc.isNewerAvailable()) {
    142                 if (log.shouldLog(Log.WARN))
    143                     log.warn("No update available for plugin: " + appName);
    144                 continue;
    145             }
    146             PluginUpdateHandler puh = PluginUpdateHandler.getInstance(ctx);
    147             String url = entry.getValue();
    148             if (log.shouldLog(Log.WARN))
    149                 log.warn("Updating plugin: " + appName);
    150             puh.update(url);
    151             do {
    152                 try {
    153                     Thread.sleep(5*1000);
    154                 } catch (InterruptedException ie) {}
    155             } while (puh.isRunning());
    156             if (puh.wasUpdateSuccessful())
     160                if (loop++ > 40) break;
     161            } while (mgr.isUpdateInProgress(PLUGIN, appName));
     162
     163            if (mgr.getUpdateAvailable(PLUGIN, appName) != null)
    157164                updated++;
    158165        }
    159166        if (updated > 0)
    160             puc.setDoneStatus(ngettext("1 plugin updated", "{0} plugins updated", updated, ctx));
     167            mgr.notifyComplete(null, ngettext("1 plugin updated", "{0} plugins updated", updated, ctx));
    161168        else
    162             puc.setDoneStatus(Messages.getString("Plugin update check complete", ctx));
     169            mgr.notifyComplete(null, Messages.getString("Plugin update check complete", ctx));
    163170    }
    164171
     
    190197     *  @throws just about anything, caller would be wise to catch Throwable
    191198     */
    192     static boolean startPlugin(RouterContext ctx, String appName) throws Exception {
     199    public static boolean startPlugin(RouterContext ctx, String appName) throws Exception {
    193200        Log log = ctx.logManager().getLog(PluginStarter.class);
    194         File pluginDir = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
     201        File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    195202        if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
    196203            log.error("Cannot start nonexistent plugin: " + appName);
     
    200207
    201208        // Do we need to extract an update?
    202         File pluginUpdate = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip" );
     209        File pluginUpdate = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName + "/app.xpi2p.zip" );
    203210        if(pluginUpdate.exists()) {
    204211            // Compare the start time of the router with the plugin.
     
    364371     *  @throws just about anything, caller would be wise to catch Throwable
    365372     */
    366     static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
     373    public static boolean stopPlugin(RouterContext ctx, String appName) throws Exception {
    367374        Log log = ctx.logManager().getLog(PluginStarter.class);
    368         File pluginDir = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
     375        File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    369376        if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
    370377            log.error("Cannot stop nonexistent plugin: " + appName);
     
    425432    static boolean deletePlugin(RouterContext ctx, String appName) throws Exception {
    426433        Log log = ctx.logManager().getLog(PluginStarter.class);
    427         File pluginDir = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
     434        File pluginDir = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName);
    428435        if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
    429436            log.error("Cannot delete nonexistent plugin: " + appName);
     
    470477    /** plugin.config */
    471478    public static Properties pluginProperties(I2PAppContext ctx, String appName) {
    472         File cfgFile = new File(ctx.getConfigDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + '/' + "plugin.config");
     479        File cfgFile = new File(ctx.getConfigDir(), PLUGIN_DIR + '/' + appName + '/' + "plugin.config");
    473480        Properties rv = new Properties();
    474481        try {
     
    531538    public static List<String> getPlugins() {
    532539        List<String> rv = new ArrayList();
    533         File pluginDir = new File(I2PAppContext.getGlobalContext().getConfigDir(), PluginUpdateHandler.PLUGIN_DIR);
     540        File pluginDir = new File(I2PAppContext.getGlobalContext().getConfigDir(), PLUGIN_DIR);
    534541        File[] files = pluginDir.listFiles();
    535542        if (files == null)
  • apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java

    r273d739 re62b76d  
    2828import net.i2p.data.DataHelper;
    2929import net.i2p.router.RouterContext;
     30import net.i2p.router.update.ConsoleUpdateManager;
    3031import net.i2p.util.Addresses;
    3132import net.i2p.util.FileUtil;
     
    539540            RouterContext ctx = contexts.get(0);
    540541
    541             NewsFetcher fetcher = NewsFetcher.getInstance(ctx);
    542             Thread newsThread = new I2PAppThread(fetcher, "NewsFetcher", true);
    543             newsThread.setPriority(Thread.NORM_PRIORITY - 1);
    544             newsThread.start();
     542            ConsoleUpdateManager um = new ConsoleUpdateManager(ctx);
     543            um.start();
    545544       
    546545            if (PluginStarter.pluginsEnabled(ctx)) {
     
    550549                ctx.addShutdownTask(new PluginStopper(ctx));
    551550            }
    552             ctx.addShutdownTask(new NewsShutdown(fetcher, newsThread));
    553551            // stat summarizer registers its own hook
    554552            ctx.addShutdownTask(new ServerShutdown());
     
    722720    }
    723721   
    724     /** @since 0.8.8 */
    725     private static class NewsShutdown implements Runnable {
    726         private final NewsFetcher _fetcher;
    727         private final Thread _newsThread;
    728 
    729         public NewsShutdown(NewsFetcher fetcher, Thread t) {
    730             _fetcher = fetcher;
    731             _newsThread = t;
    732         }
    733 
    734         public void run() {
    735             _fetcher.shutdown();
    736             _newsThread.interrupt();
    737         }
    738     }
    739 
    740722    public static Properties webAppProperties() {
    741723        return webAppProperties(I2PAppContext.getGlobalContext().getConfigDir().getAbsolutePath());
  • apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java

    r273d739 re62b76d  
    595595
    596596    public boolean updateAvailable() {
    597         return NewsFetcher.getInstance(_context).updateAvailable();
     597        return NewsHelper.isUpdateAvailable();
    598598    }
    599599
    600600    public boolean unsignedUpdateAvailable() {
    601         return NewsFetcher.getInstance(_context).unsignedUpdateAvailable();
     601        return NewsHelper.isUnsignedUpdateAvailable();
    602602    }
    603603
    604604    public String getUpdateVersion() {
    605         return NewsFetcher.getInstance(_context).updateVersion();
     605        return NewsHelper.updateVersion();
    606606    }
    607607
    608608    public String getUnsignedUpdateVersion() {
    609         return NewsFetcher.getInstance(_context).unsignedUpdateVersion();
     609        return NewsHelper.unsignedUpdateVersion();
    610610    }
    611611
     
    617617        StringBuilder buf = new StringBuilder(512);
    618618        // display all the time so we display the final failure message, and plugin update messages too
    619         String status = UpdateHandler.getStatus();
     619        String status = NewsHelper.getUpdateStatus();
    620620        if (status.length() > 0) {
    621621            buf.append("<h4>").append(status).append("</h4><hr>\n");
    622622        }
    623623        if (updateAvailable() || unsignedUpdateAvailable()) {
    624             if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
     624            if (NewsHelper.isUpdateInProgress()) {
    625625                // nothing
    626626            } else if(
  • apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java

    r273d739 re62b76d  
    11package net.i2p.router.web;
    22
    3 import java.io.ByteArrayInputStream;
    4 import java.io.ByteArrayOutputStream;
    5 import java.io.File;
    6 import java.text.DecimalFormat;
    7 import java.util.ArrayList;
    8 import java.util.Collections;
    9 import java.util.List;
    10 import java.util.StringTokenizer;
    11 
    12 import net.i2p.crypto.TrustedUpdate;
    13 import net.i2p.data.DataHelper;
    14 import net.i2p.router.Router;
    153import net.i2p.router.RouterContext;
    16 import net.i2p.router.RouterVersion;
    17 import net.i2p.router.util.RFC822Date;
    18 import net.i2p.util.EepGet;
    19 import net.i2p.util.I2PAppThread;
     4import net.i2p.router.update.ConsoleUpdateManager;
     5import net.i2p.update.UpdateType;
     6import static net.i2p.update.UpdateType.*;
    207import net.i2p.util.Log;
    21 import net.i2p.util.PartialEepGet;
    22 import net.i2p.util.VersionComparator;
    238
    249/**
     
    3217 * the update process.
    3318 * </p>
     19 *
     20 * This is like a FormHandler but we don't extend it, as we don't have the message area, etc.
    3421 */
    3522public class UpdateHandler {
    36     protected static UpdateRunner _updateRunner;
    3723    protected RouterContext _context;
    3824    protected Log _log;
    39     protected String _updateFile;
    40     private static String _status = "";
    4125    private String _action;
    4226    private String _nonce;
    4327   
    44     protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
    45     static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress";
    46     protected static final String PROP_LAST_UPDATE_TIME = "router.updateLastDownloaded";
    47 
    4828    public UpdateHandler() {
    4929        this(ContextHelper.getContext(null));
    5030    }
     31
    5132    public UpdateHandler(RouterContext ctx) {
    5233        _context = ctx;
    5334        _log = ctx.logManager().getLog(UpdateHandler.class);
    54         _updateFile = (new File(ctx.getRouterDir(), SIGNED_UPDATE_FILE)).getAbsolutePath();
    5535    }
    5636   
     
    8666            _nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) {
    8767            if (_action.contains("Unsigned")) {
    88                 // Not us, have NewsFetcher instantiate the correct class.
    89                 NewsFetcher fetcher = NewsFetcher.getInstance(_context);
    90                 fetcher.fetchUnsigned();
     68                update(ROUTER_UNSIGNED);
    9169            } else {
    92                 update();
     70                update(ROUTER_SIGNED);
    9371            }
    9472        }
    9573    }
    9674
    97     public void update() {
    98         // don't block waiting for the other one to finish
    99         if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS))) {
     75    private void update(UpdateType type) {
     76        ConsoleUpdateManager mgr = (ConsoleUpdateManager) _context.updateManager();
     77        if (mgr == null)
     78            return;
     79        if (mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_UNSIGNED)) {
    10080            _log.error("Update already running");
    10181            return;
    10282        }
    103         synchronized (UpdateHandler.class) {
    104             if (_updateRunner == null)
    105                 _updateRunner = new UpdateRunner();
    106             if (_updateRunner.isRunning()) {
    107                 return;
    108             } else {
    109                 System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
    110                 I2PAppThread update = new I2PAppThread(_updateRunner, "SignedUpdate");
    111                 update.start();
    112             }
    113         }
     83        mgr.update(type);
    11484    }
    115    
    116     public static String getStatus() {
    117         return _status;
    118     }
    119    
    120     public boolean isDone() {
    121         return false;
    122         // this needs to be fixed and tested
    123         //if(this._updateRunner == null)
    124         //    return true;
    125         //return this._updateRunner.isDone();
    126     }
    127    
    128     public class UpdateRunner implements Runnable, EepGet.StatusListener {
    129         protected volatile boolean _isRunning;
    130         protected boolean done;
    131         protected EepGet _get;
    132         protected final DecimalFormat _pct = new DecimalFormat("0.0%");
    133         /** tells the listeners what mode we are in */
    134         private boolean _isPartial;
    135         /** set by the listeners on completion */
    136         private boolean _isNewer;
    137         private ByteArrayOutputStream _baos;
    138 
    139         public UpdateRunner() {
    140             _isRunning = false;
    141             this.done = false;
    142             updateStatus("<b>" + _("Updating") + "</b>");
    143         }
    144         public boolean isRunning() { return _isRunning; }
    145         public boolean isDone() {
    146             return this.done;
    147         }
    148         public void run() {
    149             _isRunning = true;
    150             update();
    151             System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
    152             _isRunning = false;
    153         }
    154 
    155         /**
    156          *  Loop through the entire list of update URLs.
    157          *  For each one, first get the version from the first 56 bytes and see if
    158          *  it is newer than what we are running now.
    159          *  If it is, get the whole thing.
    160          */
    161         protected void update() {
    162             // Do a PartialEepGet on the selected URL, check for version we expect,
    163             // and loop if it isn't what we want.
    164             // This will allows us to do a release without waiting for the last host to install the update.
    165             // Alternative: In bytesTransferred(), Check the data in the output file after
    166             // we've received at least 56 bytes. Need a cancel() method in EepGet ?
    167 
    168             boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
    169             String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    170             int proxyPort = ConfigUpdateHandler.proxyPort(_context);
    171 
    172             List<String> urls = getUpdateURLs();
    173             if (urls.isEmpty()) {
    174                 // not likely, don't bother translating
    175                 updateStatus("<b>Update source list is empty, cannot download update</b>");
    176                 _log.log(Log.CRIT, "Update source list is empty - cannot download update");
    177                 return;
    178             }
    179 
    180             if (shouldProxy)
    181                 _baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
    182             for (String updateURL : urls) {
    183                 updateStatus("<b>" + _("Updating from {0}", linkify(updateURL)) + "</b>");
    184                 if (_log.shouldLog(Log.DEBUG))
    185                     _log.debug("Selected update URL: " + updateURL);
    186 
    187                 // Check the first 56 bytes for the version
    188                 if (shouldProxy) {
    189                     _isPartial = true;
    190                     _isNewer = false;
    191                     _baos.reset();
    192                     try {
    193                         // no retries
    194                         _get = new PartialEepGet(_context, proxyHost, proxyPort, _baos, updateURL, TrustedUpdate.HEADER_BYTES);
    195                         _get.addStatusListener(UpdateRunner.this);
    196                         _get.fetch();
    197                     } catch (Throwable t) {
    198                         _isNewer = false;
    199                     }
    200                     _isPartial = false;
    201                     if (!_isNewer)
    202                         continue;
    203                 }
    204 
    205                 // Now get the whole thing
    206                 try {
    207                     if (shouldProxy)
    208                         // 40 retries!!
    209                         _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
    210                     else
    211                         _get = new EepGet(_context, 1, _updateFile, updateURL, false);
    212                     _get.addStatusListener(UpdateRunner.this);
    213                     _get.fetch();
    214                 } catch (Throwable t) {
    215                     _log.error("Error updating", t);
    216                 }
    217                 if (this.done)
    218                     break;
    219             }
    220         }
    221        
    222         // EepGet Listeners below.
    223         // We use the same for both the partial and the full EepGet,
    224         // with a couple of adjustments depending on which mode.
    225 
    226         public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
    227             _isNewer = false;
    228             if (_log.shouldLog(Log.DEBUG))
    229                 _log.debug("Attempt failed on " + url, cause);
    230             // ignored
    231         }
    232         public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
    233             if (_isPartial)
    234                 return;
    235             StringBuilder buf = new StringBuilder(64);
    236             buf.append("<b>").append(_("Updating")).append("</b> ");
    237             double pct = ((double)alreadyTransferred + (double)currentWrite) /
    238                          ((double)alreadyTransferred + (double)currentWrite + bytesRemaining);
    239             synchronized (_pct) {
    240                 buf.append(_pct.format(pct));
    241             }
    242             buf.append(":<br>\n");
    243             buf.append(_("{0}B transferred", DataHelper.formatSize2(currentWrite + alreadyTransferred)));
    244             updateStatus(buf.toString());
    245         }
    246         public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
    247             if (_isPartial) {
    248                 // Compare version with what we have now
    249                 String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
    250                 boolean newer = (new VersionComparator()).compare(newVersion, RouterVersion.VERSION) > 0;
    251                 if (!newer) {
    252                     updateStatus("<b>" + _("No new version found at {0}", linkify(url)) + "</b>");
    253                     if (_log.shouldLog(Log.WARN))
    254                         _log.warn("Found old version \"" + newVersion + "\" at " + url);
    255                 }
    256                 _isNewer = newer;
    257                 return;
    258             }
    259             // Process the .sud/.su2 file
    260             updateStatus("<b>" + _("Update downloaded") + "</b>");
    261             TrustedUpdate up = new TrustedUpdate(_context);
    262             File f = new File(_updateFile);
    263             File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
    264             String err = up.migrateVerified(RouterVersion.VERSION, f, to);
    265             f.delete();
    266             if (err == null) {
    267                 String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
    268                 this.done = true;
    269                 // So unsigned update handler doesn't overwrite unless newer.
    270                 String lastmod = _get.getLastModified();
    271                 long modtime = 0;
    272                 if (lastmod != null)
    273                     modtime = RFC822Date.parse822Date(lastmod);
    274                 if (modtime <= 0)
    275                     modtime = _context.clock().now();
    276                 _context.router().saveConfig(PROP_LAST_UPDATE_TIME, "" + modtime);
    277                 if ("install".equals(policy)) {
    278                     _log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
    279                     updateStatus("<b>" + _("Update verified") + "</b><br>" + _("Restarting"));
    280                     restart();
    281                 } else {
    282                     _log.log(Log.CRIT, "Update was VERIFIED, will be installed at next restart");
    283                     StringBuilder buf = new StringBuilder(64);
    284                     buf.append("<b>").append(_("Update downloaded")).append("<br>");
    285                     if (_context.hasWrapper())
    286                         buf.append(_("Click Restart to install"));
    287                     else
    288                         buf.append(_("Click Shutdown and restart to install"));
    289                     if (up.newVersion() != null)
    290                         buf.append(' ').append(_("Version {0}", up.newVersion()));
    291                     buf.append("</b>");
    292                     updateStatus(buf.toString());
    293                 }
    294             } else {
    295                 _log.log(Log.CRIT, err + " from " + url);
    296                 updateStatus("<b>" + err + ' ' + _("from {0}", linkify(url)) + " </b>");
    297             }
    298         }
    299         public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
    300             _isNewer = false;
    301             // don't display bytesTransferred as it is meaningless
    302             _log.error("Update from " + url + " did not download completely (" +
    303                                bytesRemaining + " remaining after " + currentAttempt + " tries)");
    304 
    305             updateStatus("<b>" + _("Transfer failed from {0}", linkify(url)) + "</b>");
    306         }
    307         public void headerReceived(String url, int attemptNum, String key, String val) {}
    308         public void attempting(String url) {}
    309     }
    310    
    311     protected void restart() {
    312         if (_context.hasWrapper())
    313             ConfigServiceHandler.registerWrapperNotifier(_context, Router.EXIT_GRACEFUL_RESTART, false);
    314         _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
    315     }
    316 
    317     private List<String> getUpdateURLs() {
    318         String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
    319         StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
    320         List<String> URLList = new ArrayList();
    321         while (tok.hasMoreTokens())
    322             URLList.add(tok.nextToken().trim());
    323         Collections.shuffle(URLList, _context.random());
    324         return URLList;
    325     }
    326    
    327     protected void updateStatus(String s) {
    328         _status = s;
    329     }
    330 
    331     protected static String linkify(String url) {
    332         return "<a target=\"_blank\" href=\"" + url + "\"/>" + url + "</a>";
    333     }
    334 
    335     /** translate a string */
    336     protected String _(String s) {
    337         return Messages.getString(s, _context);
    338     }
    339 
    340     /**
    341      *  translate a string with a parameter
    342      *  This is a lot more expensive than _(s), so use sparingly.
    343      *
    344      *  @param s string to be translated containing {0}
    345      *    The {0} will be replaced by the parameter.
    346      *    Single quotes must be doubled, i.e. ' -> '' in the string.
    347      *  @param o parameter, not translated.
    348      *    To tranlslate parameter also, use _("foo {0} bar", _("baz"))
    349      *    Do not double the single quotes in the parameter.
    350      *    Use autoboxing to call with ints, longs, floats, etc.
    351      */
    352     protected String _(String s, Object o) {
    353         return Messages.getString(s, o, _context);
    354     }
    355 
    35685}
  • apps/routerconsole/java/src/net/i2p/router/web/WebAppConfiguration.java

    r273d739 re62b76d  
    6565        // FIXME this only works if war is the same name as the plugin
    6666        File pluginDir = new File(i2pContext.getConfigDir(),
    67                                         PluginUpdateHandler.PLUGIN_DIR + ctxPath);
     67                                        PluginStarter.PLUGIN_DIR + ctxPath);
    6868
    6969        File dir = libDir;
  • core/java/src/net/i2p/I2PAppContext.java

    r273d739 re62b76d  
    2727import net.i2p.internal.InternalClientManager;
    2828import net.i2p.stat.StatManager;
     29import net.i2p.update.UpdateManager;
    2930import net.i2p.util.Clock;
    3031import net.i2p.util.ConcurrentHashSet;
     
    985986        }
    986987    }
     988
     989    /**
     990     *  The controller of router, plugin, and other updates.
     991     *  @return always null in I2PAppContext, the update manager if in RouterContext and it is registered
     992     *  @since 0.9.2
     993     */
     994    public UpdateManager updateManager() {
     995        return null;
     996    }
    987997}
  • core/java/src/net/i2p/util/VersionComparator.java

    r273d739 re62b76d  
    2323            String lNumber = lTokens.nextToken();
    2424            String rNumber = rTokens.nextToken();
    25             int diff = intCompare(lNumber, rNumber);
     25            int diff = longCompare(lNumber, rNumber);
    2626            if (diff != 0)
    2727                return diff;
     
    3535    }
    3636
    37     private static final int intCompare(String lop, String rop) {
    38         int left, right;
     37    private static final int longCompare(String lop, String rop) {
     38        long left, right;
    3939        try {
    40             left = Integer.parseInt(lop);
     40            left = Long.parseLong(lop);
    4141        } catch (NumberFormatException nfe) {
    4242            return -1;
    4343        }
    4444        try {
    45             right = Integer.parseInt(rop);
     45            right = Long.parseLong(rop);
    4646        } catch (NumberFormatException nfe) {
    4747            return 1;
    4848        }
    49         return left - right;
     49        long diff = left - right;
     50        if (diff < 0)
     51            return -1;
     52        if (diff > 0)
     53            return 1;
     54        return 0;
    5055    }
    5156
  • router/java/src/net/i2p/router/RouterContext.java

    r273d739 re62b76d  
    2323import net.i2p.router.tunnel.TunnelDispatcher;
    2424import net.i2p.router.tunnel.pool.TunnelPoolManager;
     25import net.i2p.update.UpdateManager;
    2526import net.i2p.util.KeyRing;
    2627import net.i2p.util.I2PProperties.I2PPropertyCallback;
     
    5657    private Blocklist _blocklist;
    5758    private MessageValidator _messageValidator;
     59    private UpdateManager _updateManager;
    5860    //private MessageStateMonitor _messageStateMonitor;
    5961    private RouterThrottle _throttle;
    6062    private final Set<Runnable> _finalShutdownTasks;
    6163    // split up big lock on this to avoid deadlocks
    62     private final Object _lock1 = new Object(), _lock2 = new Object();
     64    private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object();
    6365
    6466    private static List<RouterContext> _contexts = new ArrayList(1);
     
    482484     *  @since 0.7.9
    483485     */
     486    @Override
    484487    public boolean isRouterContext() {
    485488        return true;
     
    491494     *  @since 0.8.3
    492495     */
     496    @Override
    493497    public InternalClientManager internalClientManager() {
    494498        return _clientManagerFacade;
    495499    }
     500
     501    /**
     502     *  The controller of router, plugin, and other updates.
     503     *  @return The manager if it is registered, else null
     504     *  @since 0.9.2
     505     */
     506    @Override
     507    public UpdateManager updateManager() {
     508        return _updateManager;
     509    }
     510
     511    /**
     512     *  Register as the update manager.
     513     *  @throws IllegalStateException if one was already registered
     514     *  @since 0.9.2
     515     */
     516    public void registerUpdateManager(UpdateManager mgr) {
     517        synchronized(_lock3) {
     518            if (_updateManager != null)
     519                throw new IllegalStateException();
     520            _updateManager = mgr;
     521        }
     522    }
     523
     524    /**
     525     *  Unregister the update manager.
     526     *  @throws IllegalStateException if it was not registered
     527     *  @since 0.9.2
     528     */
     529    public void unregisterUpdateManager(UpdateManager mgr) {
     530        synchronized(_lock3) {
     531            if (_updateManager != mgr)
     532                throw new IllegalStateException();
     533            _updateManager = null;
     534        }
     535    }
    496536}
Note: See TracChangeset for help on using the changeset viewer.