diff --git a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java index d73c1c3a7..6af928a24 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/ConsoleUpdateManager.java @@ -82,6 +82,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { private static final long STATUS_CLEAN_TIME = 20*60*1000; private static final long TASK_CLEANER_TIME = 15*60*1000; private static final String PROP_UNSIGNED_AVAILABLE = "router.updateUnsignedAvailable"; + private static final String PROP_DEV_SU3_AVAILABLE = "router.updateDevSU3Available"; /** * @param args ignored @@ -174,6 +175,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { // TODO see NewsFetcher //register(u, ROUTER_SIGNED, HTTPS_CLEARNET, -5); //register(u, ROUTER_SIGNED, HTTP_CLEARNET, -10); + UnsignedUpdateHandler uuh = new UnsignedUpdateHandler(_context, this); register((Checker)uuh, ROUTER_UNSIGNED, HTTP, 0); register((Updater)uuh, ROUTER_UNSIGNED, HTTP, 0); @@ -185,6 +187,19 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { _available.put(new UpdateItem(ROUTER_UNSIGNED, ""), newVA); } } + + DevSU3UpdateHandler dsuh = new DevSU3UpdateHandler(_context, this); + register((Checker)dsuh, ROUTER_DEV_SU3, HTTP, 0); + register((Updater)dsuh, ROUTER_DEV_SU3, HTTP, 0); + newVersion = _context.getProperty(PROP_DEV_SU3_AVAILABLE); + if (newVersion != null) { + List updateSources = dsuh.getUpdateSources(); + if (dsuh != null) { + VersionAvailable newVA = new VersionAvailable(newVersion, "", HTTP, updateSources); + _available.put(new UpdateItem(ROUTER_DEV_SU3, ""), newVA); + } + } + PluginUpdateHandler puh = new PluginUpdateHandler(_context, this); register((Checker)puh, PLUGIN, HTTP, 0); register((Updater)puh, PLUGIN, HTTP, 0); @@ -652,7 +667,8 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { * Call once for each type/method pair. */ public void register(Updater updater, UpdateType type, UpdateMethod method, int priority) { - if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED || type == ROUTER_SIGNED_SU3) && + if ((type == ROUTER_SIGNED || type == ROUTER_UNSIGNED || + type == ROUTER_SIGNED_SU3 || type == ROUTER_DEV_SU3) && NewsHelper.dontInstall(_context)) { if (_log.shouldLog(Log.WARN)) _log.warn("Ignoring registration for " + type + ", router updates disabled"); @@ -813,8 +829,11 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { break; case ROUTER_UNSIGNED: + case ROUTER_DEV_SU3: // save across restarts - _context.router().saveConfig(PROP_UNSIGNED_AVAILABLE, newVersion); + String prop = type == ROUTER_UNSIGNED ? PROP_UNSIGNED_AVAILABLE + : PROP_DEV_SU3_AVAILABLE; + _context.router().saveConfig(prop, newVersion); // fall through case ROUTER_SIGNED: @@ -822,6 +841,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { if (shouldInstall() && !(isUpdateInProgress(ROUTER_SIGNED) || isUpdateInProgress(ROUTER_SIGNED_SU3) || + isUpdateInProgress(ROUTER_DEV_SU3) || isUpdateInProgress(ROUTER_UNSIGNED))) { if (_log.shouldLog(Log.INFO)) _log.info("Updating " + ui + " after notify"); @@ -908,6 +928,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { case ROUTER_SIGNED: case ROUTER_SIGNED_SU3: case ROUTER_UNSIGNED: + case ROUTER_DEV_SU3: // ConfigUpdateHandler, SummaryHelper, SummaryBarRenderer handle status display break; @@ -1061,6 +1082,14 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { } break; + case ROUTER_DEV_SU3: + rv = handleSu3File(task.getURI(), actualVersion, file); + if (rv) { + _context.router().saveConfig(PROP_DEV_SU3_AVAILABLE, null); + notifyDownloaded(task.getType(), task.getID(), actualVersion); + } + break; + case PLUGIN: // file handled in PluginUpdateRunner default: // assume Updater installed it rv = true; @@ -1111,6 +1140,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { if (type == ROUTER_SIGNED) { _downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, "")); _downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, "")); + _downloaded.remove(new UpdateItem(ROUTER_DEV_SU3, "")); // remove available from other type UpdateItem altui = new UpdateItem(ROUTER_SIGNED_SU3, id); Version old = _available.get(altui); @@ -1121,6 +1151,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { } else if (type == ROUTER_SIGNED_SU3) { _downloaded.remove(new UpdateItem(ROUTER_SIGNED, "")); _downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, "")); + _downloaded.remove(new UpdateItem(ROUTER_DEV_SU3, "")); // remove available from other type UpdateItem altui = new UpdateItem(ROUTER_SIGNED, id); Version old = _available.get(altui); @@ -1131,6 +1162,11 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { } else if (type == ROUTER_UNSIGNED) { _downloaded.remove(new UpdateItem(ROUTER_SIGNED, "")); _downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, "")); + _downloaded.remove(new UpdateItem(ROUTER_DEV_SU3, "")); + } else if (type == ROUTER_DEV_SU3) { + _downloaded.remove(new UpdateItem(ROUTER_SIGNED, "")); + _downloaded.remove(new UpdateItem(ROUTER_SIGNED_SU3, "")); + _downloaded.remove(new UpdateItem(ROUTER_UNSIGNED, "")); } Version old = _available.get(ui); if (old != null && old.compareTo(ver) <= 0) @@ -1202,6 +1238,15 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp { } break; + case ROUTER_DEV_SU3: + String url3 = _context.getProperty(ConfigUpdateHandler.PROP_DEV_SU3_URL); + if (url3 != null) { + try { + return Collections.singletonList(new URI(url3)); + } catch (URISyntaxException use) {} + } + break; + case PLUGIN: Properties props = PluginStarter.pluginProperties(_context, id); String xpi2pURL = props.getProperty("updateURL"); diff --git a/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java new file mode 100644 index 000000000..9d3cb4f8e --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateChecker.java @@ -0,0 +1,93 @@ +package net.i2p.router.update; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.net.URI; +import java.util.List; + +import net.i2p.crypto.TrustedUpdate; +import net.i2p.router.RouterContext; +import net.i2p.router.RouterVersion; +import net.i2p.router.web.ConfigUpdateHandler; +import net.i2p.update.*; +import net.i2p.util.PartialEepGet; +import net.i2p.util.PortMapper; +import net.i2p.util.VersionComparator; + +/** + * Check for an updated su3 version. + * + * Take the update URL + * then fetch the first 56 bytes of the URL, extract the version, + * and compare to current full router version. + * + * @since 0.9.20 from PluginUpdateChecker + */ +class DevSU3UpdateChecker extends UpdateRunner { + + public DevSU3UpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr, + List uris) { + super(ctx, mgr, UpdateType.ROUTER_DEV_SU3, uris, RouterVersion.FULL_VERSION); + if (!uris.isEmpty()) + _currentURI = uris.get(0); + } + + @Override + protected void update() { + // must be set for super + _isPartial = true; + // use the same settings as for updater + // always proxy, or else FIXME + //boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); + String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); + int proxyPort = ConfigUpdateHandler.proxyPort(_context); + if (proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT && + proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) && + _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) { + String msg = _("HTTP client proxy tunnel must be running"); + if (_log.shouldWarn()) + _log.warn(msg); + updateStatus("" + msg + ""); + _mgr.notifyCheckComplete(this, false, false); + return; + } + //updateStatus("" + _("Checking for development build update") + ""); + _baos.reset(); + try { + _get = new PartialEepGet(_context, proxyHost, proxyPort, _baos, _currentURI.toString(), TrustedUpdate.HEADER_BYTES); + _get.addStatusListener(this); + _get.fetch(CONNECT_TIMEOUT); + } catch (Throwable t) { + _log.error("Error fetching the update", t); + } + } + + @Override + public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, + long bytesRemaining, String url) { + } + + @Override + public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, + String url, String outputFile, boolean notModified) { + String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray())); + boolean newer = VersionComparator.comp(newVersion, RouterVersion.FULL_VERSION) > 0; + if (newer) { + _mgr.notifyVersionAvailable(this, _currentURI, UpdateType.ROUTER_DEV_SU3, "", UpdateMethod.HTTP, + _urls, newVersion, RouterVersion.FULL_VERSION); + } else { + updateStatus("" + _("No new version found at {0}", linkify(url)) + ""); + if (_log.shouldWarn()) + _log.warn("Found old version \"" + newVersion + "\" at " + url); + } + _mgr.notifyCheckComplete(this, newer, true); + } + + @Override + public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) { + File f = new File(_updateFile); + f.delete(); + _mgr.notifyCheckComplete(this, false, false); + } +} + diff --git a/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateHandler.java new file mode 100644 index 000000000..606c781f5 --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateHandler.java @@ -0,0 +1,94 @@ +package net.i2p.router.update; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; + +import net.i2p.router.RouterContext; +import net.i2p.router.web.ConfigUpdateHandler; +import net.i2p.router.web.NewsHelper; +import net.i2p.update.*; +import static net.i2p.update.UpdateType.*; +import static net.i2p.update.UpdateMethod.*; + +/** + *

Handles the request to update the router by firing off an + * {@link net.i2p.util.EepGet} call to download the latest su3 file + * and display the status. + *

+ *

After the download completes the su3 is verified, and the zip is extracted + * and copied to the router directory, + * and if configured the router is restarted to complete + * the update process. + *

+ * + * @since 0.9.20 + */ +class DevSU3UpdateHandler implements Checker, Updater { + private final RouterContext _context; + private final ConsoleUpdateManager _mgr; + + public DevSU3UpdateHandler(RouterContext ctx, ConsoleUpdateManager mgr) { + _context = ctx; + _mgr = mgr; + } + + /** + * @return null if none + */ + public List getUpdateSources() { + String url = _context.getProperty(ConfigUpdateHandler.PROP_DEV_SU3_URL); + if (url == null) + return null; + + try { + return Collections.singletonList(new URI(url)); + } catch (URISyntaxException use) { + return null; + } + } + + /** + * @param currentVersion ignored, we use current router version + * @return active task or null if unable to check + */ + public UpdateTask check(UpdateType type, UpdateMethod method, + String id, String currentVersion, long maxTime) { + if (type != UpdateType.ROUTER_DEV_SU3 || method != UpdateMethod.HTTP) + return null; + + List updateSources = getUpdateSources(); + if (updateSources == null) + return null; + + long ms = _context.getProperty(NewsHelper.PROP_LAST_UPDATE_TIME, 0L); + if (ms <= 0) { + // we don't know what version you have, so stamp it with the current time, + // and we'll look for something newer next time around. + _context.router().saveConfig(NewsHelper.PROP_LAST_UPDATE_TIME, + Long.toString(_context.clock().now())); + } + + UpdateRunner update = new DevSU3UpdateChecker(_context, _mgr, updateSources); + return update; + } + + /** + * Start a download and return a handle to the download task. + * Should not block. + * + * @param id plugin name or ignored + * @param maxTime how long you have + * @return active task or null if unable to download + */ + public UpdateTask update(UpdateType type, UpdateMethod method, List updateSources, + String id, String newVersion, long maxTime) { + if (type != ROUTER_DEV_SU3 || method != HTTP || updateSources.isEmpty()) + return null; + UpdateRunner update = new DevSU3UpdateRunner(_context, _mgr, updateSources); + // set status before thread to ensure UI feedback + _mgr.notifyProgress(update, "" + _mgr._("Updating") + ""); + return update; + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateRunner.java new file mode 100644 index 000000000..8f9501d4a --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/update/DevSU3UpdateRunner.java @@ -0,0 +1,78 @@ +package net.i2p.router.update; + +import java.io.File; +import java.net.URI; +import java.util.List; + +import net.i2p.crypto.TrustedUpdate; +import net.i2p.router.RouterContext; +import net.i2p.router.web.ConfigUpdateHandler; +import static net.i2p.update.UpdateType.*; +import net.i2p.util.EepGet; +import net.i2p.util.Log; +import net.i2p.util.PortMapper; + + +/** + * Eepget the .su3 file to the temp dir, then notify. + * ConsoleUpdateManager will do the rest. + * + * @since 0.9.20 + */ +class DevSU3UpdateRunner extends UpdateRunner { + + public DevSU3UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List uris) { + super(ctx, mgr, ROUTER_DEV_SU3, uris); + if (!uris.isEmpty()) + _currentURI = uris.get(0); + } + + /** Get the file */ + @Override + protected void update() { + // always proxy for now + //boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); + String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); + int proxyPort = ConfigUpdateHandler.proxyPort(_context); + if (proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT && + proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) && + _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) { + String msg = _("HTTP client proxy tunnel must be running"); + if (_log.shouldWarn()) + _log.warn(msg); + updateStatus("" + msg + ""); + _mgr.notifyTaskFailed(this, msg, null); + return; + } + String zipURL = _currentURI.toString(); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Starting signed dev update URL: " + zipURL); + try { + // 40 retries!! + _get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, zipURL, false); + _get.addStatusListener(DevSU3UpdateRunner.this); + _get.fetch(CONNECT_TIMEOUT, -1, INACTIVITY_TIMEOUT); + } catch (Throwable t) { + _log.error("Error updating", t); + } + if (!this.done) + _mgr.notifyTaskFailed(this, "", null); + } + + /** eepget listener callback Overrides */ + @Override + public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, + String url, String outputFile, boolean notModified) { + File tmp = new File(_updateFile); + // We use TrustedUpdate here to get the version without any su3 checks, + // which will be done later. + // Only gets 16 bytes max since we aren't using the SU3 version extraction. + String version = TrustedUpdate.getVersionString(tmp); + if (version.equals("")) + version = "unknown"; + if (_mgr.notifyComplete(this, version, tmp)) + this.done = true; + else + tmp.delete(); // corrupt + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java index f34aa1bba..7041c21da 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java @@ -73,6 +73,8 @@ class NewsFetcher extends UpdateRunner { _isRunning = true; try { fetchNews(); + } catch (Throwable t) { + _mgr.notifyTaskFailed(this, "", t); } finally { _mgr.notifyCheckComplete(this, _isNewer, _success); _isRunning = false; diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsTimerTask.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsTimerTask.java index 26116a7ec..471d34712 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/NewsTimerTask.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsTimerTask.java @@ -101,15 +101,13 @@ class NewsTimerTask implements SimpleTimer.TimedEvent { _context.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED) && !NewsHelper.dontInstall(_context); } - - /** - * HEAD the update url, and if the last-mod time is newer than the last update we - * downloaded, as stored in the properties, then we download it using eepget. - * - * Non-blocking - */ - private void fetchUnsignedHead() { - _mgr.check(ROUTER_UNSIGNED); + + /** @since 0.9.20 */ + private boolean shouldFetchDevSU3() { + String url = _context.getProperty(ConfigUpdateHandler.PROP_DEV_SU3_URL); + return url != null && url.length() > 0 && + _context.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DEV_SU3) && + !NewsHelper.dontInstall(_context); } /** @@ -126,12 +124,19 @@ class NewsTimerTask implements SimpleTimer.TimedEvent { public void run() { // blocking fetchNews(); + if (shouldFetchDevSU3()) { + // give it a sec for the download to kick in, if it's going to + try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} + if (!_mgr.isCheckInProgress() && !_mgr.isUpdateInProgress()) + // nonblocking + _mgr.check(ROUTER_DEV_SU3); + } if (shouldFetchUnsigned()) { // give it a sec for the download to kick in, if it's going to try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} if (!_mgr.isCheckInProgress() && !_mgr.isUpdateInProgress()) // nonblocking - fetchUnsignedHead(); + _mgr.check(ROUTER_UNSIGNED); } } } diff --git a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateChecker.java b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateChecker.java index f69fcfe24..ca4c4b994 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateChecker.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/PluginUpdateChecker.java @@ -40,16 +40,6 @@ class PluginUpdateChecker extends UpdateRunner { @Override public String getID() { return _appName; } - @Override - public void run() { - _isRunning = true; - try { - update(); - } finally { - _isRunning = false; - } - } - @Override protected void update() { // must be set for super diff --git a/apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateChecker.java b/apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateChecker.java index 2024bacb1..15ccc6831 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateChecker.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/UnsignedUpdateChecker.java @@ -22,8 +22,6 @@ class UnsignedUpdateChecker extends UpdateRunner { private final long _ms; private boolean _unsignedUpdateAvailable; - protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; - public UnsignedUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr, List uris, long lastUpdateTime) { super(ctx, mgr, UpdateType.ROUTER_UNSIGNED, uris); @@ -36,6 +34,8 @@ class UnsignedUpdateChecker extends UpdateRunner { boolean success = false; try { success = fetchUnsignedHead(); + } catch (Throwable t) { + _mgr.notifyTaskFailed(this, "", t); } finally { _mgr.notifyCheckComplete(this, _unsignedUpdateAvailable, success); _isRunning = false; @@ -59,11 +59,14 @@ class UnsignedUpdateChecker extends UpdateRunner { if (proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT && proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) && _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) { + String msg = _("HTTP client proxy tunnel must be running"); if (_log.shouldWarn()) - _log.warn("Cannot check for unsigned update - HTTP client tunnel not running"); + _log.warn(msg); + updateStatus("" + msg + ""); return false; } + //updateStatus("" + _("Checking for development build update") + ""); try { EepHead get = new EepHead(_context, proxyHost, proxyPort, 0, url); if (get.fetch()) { @@ -81,7 +84,7 @@ class UnsignedUpdateChecker extends UpdateRunner { return true; } } catch (Throwable t) { - _log.error("Error fetching the unsigned update", t); + _log.error("Error fetching the update", t); } return false; } diff --git a/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java b/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java index 682b9b447..91e1ebf59 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/UpdateRunner.java @@ -47,8 +47,6 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList protected URI _currentURI; private final String _currentVersion; - private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; - protected static final long CONNECT_TIMEOUT = 55*1000; protected static final long INACTIVITY_TIMEOUT = 5*60*1000; protected static final long NOPROXY_INACTIVITY_TIMEOUT = 60*1000; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java index 134b727ef..ef3fb4eb1 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java @@ -27,6 +27,8 @@ public class ConfigUpdateHandler extends FormHandler { private String _trustedKeys; private boolean _updateUnsigned; private String _zipURL; + private boolean _updateDevSU3; + private String _devSU3URL; public static final String PROP_NEWS_URL = "router.newsURL"; // public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD"; @@ -61,6 +63,17 @@ public class ConfigUpdateHandler extends FormHandler { public static final String PROP_UPDATE_URL = "router.updateURL"; + /** + * default false + * @since 0.9.20 + */ + public static final String PROP_UPDATE_DEV_SU3 = "router.updateDevSU3"; + /** + * no default + * @since 0.9.20 + */ + public static final String PROP_DEV_SU3_URL = "router.updateDevSU3URL"; + /** * Changed as of release 0.8 to support both .sud and .su2 * Some JVMs (IcedTea) don't have pack200 @@ -163,11 +176,14 @@ public class ConfigUpdateHandler extends FormHandler { return; } - boolean a1 = mgr.checkAvailable(NEWS, 30*1000) != null; + boolean a1 = mgr.checkAvailable(NEWS, 40*1000) != null; boolean a2 = false; - if ((!a1) && _updateUnsigned && _zipURL != null && _zipURL.length() > 0) - a2 = mgr.checkAvailable(ROUTER_UNSIGNED, 30*1000) != null; - if (a1 || a2) { + boolean a3 = false; + if ((!a1) && _updateDevSU3 && _devSU3URL != null && _devSU3URL.length() > 0) + a2 = mgr.checkAvailable(ROUTER_DEV_SU3, 40*1000) != null; + if ((!a2) && _updateUnsigned && _zipURL != null && _zipURL.length() > 0) + a3 = mgr.checkAvailable(ROUTER_UNSIGNED, 40*1000) != null; + if (a1 || a2 || a3) { if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) ) addFormNotice(_("Update available, attempting to download now")); else @@ -220,8 +236,10 @@ public class ConfigUpdateHandler extends FormHandler { changes.put(PROP_SHOULD_PROXY, Boolean.toString(_updateThroughProxy)); changes.put(PROP_SHOULD_PROXY_NEWS, Boolean.toString(_newsThroughProxy)); - if (isAdvanced()) + if (isAdvanced()) { changes.put(PROP_UPDATE_UNSIGNED, Boolean.toString(_updateUnsigned)); + changes.put(PROP_UPDATE_DEV_SU3, Boolean.toString(_updateDevSU3)); + } String oldFreqStr = _context.getProperty(PROP_REFRESH_FREQUENCY, DEFAULT_REFRESH_FREQUENCY); long oldFreq = DEFAULT_REFRESH_FREQ; @@ -276,6 +294,18 @@ public class ConfigUpdateHandler extends FormHandler { } } + if ( (_devSU3URL != null) && (_devSU3URL.length() > 0) ) { + String oldURL = _context.router().getConfigSetting(PROP_DEV_SU3_URL); + if ( (oldURL == null) || (!_devSU3URL.equals(oldURL)) ) { + if (isAdvanced()) { + changes.put(PROP_DEV_SU3_URL, _devSU3URL); + addFormNotice(_("Updating signed development build URL to {0}", _devSU3URL)); + } else { + addFormError("Changing signed update URL disabled"); + } + } + } + _context.router().saveConfig(changes, null); } @@ -293,4 +323,8 @@ public class ConfigUpdateHandler extends FormHandler { public void setZipURL(String url) { _zipURL = url; } /** @since 0.9.9 */ public void setNewsThroughProxy(String foo) { _newsThroughProxy = true; } + /** @since 0.9.20 */ + public void setUpdateDevSU3(String foo) { _updateDevSU3 = true; } + /** @since 0.9.20 */ + public void setDevSU3URL(String url) { _devSU3URL = url; } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java index ebbcf7852..c5c13c0aa 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java @@ -95,6 +95,14 @@ public class ConfigUpdateHelper extends HelperBase { return ""; } + /** @since 0.9.20 */ + public String getUpdateDevSU3() { + if (_context.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DEV_SU3)) + return ""; + else + return ""; + } + private static final long PERIODS[] = new long[] { 12*60*60*1000l, 24*60*60*1000l, 36*60*60*1000l, 48*60*60*1000l, 3*24*60*60*1000l, 7*24*60*60*1000l, @@ -168,6 +176,11 @@ public class ConfigUpdateHelper extends HelperBase { return _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL, ""); } + /** @since 0.9.20 */ + public String getDevSU3URL() { + return _context.getProperty(ConfigUpdateHandler.PROP_DEV_SU3_URL, ""); + } + public String getNewsStatus() { return NewsHelper.status(_context); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java index 13ab7face..f7a30c6dd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsHelper.java @@ -51,11 +51,13 @@ public class NewsHelper extends ContentHelper { return mgr.isUpdateInProgress(ROUTER_SIGNED) || mgr.isUpdateInProgress(ROUTER_SIGNED_SU3) || mgr.isUpdateInProgress(ROUTER_UNSIGNED) || + mgr.isUpdateInProgress(ROUTER_DEV_SU3) || mgr.isUpdateInProgress(TYPE_DUMMY); } /** - * Will be false if already downloaded + * Release update only. + * Will be false if already downloaded. * @since 0.9.4 moved from NewsFetcher */ public static boolean isUpdateAvailable() { @@ -66,7 +68,8 @@ public class NewsHelper extends ContentHelper { } /** - * Available version, will be null if already downloaded + * Release update only. + * Available version, will be null if already downloaded. * @return null if none * @since 0.9.4 moved from NewsFetcher */ @@ -80,6 +83,7 @@ public class NewsHelper extends ContentHelper { } /** + * Release update only. * Translated message about new version available but constrained * @return null if none * @since 0.9.9 @@ -91,7 +95,8 @@ public class NewsHelper extends ContentHelper { } /** - * Already downloaded but not installed version + * Release update only. + * Already downloaded but not installed version. * @return null if none * @since 0.9.4 */ @@ -105,13 +110,14 @@ public class NewsHelper extends ContentHelper { } /** - * Will be false if already downloaded + * Will be false if already downloaded or if dev update disabled. * @since 0.9.4 moved from NewsFetcher */ - public static boolean isUnsignedUpdateAvailable() { + public static boolean isUnsignedUpdateAvailable(RouterContext ctx) { ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance(); if (mgr == null) return false; - return mgr.getUpdateAvailable(ROUTER_UNSIGNED) != null; + return mgr.getUpdateAvailable(ROUTER_UNSIGNED) != null && + ctx.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED); } /** @@ -135,6 +141,38 @@ public class NewsHelper extends ContentHelper { return formatUnsignedVersion(mgr.getUpdateDownloaded(ROUTER_UNSIGNED)); } + /** + * Will be false if already downloaded or if dev update disabled. + * @since 0.9.20 + */ + public static boolean isDevSU3UpdateAvailable(RouterContext ctx) { + ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance(); + if (mgr == null) return false; + return mgr.getUpdateAvailable(ROUTER_DEV_SU3) != null && + ctx.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_DEV_SU3); + } + + /** + * @return null if none + * @since 0.9.20 + */ + public static String devSU3UpdateVersion() { + ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance(); + if (mgr == null) return null; + return mgr.getUpdateAvailable(ROUTER_DEV_SU3); + } + + /** + * Already downloaded but not installed version + * @return null if none + * @since 0.9.20 + */ + public static String devSU3VersionDownloaded() { + ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance(); + if (mgr == null) return null; + return mgr.getUpdateDownloaded(ROUTER_DEV_SU3); + } + /** * Convert long date stamp to * '07-Jul 21:09 UTC' with month name in the system locale diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 42dcd3352..0509d6f37 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -657,22 +657,33 @@ public class SummaryHelper extends HelperBase { } ********/ - private boolean updateAvailable() { + private static boolean updateAvailable() { return NewsHelper.isUpdateAvailable(); } private boolean unsignedUpdateAvailable() { - return NewsHelper.isUnsignedUpdateAvailable(); + return NewsHelper.isUnsignedUpdateAvailable(_context); } - private String getUpdateVersion() { - return NewsHelper.updateVersion(); + /** @since 0.9.20 */ + private boolean devSU3UpdateAvailable() { + return NewsHelper.isDevSU3UpdateAvailable(_context); } - private String getUnsignedUpdateVersion() { + private static String getUpdateVersion() { + return DataHelper.escapeHTML(NewsHelper.updateVersion()); + } + + private static String getUnsignedUpdateVersion() { + // value is a formatted date, does not need escaping return NewsHelper.unsignedUpdateVersion(); } + /** @since 0.9.20 */ + private static String getDevSU3UpdateVersion() { + return DataHelper.escapeHTML(NewsHelper.devSU3UpdateVersion()); + } + /** * The update status and buttons * @since 0.8.13 moved from SummaryBarRenderer @@ -687,8 +698,11 @@ public class SummaryHelper extends HelperBase { needSpace = true; } String dver = NewsHelper.updateVersionDownloaded(); - if (dver == null) - dver = NewsHelper.unsignedVersionDownloaded(); + if (dver == null) { + dver = NewsHelper.devSU3VersionDownloaded(); + if (dver == null) + dver = NewsHelper.unsignedVersionDownloaded(); + } if (dver != null && !NewsHelper.isUpdateInProgress() && !_context.router().gracefulShutdownInProgress()) { @@ -701,11 +715,12 @@ public class SummaryHelper extends HelperBase { buf.append(_("Click Restart to install")); else buf.append(_("Click Shutdown and restart to install")); - buf.append(' ').append(_("Version {0}", dver)); + buf.append(' ').append(_("Version {0}", DataHelper.escapeHTML(dver))); buf.append(""); } boolean avail = updateAvailable(); boolean unsignedAvail = unsignedUpdateAvailable(); + boolean devSU3Avail = devSU3UpdateAvailable(); String constraint = avail ? NewsHelper.updateConstraint() : null; if (avail && constraint != null && !NewsHelper.isUpdateInProgress() && @@ -719,7 +734,7 @@ public class SummaryHelper extends HelperBase { buf.append(constraint).append(""); avail = false; } - if ((avail || unsignedAvail) && + if ((avail || unsignedAvail || devSU3Avail) && !NewsHelper.isUpdateInProgress() && !_context.router().gracefulShutdownInProgress() && _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) > 0 && // assume using proxy for now @@ -741,6 +756,14 @@ public class SummaryHelper extends HelperBase { .append(_("Download {0} Update", getUpdateVersion())) .append("
\n"); } + if (devSU3Avail) { + buf.append("
\n"); + } if (unsignedAvail) { buf.append("