From 904f755c8c94ef42f72e24a6ba78910cd82926bf Mon Sep 17 00:00:00 2001 From: jrandom Date: Thu, 24 Mar 2005 01:19:52 +0000 Subject: [PATCH] 2005-03-23 jrandom * Implemented the news fetch / update policy code, as configurated on /configupdate.jsp. Defaults are to grab the news every 24h (or if it doesn't exist yet, on startup). No action is taken however, though if the news.xml specifies that a new release is available, an option to update will be shown on the router console. * New initialNews.xml delivered with new installs, and moved news.xml out of the i2pwww module and into the i2p module so that we can bundle it within each update. --- .../i2p/router/web/ConfigUpdateHandler.java | 24 ++- .../i2p/router/web/ConfigUpdateHelper.java | 69 +++++-- .../src/net/i2p/router/web/NewsFetcher.java | 171 ++++++++++++++++++ .../i2p/router/web/RouterConsoleRunner.java | 6 + .../src/net/i2p/router/web/SummaryHelper.java | 4 +- .../src/net/i2p/router/web/UpdateHandler.java | 33 ++-- apps/routerconsole/jsp/configupdate.jsp | 2 + apps/routerconsole/jsp/default.css | 9 + apps/routerconsole/jsp/index.jsp | 7 + apps/routerconsole/jsp/summary.jsp | 2 +- build.xml | 3 + history.txt | 12 +- initialNews.xml | 14 ++ news.xml | 21 +++ readme.html | 2 - .../src/net/i2p/router/RouterVersion.java | 4 +- 16 files changed, 352 insertions(+), 31 deletions(-) create mode 100644 apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java create mode 100644 initialNews.xml create mode 100644 news.xml 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 dd6cdc9b1e..e75f6e0b60 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java @@ -10,13 +10,15 @@ public class ConfigUpdateHandler extends FormHandler { private long _refreshFrequency; private String _updateURL; private String _updatePolicy; + private String _proxyHost; + private String _proxyPort; private boolean _updateThroughProxy; private String _trustedKeys; public static final String PROP_NEWS_URL = "router.newsURL"; - public static final String DEFAULT_NEWS_URL = "http://www.i2p/routerConsoleNews.xml"; + public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD"; public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency"; - public static final String DEFAULT_REFRESH_FREQUENCY = 24*60*60*1000 + ""; + public static final String DEFAULT_REFRESH_FREQUENCY = 12*60*60*1000 + ""; public static final String PROP_UPDATE_URL = "router.updateURL"; public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud"; public static final String PROP_UPDATE_POLICY = "router.updatePolicy"; @@ -44,6 +46,22 @@ public class ConfigUpdateHandler extends FormHandler { } } + if ( (_proxyHost != null) && (_proxyHost.length() > 0) ) { + String oldHost = _context.router().getConfigSetting(PROP_PROXY_HOST); + if ( (oldHost == null) || (!_proxyHost.equals(oldHost)) ) { + _context.router().setConfigSetting(PROP_PROXY_HOST, _proxyHost); + addFormNotice("Updating proxy host to " + _proxyHost); + } + } + + if ( (_proxyPort != null) && (_proxyPort.length() > 0) ) { + String oldPort = _context.router().getConfigSetting(PROP_PROXY_PORT); + if ( (oldPort == null) || (!_proxyHost.equals(oldPort)) ) { + _context.router().setConfigSetting(PROP_PROXY_PORT, _proxyPort); + addFormNotice("Updating proxy port to " + _proxyPort); + } + } + if (_updateThroughProxy) { _context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.TRUE.toString()); } else { @@ -80,4 +98,6 @@ public class ConfigUpdateHandler extends FormHandler { public void setUpdatePolicy(String policy) { _updatePolicy = policy; } public void setTrustedKeys(String keys) { _trustedKeys = keys; } public void setUpdateThroughProxy(String foo) { _updateThroughProxy = true; } + public void setProxyHost(String host) { _proxyHost = host; } + public void setProxyPort(String port) { _proxyPort = port; } } 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 1f35886372..a50c2c8d28 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java @@ -1,6 +1,7 @@ package net.i2p.router.web; import java.util.List; +import net.i2p.data.DataHelper; import net.i2p.crypto.TrustedUpdate; import net.i2p.router.RouterContext; @@ -40,6 +41,20 @@ public class ConfigUpdateHelper { else return ConfigUpdateHandler.DEFAULT_UPDATE_URL; } + public String getProxyHost() { + String host = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST); + if (host != null) + return host; + else + return ConfigUpdateHandler.DEFAULT_PROXY_HOST; + } + public String getProxyPort() { + String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT); + if (port != null) + return port; + else + return ConfigUpdateHandler.DEFAULT_PROXY_HOST; + } public String getUpdateThroughProxy() { String proxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY); @@ -50,21 +65,53 @@ public class ConfigUpdateHelper { return ""; } + private static final long PERIODS[] = new long[] { 12*60*60*1000l, 24*60*60*1000l, 48*60*60*1000l, -1l }; + public String getRefreshFrequencySelectBox() { - return ""; + String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY); + if (freq == null) freq = ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY; + long ms = -1; + try { + ms = Long.parseLong(freq); + } catch (NumberFormatException nfe) {} + + StringBuffer buf = new StringBuffer(256); + buf.append("\n"); + return buf.toString(); } + public String getUpdatePolicySelectBox() { - return ""; + String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); + if (policy == null) policy = ConfigUpdateHandler.DEFAULT_UPDATE_POLICY; + + StringBuffer buf = new StringBuffer(256); + buf.append("\n"); + return buf.toString(); } + public String getTrustedKeys() { StringBuffer buf = new StringBuffer(1024); TrustedUpdate up = new TrustedUpdate(_context); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java new file mode 100644 index 0000000000..0405120bcd --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java @@ -0,0 +1,171 @@ +package net.i2p.router.web; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; + +import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; +import net.i2p.router.RouterContext; +import net.i2p.router.RouterVersion; +import net.i2p.util.EepGet; +import net.i2p.util.Log; + +/** + * Task to periodically look for updates to the news.xml, and to keep + * track of whether that has an announcement for a new version. + */ +public class NewsFetcher implements Runnable, EepGet.StatusListener { + private I2PAppContext _context; + private Log _log; + private boolean _updateAvailable; + private long _lastFetch; + private static NewsFetcher _instance; + public static final NewsFetcher getInstance() { return _instance; } + + private static final String NEWS_FILE = "docs/news.xml"; + + public NewsFetcher(I2PAppContext ctx) { + _context = ctx; + _log = ctx.logManager().getLog(NewsFetcher.class); + _instance = this; + File news = new File(NEWS_FILE); + if (news.exists()) + _lastFetch = news.lastModified(); + else + _lastFetch = 0; + } + + public boolean updateAvailable() { return _updateAvailable; } + + public void run() { + try { Thread.sleep(_context.random().nextLong(5*60*1000)); } catch (InterruptedException ie) {} + while (true) { + if (!_updateAvailable) checkForUpdates(); + if (shouldFetchNews()) + fetchNews(); + try { Thread.sleep(10*60*1000); } catch (InterruptedException ie) {} + } + } + + private boolean shouldInstall() { + String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); + return ("install".equals(policy)); + } + + private boolean shouldFetchNews() { + String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY); + if (freq == null) + freq = 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; + } + } + private void fetchNews() { + String newsURL = _context.getProperty(ConfigUpdateHandler.PROP_NEWS_URL, ConfigUpdateHandler.DEFAULT_NEWS_URL); + 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); + String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT); + int proxyPort = -1; + try { + proxyPort = Integer.parseInt(port); + EepGet get = null; + if (shouldProxy) + get = new EepGet(_context, proxyHost, proxyPort, 10, NEWS_FILE, newsURL); + else + get = new EepGet(_context, 10, NEWS_FILE, newsURL); + get.addStatusListener(this); + get.fetch(); + } catch (Throwable t) { + _log.error("Error fetching the news", t); + } + + _lastFetch = _context.clock().now(); + } + + private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\""; + + private void checkForUpdates() { + File news = new File(NEWS_FILE); + if (!news.exists()) return; + FileInputStream in = null; + try { + in = new FileInputStream(news); + StringBuffer buf = new StringBuffer(128); + while (DataHelper.readLine(in, buf)) { + if (buf.indexOf(VERSION_STRING) != -1) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Our version found, no need to update: " + buf.toString()); + return; + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("No match in " + buf.toString()); + } + buf.setLength(0); + } + } catch (IOException ioe) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Error checking the news for an update", ioe); + return; + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + } + // could not find version="0.5.0.1", so there must be an update ;) + + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Our version was NOT found (" + RouterVersion.VERSION + "), update needed"); + _updateAvailable = true; + + if (shouldInstall()) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Policy requests update, so we update"); + UpdateHandler handler = null; + if (_context instanceof RouterContext) { + handler = new UpdateHandler((RouterContext)_context); + } else { + List contexts = RouterContext.listContexts(); + if (contexts.size() > 0) + handler = new UpdateHandler((RouterContext)contexts.get(0)); + else + _log.log(Log.CRIT, "No router context to update with?"); + } + if (handler != null) + handler.update(); + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Policy requests manual update, so we do nothing"); + } + } + + public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) { + // ignore + } + public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) { + // ignore + } + public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile) { + if (_log.shouldLog(Log.INFO)) + _log.info("News fetched from " + url); + checkForUpdates(); + } + + public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Failed to fetch the news from " + url); + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index 1585675293..bff32d5bc4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -4,9 +4,11 @@ import java.io.File; import java.io.IOException; import java.util.List; +import net.i2p.I2PAppContext; import net.i2p.router.RouterContext; import net.i2p.apps.systray.SysTray; import net.i2p.util.FileUtil; +import net.i2p.util.I2PThread; import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.WebApplicationContext; @@ -70,6 +72,10 @@ public class RouterConsoleRunner { } catch (Throwable t) { t.printStackTrace(); } + + I2PThread t = new I2PThread(new NewsFetcher(I2PAppContext.getGlobalContext()), "NewsFetcher"); + t.setDaemon(true); + t.start(); } private void initialize(WebApplicationContext context) { 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 dc878f555f..e7c4400dcd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -468,5 +468,7 @@ public class SummaryHelper { return _context.throttle().getTunnelLag() + "ms"; } - public boolean updateAvailable() { return true; } + public boolean updateAvailable() { + return NewsFetcher.getInstance().updateAvailable(); + } } \ No newline at end of file diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index c2a1535ce7..c2fd838f5b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -24,6 +24,12 @@ public class UpdateHandler { private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; + public UpdateHandler() {} + public UpdateHandler(RouterContext ctx) { + _context = ctx; + _log = ctx.logManager().getLog(UpdateHandler.class); + } + /** * Configure this bean to query a particular router context * @@ -44,20 +50,25 @@ public class UpdateHandler { if (nonce == null) return; if (nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) || nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) { - synchronized (UpdateHandler.class) { - if (_updateRunner == null) - _updateRunner = new UpdateRunner(); - if (_updateRunner.isRunning()) { - return; - } else { - System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true"); - I2PThread update = new I2PThread(_updateRunner, "Update"); - update.start(); - } - } + update(); } } + public void update() { + synchronized (UpdateHandler.class) { + if (_updateRunner == null) + _updateRunner = new UpdateRunner(); + if (_updateRunner.isRunning()) { + return; + } else { + System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true"); + I2PThread update = new I2PThread(_updateRunner, "Update"); + update.start(); + } + } + + } + public String getStatus() { return _updateRunner.getStatus(); } diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index 15f8360793..f1429d7393 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -38,6 +38,8 @@
Update anonymously?
+ Proxy host: " />
+ Proxy port: " />
Trusted keys: diff --git a/apps/routerconsole/jsp/default.css b/apps/routerconsole/jsp/default.css index b83d59e18d..f06e462073 100644 --- a/apps/routerconsole/jsp/default.css +++ b/apps/routerconsole/jsp/default.css @@ -60,3 +60,12 @@ div.main { text-align: left; color: inherit; } + +div.news { + margin: 0em 1em 1em 224px; + padding: .5em 1em; + background-color: #ffffc0; + border: medium solid #ffffd0; + text-align: left; + color: inherit; +} diff --git a/apps/routerconsole/jsp/index.jsp b/apps/routerconsole/jsp/index.jsp index 4b792fc84a..3db0d4d0df 100644 --- a/apps/routerconsole/jsp/index.jsp +++ b/apps/routerconsole/jsp/index.jsp @@ -10,6 +10,13 @@ <%@include file="nav.jsp" %> <%@include file="summary.jsp" %> +
+ + + + +
+
diff --git a/apps/routerconsole/jsp/summary.jsp b/apps/routerconsole/jsp/summary.jsp index 20dbdc3f7e..eeb0ddda2c 100644 --- a/apps/routerconsole/jsp/summary.jsp +++ b/apps/routerconsole/jsp/summary.jsp @@ -28,7 +28,7 @@ uri = uri + "&updateNonce=" + nonce; else uri = uri + "?updateNonce=" + nonce; - out.print(" Update"); + out.print(" Update available"); } } %>
diff --git a/build.xml b/build.xml index 5a1370490d..7a2342df06 100644 --- a/build.xml +++ b/build.xml @@ -222,6 +222,7 @@ + @@ -270,6 +271,8 @@ + + diff --git a/history.txt b/history.txt index e98ea9b7cc..fa62fc66c9 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,14 @@ -$Id: history.txt,v 1.174 2005/03/21 20:38:21 jrandom Exp $ +$Id: history.txt,v 1.175 2005/03/23 16:13:05 jrandom Exp $ + +2005-03-23 jrandom + * Implemented the news fetch / update policy code, as configurated on + /configupdate.jsp. Defaults are to grab the news every 24h (or if it + doesn't exist yet, on startup). No action is taken however, though if + the news.xml specifies that a new release is available, an option to + update will be shown on the router console. + * New initialNews.xml delivered with new installs, and moved news.xml out + of the i2pwww module and into the i2p module so that we can bundle it + within each update. 2005-03-23 jrandom * New /configupdate.jsp page for controlling the update / notification diff --git a/initialNews.xml b/initialNews.xml new file mode 100644 index 0000000000..ac0b4c0e27 --- /dev/null +++ b/initialNews.xml @@ -0,0 +1,14 @@ + + + +

Congratulations on getting I2P installed!

+
+ diff --git a/news.xml b/news.xml new file mode 100644 index 0000000000..788537021d --- /dev/null +++ b/news.xml @@ -0,0 +1,21 @@ + + + +I2P news online! +You can configure how and when this +data is retrieved. It will let your router know when a new release is +available, and will act according to your preferences.
+Status notes +(non-anon) | + Meeting logs +(non-anon)
+
+ diff --git a/readme.html b/readme.html index 7648db7a91..88108d0cce 100644 --- a/readme.html +++ b/readme.html @@ -1,5 +1,3 @@ -

Congratulations on getting I2P installed!

-

If this is your first time running I2P, you will see a link on the left hand side telling you to "reseed" - click that to get connected to the network (you only need to do it if that link shows up). Within 5 minutes, you should see diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a5ec0048db..305d6beee5 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.168 $ $Date: 2005/03/21 20:38:21 $"; + public final static String ID = "$Revision: 1.169 $ $Date: 2005/03/23 16:13:05 $"; public final static String VERSION = "0.5.0.3"; - public final static long BUILD = 2; + public final static long BUILD = 3; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID);