- Save available unsigned version across restarts

- Fix status display after downloaded
- Don't display update buttons unless HTTP proxy is up
- Pass the manager down thru the constructors
This commit is contained in:
zzz
2012-10-19 20:26:08 +00:00
parent 4f936f958d
commit fea3bb63c1
15 changed files with 160 additions and 94 deletions

View File

@ -5,7 +5,6 @@ import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -77,6 +76,7 @@ public class ConsoleUpdateManager implements UpdateManager {
private static final long DEFAULT_CHECK_TIME = 60*1000;
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";
public ConsoleUpdateManager(RouterContext ctx) {
_context = ctx;
@ -99,7 +99,7 @@ public class ConsoleUpdateManager implements UpdateManager {
notifyInstalled(NEWS, "", Long.toString(NewsHelper.lastUpdated(_context)));
notifyInstalled(ROUTER_SIGNED, "", RouterVersion.VERSION);
// hack to init from the current news file... do this before we register Updaters
(new NewsFetcher(_context, Collections.EMPTY_LIST)).checkForUpdates();
(new NewsFetcher(_context, this, Collections.EMPTY_LIST)).checkForUpdates();
for (String plugin : PluginStarter.getPlugins()) {
Properties props = PluginStarter.pluginProperties(_context, plugin);
String ver = props.getProperty("version");
@ -108,24 +108,32 @@ public class ConsoleUpdateManager implements UpdateManager {
}
_context.registerUpdateManager(this);
DummyHandler dh = new DummyHandler(_context);
DummyHandler dh = new DummyHandler(_context, this);
register((Checker)dh, TYPE_DUMMY, HTTP, 0);
register((Updater)dh, TYPE_DUMMY, HTTP, 0);
// register news before router, so we don't fire off an update
// right at instantiation if the news is already indicating a new version
Checker c = new NewsHandler(_context);
Checker c = new NewsHandler(_context, this);
register(c, NEWS, HTTP, 0);
register(c, ROUTER_SIGNED, HTTP, 0); // news is an update checker for the router
Updater u = new UpdateHandler(_context);
Updater u = new UpdateHandler(_context, this);
register(u, ROUTER_SIGNED, HTTP, 0);
UnsignedUpdateHandler uuh = new UnsignedUpdateHandler(_context);
UnsignedUpdateHandler uuh = new UnsignedUpdateHandler(_context, this);
register((Checker)uuh, ROUTER_UNSIGNED, HTTP, 0);
register((Updater)uuh, ROUTER_UNSIGNED, HTTP, 0);
PluginUpdateHandler puh = new PluginUpdateHandler(_context);
String newVersion = _context.getProperty(PROP_UNSIGNED_AVAILABLE);
if (newVersion != null) {
List<URI> updateSources = uuh.getUpdateSources();
if (uuh != null) {
VersionAvailable newVA = new VersionAvailable(newVersion, "", HTTP, updateSources);
_available.put(new UpdateItem(ROUTER_UNSIGNED, ""), newVA);
}
}
PluginUpdateHandler puh = new PluginUpdateHandler(_context, this);
register((Checker)puh, PLUGIN, HTTP, 0);
register((Checker)puh, PLUGIN_INSTALL, HTTP, 0);
register((Updater)puh, PLUGIN_INSTALL, HTTP, 0);
new NewsTimerTask(_context);
new NewsTimerTask(_context, this);
_context.simpleScheduler().addPeriodicEvent(new TaskCleaner(), TASK_CLEANER_TIME);
}
@ -605,9 +613,13 @@ public class ConsoleUpdateManager implements UpdateManager {
case NEWS:
break;
case ROUTER_UNSIGNED:
// save across restarts
_context.router().saveConfig(PROP_UNSIGNED_AVAILABLE, newVersion);
// fall through
case ROUTER_SIGNED:
case ROUTER_SIGNED_PACK200:
case ROUTER_UNSIGNED:
if (shouldInstall() &&
!(isUpdateInProgress(ROUTER_SIGNED) ||
isUpdateInProgress(ROUTER_SIGNED_PACK200) ||
@ -758,8 +770,10 @@ public class ConsoleUpdateManager implements UpdateManager {
case ROUTER_UNSIGNED:
rv = handleUnsignedFile(task.getURI(), actualVersion, file);
if (rv)
if (rv) {
_context.router().saveConfig(PROP_UNSIGNED_AVAILABLE, null);
notifyDownloaded(task.getType(), task.getID(), actualVersion);
}
break;
case PLUGIN:
@ -887,6 +901,7 @@ public class ConsoleUpdateManager implements UpdateManager {
}
/**
*
* @return success
*/
private boolean handleSudFile(URI uri, String actualVersion, File f) {
@ -911,16 +926,8 @@ public class ConsoleUpdateManager implements UpdateManager {
restart();
} else {
_log.log(Log.CRIT, "Update was VERIFIED, will be installed at next restart");
StringBuilder buf = new StringBuilder(64);
buf.append("<b>").append(_("Update downloaded")).append("<br>");
if (_context.hasWrapper())
buf.append(_("Click Restart to install"));
else
buf.append(_("Click Shutdown and restart to install"));
if (up.newVersion() != null)
buf.append(' ').append(_("Version {0}", up.newVersion()));
buf.append("</b>");
updateStatus(buf.toString());
// SummaryHelper will display restart info separately
updateStatus("");
}
} else {
_log.log(Log.CRIT, err + " from " + url);
@ -963,15 +970,8 @@ public class ConsoleUpdateManager implements UpdateManager {
restart();
} else {
_log.log(Log.CRIT, "Update was downloaded, will be installed at next restart");
StringBuilder buf = new StringBuilder(64);
buf.append("<b>").append(_("Update downloaded")).append("</b><br>");
if (_context.hasWrapper())
buf.append(_("Click Restart to install"));
else
buf.append(_("Click Shutdown and restart to install"));
String ver = (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime)) + " UTC";
buf.append(' ').append(_("Version {0}", ver));
updateStatus(buf.toString());
// SummaryHelper will display restart info separately
updateStatus("");
}
} else {
_log.log(Log.CRIT, "Failed copy to " + to);
@ -999,14 +999,14 @@ public class ConsoleUpdateManager implements UpdateManager {
}
/** translate a string */
private String _(String s) {
public String _(String s) {
return Messages.getString(s, _context);
}
/**
* translate a string with a parameter
*/
private String _(String s, Object o) {
public String _(String s, Object o) {
return Messages.getString(s, o, _context);
}

View File

@ -14,9 +14,11 @@ import net.i2p.update.*;
*/
class DummyHandler implements Checker, Updater {
private final RouterContext _context;
private final ConsoleUpdateManager _mgr;
public DummyHandler(RouterContext ctx) {
public DummyHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_mgr = mgr;
}
/**
@ -26,7 +28,7 @@ class DummyHandler implements Checker, Updater {
String id, String currentVersion, long maxTime) {
if (type != UpdateType.TYPE_DUMMY)
return null;
return new DummyRunner(_context, maxTime);
return new DummyRunner(_context, _mgr, maxTime);
}
/**
@ -36,7 +38,7 @@ class DummyHandler implements Checker, Updater {
String id, String newVersion, long maxTime) {
if (type != UpdateType.TYPE_DUMMY)
return null;
return new DummyRunner(_context, maxTime);
return new DummyRunner(_context, _mgr, maxTime);
}
/**
@ -45,8 +47,8 @@ class DummyHandler implements Checker, Updater {
private static class DummyRunner extends UpdateRunner {
private final long _delay;
public DummyRunner(RouterContext ctx, long maxTime) {
super(ctx, Collections.EMPTY_LIST);
public DummyRunner(RouterContext ctx, ConsoleUpdateManager mgr, long maxTime) {
super(ctx, mgr, Collections.EMPTY_LIST);
_delay = maxTime;
}
@ -58,11 +60,8 @@ class DummyHandler implements Checker, Updater {
try {
Thread.sleep(_delay);
} catch (InterruptedException ie) {}
UpdateManager mgr = _context.updateManager();
if (mgr != null) {
mgr.notifyCheckComplete(this, false, false);
mgr.notifyTaskFailed(this, "dummy", null);
}
_mgr.notifyCheckComplete(this, false, false);
_mgr.notifyTaskFailed(this, "dummy", null);
}
}
}

View File

@ -43,8 +43,8 @@ class NewsFetcher extends UpdateRunner {
private static final String TEMP_NEWS_FILE = "news.xml.temp";
public NewsFetcher(RouterContext ctx, List<URI> uris) {
super(ctx, uris);
public NewsFetcher(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
super(ctx, mgr, uris);
_newsFile = new File(ctx.getRouterDir(), NewsHelper.NEWS_FILE);
_tempFile = new File(ctx.getTempDir(), "tmp-" + ctx.random().nextLong() + TEMP_NEWS_FILE);
long lastMod = NewsHelper.lastChecked(ctx);

View File

@ -24,8 +24,8 @@ class NewsHandler extends UpdateHandler implements Checker {
/** @since 0.7.14 not configurable */
private static final String BACKUP_NEWS_URL = "http://www.i2p2.i2p/_static/news/news.xml";
public NewsHandler(RouterContext ctx) {
super(ctx);
public NewsHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
super(ctx, mgr);
}
/**
@ -45,7 +45,7 @@ class NewsHandler extends UpdateHandler implements Checker {
try {
updateSources.add(new URI(BACKUP_NEWS_URL));
} catch (URISyntaxException use) {}
UpdateRunner update = new NewsFetcher(_context, updateSources);
UpdateRunner update = new NewsFetcher(_context, _mgr, updateSources);
update.start();
return update;
}

View File

@ -43,10 +43,10 @@ class NewsTimerTask implements SimpleTimer.TimedEvent {
private static final long INITIAL_DELAY = 5*60*1000;
private static final long RUN_DELAY = 10*60*1000;
public NewsTimerTask(RouterContext ctx) {
public NewsTimerTask(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_log = ctx.logManager().getLog(NewsTimerTask.class);
_mgr = (ConsoleUpdateManager) _context.updateManager();
_mgr = mgr;
ctx.simpleScheduler().addPeriodicEvent(this,
INITIAL_DELAY + _context.random().nextLong(INITIAL_DELAY),
RUN_DELAY);

View File

@ -34,8 +34,9 @@ class PluginUpdateChecker extends UpdateRunner {
private final String _appName;
private final String _oldVersion;
public PluginUpdateChecker(RouterContext ctx, List<URI> uris, String appName, String oldVersion ) {
super(ctx, uris);
public PluginUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
List<URI> uris, String appName, String oldVersion ) {
super(ctx, mgr, uris);
_baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
if (!uris.isEmpty())
_currentURI = uris.get(0);

View File

@ -36,9 +36,11 @@ import net.i2p.util.VersionComparator;
*/
class PluginUpdateHandler implements Checker, Updater {
private final RouterContext _context;
private final ConsoleUpdateManager _mgr;
public PluginUpdateHandler(RouterContext ctx) {
public PluginUpdateHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_mgr = mgr;
}
/** check a single plugin */
@ -64,7 +66,7 @@ class PluginUpdateHandler implements Checker, Updater {
return null;
}
UpdateRunner update = new PluginUpdateChecker(_context, updateSources, appName, oldVersion);
UpdateRunner update = new PluginUpdateChecker(_context, _mgr, updateSources, appName, oldVersion);
update.start();
return update;
}
@ -84,7 +86,9 @@ class PluginUpdateHandler implements Checker, Updater {
return null;
}
UpdateRunner update = new PluginUpdateRunner(_context, updateSources, appName, oldVersion);
UpdateRunner update = new PluginUpdateRunner(_context, _mgr, updateSources, appName, oldVersion);
// set status before thread to ensure UI feedback
_mgr.notifyProgress(update, "<b>" + _mgr._("Updating") + "</b>");
update.start();
return update;
}

View File

@ -53,8 +53,9 @@ class PluginUpdateRunner extends UpdateRunner {
private static final String ZIP = XPI2P + ".zip";
public static final String PLUGIN_DIR = PluginStarter.PLUGIN_DIR;
public PluginUpdateRunner(RouterContext ctx, List<URI> uris, String appName, String oldVersion ) {
super(ctx, uris);
public PluginUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris,
String appName, String oldVersion ) {
super(ctx, mgr, uris);
if (uris.isEmpty())
_uri = null;
else

View File

@ -27,8 +27,9 @@ class UnsignedUpdateChecker extends UpdateRunner {
protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
public UnsignedUpdateChecker(RouterContext ctx, List<URI> uris, long lastUpdateTime) {
super(ctx, uris);
public UnsignedUpdateChecker(RouterContext ctx, ConsoleUpdateManager mgr,
List<URI> uris, long lastUpdateTime) {
super(ctx, mgr, uris);
_ms = lastUpdateTime;
}

View File

@ -31,9 +31,27 @@ import net.i2p.util.Log;
*/
class UnsignedUpdateHandler implements Checker, Updater {
private final RouterContext _context;
private final ConsoleUpdateManager _mgr;
public UnsignedUpdateHandler(RouterContext ctx) {
public UnsignedUpdateHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_mgr = mgr;
}
/**
* @return null if none
* @since 0.9.4
*/
public List<URI> getUpdateSources() {
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
if (url == null)
return null;
try {
return Collections.singletonList(new URI(url));
} catch (URISyntaxException use) {
return null;
}
}
/**
@ -45,17 +63,10 @@ class UnsignedUpdateHandler implements Checker, Updater {
if (type != UpdateType.ROUTER_UNSIGNED || method != UpdateMethod.HTTP)
return null;
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
if (url == null)
List<URI> updateSources = getUpdateSources();
if (updateSources == null)
return null;
List<URI> updateSources;
try {
updateSources = Collections.singletonList(new URI(url));
} catch (URISyntaxException use) {
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,
@ -65,7 +76,7 @@ class UnsignedUpdateHandler implements Checker, Updater {
return null;
}
UpdateRunner update = new UnsignedUpdateChecker(_context, updateSources, ms);
UpdateRunner update = new UnsignedUpdateChecker(_context, _mgr, updateSources, ms);
update.start();
return update;
}
@ -83,7 +94,9 @@ class UnsignedUpdateHandler implements Checker, Updater {
String id, String newVersion, long maxTime) {
if (type != ROUTER_UNSIGNED || method != HTTP || updateSources.isEmpty())
return null;
UpdateRunner update = new UnsignedUpdateRunner(_context, updateSources);
UpdateRunner update = new UnsignedUpdateRunner(_context, _mgr, updateSources);
// set status before thread to ensure UI feedback
_mgr.notifyProgress(update, "<b>" + _mgr._("Updating") + "</b>");
update.start();
return update;
}

View File

@ -24,8 +24,8 @@ import net.i2p.util.Log;
*/
class UnsignedUpdateRunner extends UpdateRunner {
public UnsignedUpdateRunner(RouterContext ctx, List<URI> uris) {
super(ctx, uris);
public UnsignedUpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
super(ctx, mgr, uris);
if (!uris.isEmpty())
_currentURI = uris.get(0);
}
@ -39,7 +39,6 @@ class UnsignedUpdateRunner extends UpdateRunner {
@Override
protected void update() {
String zipURL = _currentURI.toString();
updateStatus("<b>" + _("Updating") + "</b>");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Starting unsigned update URL: " + zipURL);
// always proxy for now

View File

@ -38,9 +38,11 @@ import net.i2p.util.VersionComparator;
*/
class UpdateHandler implements Updater {
protected final RouterContext _context;
protected final ConsoleUpdateManager _mgr;
public UpdateHandler(RouterContext ctx) {
public UpdateHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_mgr = mgr;
}
/**
@ -56,7 +58,9 @@ class UpdateHandler implements Updater {
if ((type != UpdateType.ROUTER_SIGNED && type != UpdateType.ROUTER_SIGNED_PACK200) ||
method != UpdateMethod.HTTP || updateSources.isEmpty())
return null;
UpdateRunner update = new UpdateRunner(_context, updateSources);
UpdateRunner update = new UpdateRunner(_context, _mgr, updateSources);
// set status before thread to ensure UI feedback
_mgr.notifyProgress(update, "<b>" + _mgr._("Updating") + "</b>");
update.start();
return update;
}

View File

@ -49,12 +49,12 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
protected static final long INACTIVITY_TIMEOUT = 5*60*1000;
protected static final long NOPROXY_INACTIVITY_TIMEOUT = 60*1000;
public UpdateRunner(RouterContext ctx, List<URI> uris) {
public UpdateRunner(RouterContext ctx, ConsoleUpdateManager mgr, List<URI> uris) {
super("Update Runner");
setDaemon(true);
_context = ctx;
_log = ctx.logManager().getLog(getClass());
_mgr = (ConsoleUpdateManager) ctx.updateManager();
_mgr = mgr;
_urls = uris;
_updateFile = (new File(ctx.getTempDir(), "update" + ctx.random().nextInt() + ".tmp")).getAbsolutePath();
}
@ -226,13 +226,13 @@ class UpdateRunner extends I2PAppThread implements UpdateTask, EepGet.StatusList
/** translate a string */
protected String _(String s) {
return Messages.getString(s, _context);
return _mgr._(s);
}
/**
* translate a string with a parameter
*/
protected String _(String s, Object o) {
return Messages.getString(s, o, _context);
return _mgr._(s, o);
}
}

View File

@ -50,6 +50,7 @@ public class NewsHelper extends ContentHelper {
}
/**
* Will be false if already downloaded
* @since 0.9.4 moved from NewsFetcher
*/
public static boolean isUpdateAvailable() {
@ -59,6 +60,7 @@ public class NewsHelper extends ContentHelper {
}
/**
* Available version, will be null if already downloaded
* @return null if none
* @since 0.9.4 moved from NewsFetcher
*/
@ -69,6 +71,18 @@ public class NewsHelper extends ContentHelper {
}
/**
* Already downloaded but not installed version
* @return null if none
* @since 0.9.4
*/
public static String updateVersionDownloaded() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return null;
return mgr.getUpdateDownloaded(ROUTER_SIGNED);
}
/**
* Will be false if already downloaded
* @since 0.9.4 moved from NewsFetcher
*/
public static boolean isUnsignedUpdateAvailable() {
@ -84,11 +98,30 @@ public class NewsHelper extends ContentHelper {
public static String unsignedUpdateVersion() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return null;
String ver = mgr.getUpdateAvailable(ROUTER_UNSIGNED);
return formatUnsignedVersion(mgr.getUpdateAvailable(ROUTER_UNSIGNED));
}
/**
* Already downloaded but not installed version
* @return null if none
* @since 0.9.4
*/
public static String unsignedVersionDownloaded() {
ConsoleUpdateManager mgr = ConsoleUpdateManager.getInstance();
if (mgr == null) return null;
return formatUnsignedVersion(mgr.getUpdateDownloaded(ROUTER_UNSIGNED));
}
/**
* Convert long date stamp to
* '07-Jul 21:09 UTC' with month name in the system locale
* @return null if ver = null
* @since 0.9.4 moved from NewsFetcher
*/
private static String formatUnsignedVersion(String ver) {
if (ver != null) {
try {
long modtime = Long.parseLong(ver);
// '07-Jul 21:09 UTC' with month name in the system locale
return (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime)) + " UTC";
} catch (NumberFormatException nfe) {}
}

View File

@ -27,6 +27,7 @@ import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
import net.i2p.router.transport.ntcp.NTCPAddress;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.util.PortMapper;
/**
* Simple helper to query the appropriate router for data necessary to render
@ -627,19 +628,19 @@ public class SummaryHelper extends HelperBase {
}
********/
public boolean updateAvailable() {
private boolean updateAvailable() {
return NewsHelper.isUpdateAvailable();
}
public boolean unsignedUpdateAvailable() {
private boolean unsignedUpdateAvailable() {
return NewsHelper.isUnsignedUpdateAvailable();
}
public String getUpdateVersion() {
private String getUpdateVersion() {
return NewsHelper.updateVersion();
}
public String getUnsignedUpdateVersion() {
private String getUnsignedUpdateVersion() {
return NewsHelper.unsignedUpdateVersion();
}
@ -654,15 +655,26 @@ public class SummaryHelper extends HelperBase {
if (status.length() > 0) {
buf.append("<h4>").append(status).append("</h4>\n");
}
if (updateAvailable() || unsignedUpdateAvailable()) {
if (NewsHelper.isUpdateInProgress()) {
// nothing
} else if(
// isDone() is always false for now, see UpdateHandler
// ((!update.isDone()) &&
getAction() == null &&
getUpdateNonce() == null &&
ConfigRestartBean.getRestartTimeRemaining() > 12*60*1000) {
String dver = NewsHelper.updateVersionDownloaded();
if (dver == null)
dver = NewsHelper.unsignedVersionDownloaded();
if (dver != null &&
!NewsHelper.isUpdateInProgress() &&
!_context.router().gracefulShutdownInProgress()) {
buf.append("<h4><b>").append(_("Update downloaded")).append("<br>");
if (_context.hasWrapper())
buf.append(_("Click Restart to install"));
else
buf.append(_("Click Shutdown and restart to install"));
buf.append(' ').append(_("Version {0}", dver));
buf.append("</b></h4>");
}
if ((updateAvailable() || unsignedUpdateAvailable()) &&
!NewsHelper.isUpdateInProgress() &&
!_context.router().gracefulShutdownInProgress() &&
_context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) > 0 && // assume using proxy for now
getAction() == null &&
getUpdateNonce() == null) {
long nonce = _context.random().nextLong();
String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce");
if (prev != null)
@ -686,7 +698,6 @@ public class SummaryHelper extends HelperBase {
.append("</button><br>\n");
}
buf.append("</form>\n");
}
}
return buf.toString();
}