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 dd6cdc9b1..e75f6e0b6 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 1f3588637..a50c2c8d2 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 000000000..0405120bc
--- /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 158567529..bff32d5bc 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 dc878f555..e7c4400dc 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 c2a1535ce..c2fd838f5 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 15f836079..f1429d739 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 b83d59e18..f06e46207 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 4b792fc84..3db0d4d0d 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 20dbdc3f7..eeb0ddda2 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 5a1370490..7a2342df0 100644
--- a/build.xml
+++ b/build.xml
@@ -222,6 +222,7 @@
+
@@ -270,6 +271,8 @@
+
+
diff --git a/history.txt b/history.txt
index e98ea9b7c..fa62fc66c 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 000000000..ac0b4c0e2
--- /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 000000000..788537021
--- /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 7648db7a9..88108d0cc 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 a5ec0048d..305d6beee 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);