package net.i2p.router.update; import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; import net.i2p.router.web.ConfigUpdateHandler; import net.i2p.router.web.NewsHelper; import static net.i2p.update.UpdateType.*; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; import net.i2p.util.SimpleTimer; /** * Task to periodically look for updates to the news.xml, and to keep * track of whether that has an announcement for a new version. * Also looks for unsigned updates. * * Runs forever on instantiation, can't be stopped. * * @since 0.9.4 moved from NewsFetcher */ class NewsTimerTask implements SimpleTimer.TimedEvent { private final RouterContext _context; private final Log _log; private final ConsoleUpdateManager _mgr; private volatile boolean _firstRun = true; private static final long INITIAL_DELAY = 5*60*1000; private static final long NEW_INSTALL_DELAY = 25*60*1000; private static final long RUN_DELAY = 10*60*1000; public NewsTimerTask(RouterContext ctx, ConsoleUpdateManager mgr) { _context = ctx; _log = ctx.logManager().getLog(NewsTimerTask.class); _mgr = mgr; long installed = ctx.getProperty("router.firstInstalled", 0L); boolean isNew = (ctx.clock().now() - installed) < 30*60*1000L; long delay = isNew ? NEW_INSTALL_DELAY : INITIAL_DELAY; delay += _context.random().nextLong(INITIAL_DELAY); if (_log.shouldLog(Log.INFO)) _log.info("Scheduling first news check in " + DataHelper.formatDuration(delay)); ctx.simpleTimer2().addPeriodicEvent(this, delay, RUN_DELAY); // UpdateManager calls NewsFetcher to check the existing news at startup } public void timeReached() { if (shouldFetchNews()) { Thread t = new Fetcher(); t.start(); } else if (_firstRun) { // This covers the case where we got a new news but then shut down before it // was successfully downloaded, and then restarted within the 36 hour delay // before fetching news again. // If we already know about a new version (from ConsoleUpdateManager calling // NewsFetcher.checkForUpdates() before any Updaters were registered), // this will fire off an update. // If disabled this does nothing. // TODO unsigned too? if (_mgr.shouldInstall() && !_mgr.isCheckInProgress() && !_mgr.isUpdateInProgress()) // non-blocking _mgr.update(ROUTER_SIGNED); } _firstRun = false; } private boolean shouldFetchNews() { if (_context.router().gracefulShutdownInProgress()) return false; if (_mgr.isCheckInProgress() || _mgr.isUpdateInProgress()) return false; long lastFetch = NewsHelper.lastChecked(_context); String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY, ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY); try { long ms = Long.parseLong(freq); if (ms <= 0) return false; if (lastFetch + ms < _context.clock().now()) { return true; } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Last fetched " + DataHelper.formatDuration(_context.clock().now() - lastFetch) + " ago"); return false; } } catch (NumberFormatException nfe) { if (_log.shouldLog(Log.ERROR)) _log.error("Invalid refresh frequency: " + freq); return false; } } /** blocking */ private void fetchNews() { _mgr.checkAvailable(NEWS, 60*1000); } private boolean shouldFetchUnsigned() { String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL); return url != null && url.length() > 0 && _context.getBooleanProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED) && !NewsHelper.dontInstall(_context); } /** @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); } /** * Don't clog the scheduler when fetching the news * * @since 0.9.9 */ private class Fetcher extends I2PAppThread { public Fetcher() { super("News Fetcher"); setDaemon(true); } 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 _mgr.check(ROUTER_UNSIGNED); } } } }