Changeset 4db4010


Ignore:
Timestamp:
Oct 14, 2012 10:42:00 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
b9d717b
Parents:
8df2a2d (diff), 20279d1 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p' (head 2da3b585b42d058e25909bc303d72277ae2463b5)

to branch 'i2p.i2p.zzz.update' (head ebbad994215dc2822e9a1776399864ed77a0e5a0)

Files:
19 added
3 deleted
19 edited
1 moved

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/build.xml

    r8df2a2d r4db4010  
    331331            windowtitle="Router Console" />
    332332    </target>
     333
     334    <!-- scala paths -->
     335    <target name="scala.init">
     336        <property name="scala-library.jar" value="${scalatest.libs}/scala-library.jar" />
     337        <property name="scalatest.jar" value="${scalatest.libs}/scalatest.jar" />
     338        <taskdef resource="scala/tools/ant/antlib.xml">
     339            <classpath>
     340                <pathelement location="${scalatest.libs}/scala-compiler.jar" />
     341                <pathelement location="${scala-library.jar}" />
     342            </classpath>
     343        </taskdef>
     344    </target>
     345
     346    <!-- unit tests -->
     347    <target name="builddepscalatest">
     348        <ant dir="../../../router/java/" target="jar" />
     349        <ant dir="../../../router/java/" target="jarScalaTest" />
     350    </target>
     351    <target name="scalatest.compileTest" depends="builddepscalatest, compile, scala.init">
     352        <mkdir dir="./build" />
     353        <mkdir dir="./build/obj_scala" />
     354        <scalac srcdir="./test/scalatest" destdir="./build/obj_scala" deprecation="on" >
     355            <classpath>
     356                <pathelement location="${classpath}" />
     357                <pathelement location="${scala-library.jar}" />
     358                <pathelement location="${scalatest.jar}" />
     359                <pathelement location="../../../core/java/build/i2pscalatest.jar" />
     360                <pathelement location="../../../router/java/build/routerscalatest.jar" />
     361                <pathelement location="./build/obj" />
     362            </classpath>
     363        </scalac>
     364    </target>
     365    <!-- preparation of code coverage tool of choice -->
     366    <target name="prepareClover" depends="compile" if="with.clover">
     367        <taskdef resource="clovertasks"/>
     368        <mkdir dir="../../../reports/apps/routerconsole/clover" />
     369        <clover-setup initString="../../../reports/apps/routerconsole/clover/coverage.db"/>
     370    </target>
     371    <target name="prepareCobertura" depends="compile" if="with.cobertura">
     372        <taskdef classpath="${with.cobertura}" resource="tasks.properties" onerror="report" />
     373        <mkdir dir="./build/obj_cobertura" />
     374        <delete file="./cobertura.ser" />
     375        <cobertura-instrument todir="./build/obj_cobertura">
     376            <fileset dir="./build/obj">
     377                <include name="**/*.class"/>
     378                <exclude name="**/*Test.class" />
     379            </fileset>
     380        </cobertura-instrument>
     381    </target>
     382    <target name="prepareTest" depends="prepareClover, prepareCobertura" />
     383    <!-- end preparation of code coverage tool -->
     384    <target name="scalatest.test" depends="clean, scalatest.compileTest, prepareTest">
     385        <mkdir dir="../../../reports/apps/routerconsole/scalatest/" />
     386        <delete>
     387            <fileset dir="../../../reports/apps/routerconsole/scalatest">
     388                <include name="TEST-*.xml"/>
     389            </fileset>
     390        </delete>
     391        <taskdef name="scalatest" classname="org.scalatest.tools.ScalaTestAntTask">
     392            <classpath>
     393                <pathelement location="${classpath}" />
     394                <pathelement location="${scala-library.jar}" />
     395                <pathelement location="${scalatest.jar}" />
     396                <pathelement location="./build/obj_cobertura" />
     397                <pathelement location="./build/obj" />
     398                <pathelement location="${with.clover}" />
     399                <pathelement location="${with.cobertura}" />
     400            </classpath>
     401        </taskdef>
     402        <scalatest runpath="./build/obj_scala" fork="yes" maxmemory="384M">
     403            <tagsToExclude>
     404                SlowTests
     405            </tagsToExclude>
     406            <reporter type="stdout" />
     407            <reporter type="junitxml" directory="../../../reports/apps/routerconsole/scalatest/" />
     408        </scalatest>
     409        <!-- fetch the real hostname of this machine -->
     410        <exec executable="hostname" outputproperty="host.name"/>
     411        <!-- set if unset -->
     412        <property name="host.fakename" value="i2ptester" />
     413        <!-- replace hostname that junit inserts into reports with fake one -->
     414        <replace dir="../../../reports/apps/routerconsole/scalatest/" token="${host.name}" value="${host.fakename}"/>
     415    </target>
     416    <target name="test" depends="scalatest.test"/>
     417    <!-- test reports -->
     418    <target name="scalatest.report">
     419        <junitreport todir="../../../reports/apps/routerconsole/scalatest">
     420            <fileset dir="../../../reports/apps/routerconsole/scalatest">
     421                <include name="TEST-*.xml"/>
     422            </fileset>
     423            <report format="frames" todir="../../../reports/apps/routerconsole/html/scalatest"/>
     424        </junitreport>
     425    </target>
     426    <target name="clover.report" depends="test" if="with.clover">
     427        <clover-report>
     428            <current outfile="../../../reports/apps/routerconsole/html/clover">
     429                <format type="html"/>
     430            </current>
     431        </clover-report>
     432    </target>
     433    <target name="cobertura.report" depends="test" if="with.cobertura">
     434        <mkdir dir="../../../reports/apps/routerconsole/cobertura" />
     435        <cobertura-report format="xml" srcdir="./src" destdir="../../../reports/apps/routerconsole/cobertura" />
     436        <mkdir dir="../../../reports/apps/routerconsole/html/cobertura" />
     437        <cobertura-report format="html" srcdir="./src" destdir="../../../reports/apps/routerconsole/html/cobertura" />
     438        <delete file="./cobertura.ser" />
     439    </target>
     440    <target name="test.report" depends="scalatest.report, clover.report, cobertura.report"/>
     441    <!-- end test reports -->
     442    <target name="fulltest" depends="cleandep, test, test.report" />
     443    <!-- end unit tests -->
     444
    333445    <target name="clean">
    334446        <delete dir="./build" />
  • apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateRunner.java

    r8df2a2d r4db4010  
    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         _context.simpleScheduler().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://")) {
     
    14096                updateStatus("<b>" + _("Downloading plugin from {0}", _xpi2pURL) + "</b>");
    14197                // use the same settings as for updater
    142                 boolean shouldProxy = Boolean.parseBoolean(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY));
     98                boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
    14399                String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
    144100                int proxyPort = ConfigUpdateHandler.proxyPort(_context);
     
    158114
    159115        @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());
    172         }
    173 
    174         @Override
    175116        public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
    176117            boolean update = false;
     
    314255            File destDir = new SecureDirectory(appDir, appName);
    315256            if (destDir.exists()) {
    316                 if (Boolean.parseBoolean(props.getProperty("install-only"))) {
     257                if (Boolean.valueOf(props.getProperty("install-only")).booleanValue()) {
    317258                    to.delete();
    318259                    statusDone("<b>" + _("Downloaded plugin is for new installs only, but the plugin is already installed", url) + "</b>");
     
    375316                }
    376317                // do we defer extraction and installation?
    377                 if (Boolean.parseBoolean(props.getProperty("router-restart-required"))) {
     318                if (Boolean.valueOf(props.getProperty("router-restart-required")).booleanValue()) {
    378319                    // Yup!
    379320                    try {
     
    406347                update = true;
    407348            } else {
    408                 if (Boolean.parseBoolean(props.getProperty("update-only"))) {
     349                if (Boolean.valueOf(props.getProperty("update-only")).booleanValue()) {
    409350                    to.delete();
    410351                    statusDone("<b>" + _("Plugin is for upgrades only, but the plugin is not installed") + "</b>");
     
    427368            to.delete();
    428369            // install != update. Changing the user's settings like this is probabbly a bad idea.
    429             if (Boolean.parseBoolean( props.getProperty("dont-start-at-install"))) {
     370            if (Boolean.valueOf( props.getProperty("dont-start-at-install")).booleanValue()) {
    430371                statusDone("<b>" + _("Plugin {0} installed", appName) + "</b>");
    431372                if(!update) {
     
    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

    r8df2a2d r4db4010  
    6060        // Protected with nonce in css.jsi
    6161        if (val != null)
    62             NewsFetcher.getInstance(_context).showNews(val.equals("1"));
     62            NewsHelper.showNews(_context, val.equals("1"));
    6363    }
    6464
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java

    r8df2a2d r4db4010  
    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

    r8df2a2d r4db4010  
    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

    r8df2a2d r4db4010  
    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

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

    r8df2a2d r4db4010  
    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

    r8df2a2d r4db4010  
    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

    r8df2a2d r4db4010  
    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

    r8df2a2d r4db4010  
    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.parseBoolean(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) &&
     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

    r8df2a2d r4db4010  
    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;
     
    569570            RouterContext ctx = contexts.get(0);
    570571
    571             NewsFetcher fetcher = NewsFetcher.getInstance(ctx);
    572             Thread newsThread = new I2PAppThread(fetcher, "NewsFetcher", true);
    573             newsThread.setPriority(Thread.NORM_PRIORITY - 1);
    574             newsThread.start();
     572            ConsoleUpdateManager um = new ConsoleUpdateManager(ctx);
     573            um.start();
    575574       
    576575            if (PluginStarter.pluginsEnabled(ctx)) {
     
    580579                ctx.addShutdownTask(new PluginStopper(ctx));
    581580            }
    582             ctx.addShutdownTask(new NewsShutdown(fetcher, newsThread));
    583581            // stat summarizer registers its own hook
    584582            ctx.addShutdownTask(new ServerShutdown());
     
    752750    }
    753751   
    754     /** @since 0.8.8 */
    755     private static class NewsShutdown implements Runnable {
    756         private final NewsFetcher _fetcher;
    757         private final Thread _newsThread;
    758 
    759         public NewsShutdown(NewsFetcher fetcher, Thread t) {
    760             _fetcher = fetcher;
    761             _newsThread = t;
    762         }
    763 
    764         public void run() {
    765             _fetcher.shutdown();
    766             _newsThread.interrupt();
    767         }
    768     }
    769 
    770752    public static Properties webAppProperties() {
    771753        return webAppProperties(I2PAppContext.getGlobalContext().getConfigDir().getAbsolutePath());
  • apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java

    r8df2a2d r4db4010  
    629629
    630630    public boolean updateAvailable() {
    631         return NewsFetcher.getInstance(_context).updateAvailable();
     631        return NewsHelper.isUpdateAvailable();
    632632    }
    633633
    634634    public boolean unsignedUpdateAvailable() {
    635         return NewsFetcher.getInstance(_context).unsignedUpdateAvailable();
     635        return NewsHelper.isUnsignedUpdateAvailable();
    636636    }
    637637
    638638    public String getUpdateVersion() {
    639         return NewsFetcher.getInstance(_context).updateVersion();
     639        return NewsHelper.updateVersion();
    640640    }
    641641
    642642    public String getUnsignedUpdateVersion() {
    643         return NewsFetcher.getInstance(_context).unsignedUpdateVersion();
     643        return NewsHelper.unsignedUpdateVersion();
    644644    }
    645645
     
    651651        StringBuilder buf = new StringBuilder(512);
    652652        // display all the time so we display the final failure message, and plugin update messages too
    653         String status = UpdateHandler.getStatus();
     653        String status = NewsHelper.getUpdateStatus();
    654654        if (status.length() > 0) {
    655655            buf.append("<h4>").append(status).append("</h4>\n");
    656656        }
    657657        if (updateAvailable() || unsignedUpdateAvailable()) {
    658             if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
     658            if (NewsHelper.isUpdateInProgress()) {
    659659                // nothing
    660660            } else if(
  • apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java

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

    r8df2a2d r4db4010  
    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/build.xml

    r8df2a2d r4db4010  
    8282
    8383    <!-- unit tests -->
    84     <target name="scalatest.compileTest" depends="jar, scala.init">
     84    <target name="scalatest.compileTest" depends="compile, scala.init">
    8585        <mkdir dir="./build" />
    8686        <mkdir dir="./build/obj_scala" />
    8787        <scalac srcdir="./test/scalatest" destdir="./build/obj_scala" deprecation="on" >
    8888            <classpath>
     89                <pathelement location="${classpath}" />
    8990                <pathelement location="${scala-library.jar}" />
    9091                <pathelement location="${scalatest.jar}" />
    91                 <pathelement location="./build/i2p.jar" />
     92                <pathelement location="./build/obj" />
    9293            </classpath>
    9394        </scalac>
     
    102103            <compilerarg line="${javac.compilerargs}" />
    103104        </javac>
     105    </target>
     106    <!-- jars with tests -->
     107    <target name="jarScalaTest" depends="scalatest.compileTest">
     108        <mkdir dir="./build/obj_scala_jar" />
     109        <copy todir="./build/obj_scala_jar">
     110            <fileset dir="./build/">
     111                <include name="obj/**/*.class"/>
     112            </fileset>
     113            <mapper type="glob" from="obj/*" to="*" />
     114        </copy>
     115        <copy todir="./build/obj_scala_jar">
     116            <fileset dir="./build/">
     117                <include name="obj_scala/**/*.class"/>
     118            </fileset>
     119            <mapper type="glob" from="obj_scala/*" to="*" />
     120        </copy>
     121        <jar destfile="./build/i2pscalatest.jar" basedir="./build/obj_scala_jar" includes="**/*.class" />
    104122    </target>
    105123    <target name="jarTest" depends="junit.compileTest">
  • core/java/src/net/i2p/I2PAppContext.java

    r8df2a2d r4db4010  
    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;
     
    992993        }
    993994    }
     995
     996    /**
     997     *  The controller of router, plugin, and other updates.
     998     *  @return always null in I2PAppContext, the update manager if in RouterContext and it is registered
     999     *  @since 0.9.2
     1000     */
     1001    public UpdateManager updateManager() {
     1002        return null;
     1003    }
    9941004}
  • core/java/src/net/i2p/util/VersionComparator.java

    r8df2a2d r4db4010  
    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/build.xml

    r8df2a2d r4db4010  
    100100
    101101    <!-- unit tests -->
     102    <target name="builddepscalatest">
     103        <ant dir="../../core/java/" target="jar" />
     104        <ant dir="../../core/java/" target="jarScalaTest" />
     105    </target>
    102106    <target name="builddeptest">
    103107        <ant dir="../../core/java/" target="jarTest" />
    104108    </target>
    105     <target name="scalatest.compileTest" depends="jar, scala.init">
     109    <target name="scalatest.compileTest" depends="builddepscalatest, compile, scala.init">
    106110        <mkdir dir="./build" />
    107111        <mkdir dir="./build/obj_scala" />
    108112        <scalac srcdir="./test/scalatest" destdir="./build/obj_scala" deprecation="on" >
    109113            <classpath>
     114                <pathelement location="${classpath}" />
    110115                <pathelement location="${scala-library.jar}" />
    111116                <pathelement location="${scalatest.jar}" />
    112                 <pathelement location="../../core/java/build/i2p.jar" />
    113                 <pathelement location="./build/router.jar" />
     117                <pathelement location="../../core/java/build/i2pscalatest.jar" />
     118                <pathelement location="./build/obj" />
    114119            </classpath>
    115120        </scalac>
     
    124129            <compilerarg line="${javac.compilerargs}" />
    125130        </javac>
     131    </target>
     132    <!-- jars with tests -->
     133    <target name="jarScalaTest" depends="scalatest.compileTest">
     134        <mkdir dir="./build/obj_scala_jar" />
     135        <copy todir="./build/obj_scala_jar">
     136            <fileset dir="./build/">
     137                <include name="obj/**/*.class"/>
     138            </fileset>
     139            <mapper type="glob" from="obj/*" to="*" />
     140        </copy>
     141        <copy todir="./build/obj_scala_jar">
     142            <fileset dir="./build/">
     143                <include name="obj_scala/**/*.class"/>
     144            </fileset>
     145            <mapper type="glob" from="obj_scala/*" to="*" />
     146        </copy>
     147        <jar destfile="./build/routerscalatest.jar" basedir="./build/obj_scala_jar" includes="**/*.class" />
    126148    </target>
    127149    <target name="jarTest" depends="junit.compileTest">
  • router/java/src/net/i2p/router/RouterContext.java

    r8df2a2d r4db4010  
    2424import net.i2p.router.tunnel.TunnelDispatcher;
    2525import net.i2p.router.tunnel.pool.TunnelPoolManager;
     26import net.i2p.update.UpdateManager;
    2627import net.i2p.util.KeyRing;
    2728import net.i2p.util.I2PProperties.I2PPropertyCallback;
     
    5758    private Blocklist _blocklist;
    5859    private MessageValidator _messageValidator;
     60    private UpdateManager _updateManager;
    5961    //private MessageStateMonitor _messageStateMonitor;
    6062    private RouterThrottle _throttle;
    6163    private final Set<Runnable> _finalShutdownTasks;
    6264    // split up big lock on this to avoid deadlocks
    63     private final Object _lock1 = new Object(), _lock2 = new Object();
     65    private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object();
    6466
    6567    private static final List<RouterContext> _contexts = new CopyOnWriteArrayList();
     
    484486     *  @since 0.7.9
    485487     */
     488    @Override
    486489    public boolean isRouterContext() {
    487490        return true;
     
    493496     *  @since 0.8.3
    494497     */
     498    @Override
    495499    public InternalClientManager internalClientManager() {
    496500        return _clientManagerFacade;
    497501    }
     502
     503    /**
     504     *  The controller of router, plugin, and other updates.
     505     *  @return The manager if it is registered, else null
     506     *  @since 0.9.2
     507     */
     508    @Override
     509    public UpdateManager updateManager() {
     510        return _updateManager;
     511    }
     512
     513    /**
     514     *  Register as the update manager.
     515     *  @throws IllegalStateException if one was already registered
     516     *  @since 0.9.2
     517     */
     518    public void registerUpdateManager(UpdateManager mgr) {
     519        synchronized(_lock3) {
     520            if (_updateManager != null)
     521                throw new IllegalStateException();
     522            _updateManager = mgr;
     523        }
     524    }
     525
     526    /**
     527     *  Unregister the update manager.
     528     *  @throws IllegalStateException if it was not registered
     529     *  @since 0.9.2
     530     */
     531    public void unregisterUpdateManager(UpdateManager mgr) {
     532        synchronized(_lock3) {
     533            if (_updateManager != mgr)
     534                throw new IllegalStateException();
     535            _updateManager = null;
     536        }
     537    }
    498538}
Note: See TracChangeset for help on using the changeset viewer.