added actual form handling to the main config.jsp page

dropped the old notice.jsp style result notification
display destination info on the left nav
This commit is contained in:
jrandom
2004-07-31 02:34:24 +00:00
committed by zzz
parent 7b60d3dab9
commit ed9f9625ae
13 changed files with 419 additions and 16 deletions

View File

@ -0,0 +1,291 @@
package net.i2p.router.web;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
/**
* Handler to deal with form submissions from the main config form and act
* upon the values.
*
*/
public class ConfigNetHandler extends FormHandler {
private String _hostname;
private boolean _guessRequested;
private boolean _reseedRequested;
private boolean _saveRequested;
private boolean _timeSyncEnabled;
private String _port;
private String _inboundRate;
private String _inboundBurst;
private String _outboundRate;
private String _outboundBurst;
private String _reseedFrom;
public void ConfigNetHandler() {
_guessRequested = false;
_reseedRequested = false;
_saveRequested = false;
_timeSyncEnabled = false;
}
protected void processForm() {
if (_guessRequested) {
guessHostname();
} else if (_reseedRequested) {
reseed();
} else if (_saveRequested) {
saveChanges();
} else {
// noop
}
}
public void setGuesshost(String moo) { _guessRequested = true; }
public void setReseed(String moo) { _reseedRequested = true; }
public void setSave(String moo) { _saveRequested = true; }
public void setEnabletimesync(String moo) { _timeSyncEnabled = true; }
public void setHostname(String hostname) {
_hostname = (hostname != null ? hostname.trim() : null);
}
public void setPort(String port) {
_port = (port != null ? port.trim() : null);
}
public void setInboundrate(String rate) {
_inboundRate = (rate != null ? rate.trim() : null);
}
public void setInboundburstfactor(String factor) {
_inboundBurst = (factor != null ? factor.trim() : null);
}
public void setOutboundrate(String rate) {
_outboundRate = (rate != null ? rate.trim() : null);
}
public void setOutboundburstfactor(String factor) {
_outboundBurst = (factor != null ? factor.trim() : null);
}
public void setReseedfrom(String url) {
_reseedFrom = (url != null ? url.trim() : null);
}
private static final String IP_PREFIX = "<h1>Your IP is ";
private static final String IP_SUFFIX = " <br></h1>";
private void guessHostname() {
BufferedReader reader = null;
try {
URL url = new URL("http://www.whatismyip.com/");
URLConnection con = url.openConnection();
con.connect();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line = null;
while ( (line = reader.readLine()) != null) {
if (line.startsWith(IP_PREFIX)) {
int end = line.indexOf(IP_SUFFIX);
if (end == -1) {
addFormError("Unable to guess the host (BAD_SUFFIX)");
return;
}
String ip = line.substring(IP_PREFIX.length(), end);
addFormNotice("Host guess: " + ip);
return;
}
}
addFormError("Unable to guess the host (NO_PREFIX)");
} catch (IOException ioe) {
addFormError("Unable to guess the host (IO_ERROR)");
} finally {
if (reader != null) try { reader.close(); } catch (IOException ioe) {}
}
}
private static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb/";
/**
* Reseed has been requested, so lets go ahead and do it. Fetch all of
* the routerInfo-*.dat files from the specified URL (or the default) and
* save them into this router's netDb dir.
*
*/
private void reseed() {
String seedURL = DEFAULT_SEED_URL;
if (_reseedFrom != null)
seedURL = _reseedFrom;
try {
URL dir = new URL(seedURL);
String content = new String(readURL(dir));
Set urls = new HashSet();
int cur = 0;
while (true) {
int start = content.indexOf("href=\"routerInfo-", cur);
if (start < 0)
break;
int end = content.indexOf(".dat\">", start);
String name = content.substring(start+"href=\"routerInfo-".length(), end);
urls.add(name);
cur = end + 1;
}
int fetched = 0;
for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
fetchSeed(seedURL, (String)iter.next());
fetched++;
}
addFormNotice("Reseeded with " + fetched + " peers");
} catch (Throwable t) {
_context.logManager().getLog(ConfigNetHandler.class).error("Error reseeding", t);
addFormError("Error reseeding (RESEED_EXCEPTION)");
}
}
private void fetchSeed(String seedURL, String peer) throws Exception {
URL url = new URL(seedURL + "/routerInfo-" + peer + ".dat");
byte data[] = readURL(url);
writeSeed(peer, data);
}
private byte[] readURL(URL url) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
URLConnection con = url.openConnection();
InputStream in = con.getInputStream();
byte buf[] = new byte[1024];
while (true) {
int read = in.read(buf);
if (read < 0)
break;
baos.write(buf, 0, read);
}
in.close();
return baos.toByteArray();
}
private void writeSeed(String name, byte data[]) throws Exception {
// props taken from KademliaNetworkDatabaseFacade...
String dirName = _context.getProperty("router.networkDatabase.dbDir", "netDb");
File netDbDir = new File(dirName);
if (!netDbDir.exists()) {
boolean ok = netDbDir.mkdirs();
if (ok)
addFormNotice("Network database directory created: " + dirName);
else
addFormNotice("Error creating network database directory: " + dirName);
}
FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
fos.write(data);
fos.close();
}
/**
* The user made changes to the network config and wants to save them, so
* lets go ahead and do so.
*
*/
private void saveChanges() {
boolean restartRequired = false;
if ( (_hostname != null) && (_hostname.length() > 0) ) {
String oldHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_HOSTNAME);
if ( (oldHost == null) || (!oldHost.equalsIgnoreCase(_hostname)) ) {
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_HOSTNAME, _hostname);
addFormNotice("Updating hostname from " + oldHost + " to " + _hostname);
restartRequired = true;
}
}
if ( (_port != null) && (_port.length() > 0) ) {
String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT);
if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_port)) ) {
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _port);
addFormNotice("Updating TCP port from " + oldPort + " to " + _port);
restartRequired = true;
}
}
updateRates();
if (_timeSyncEnabled) {
System.setProperty("timestamper.enabled", "true");
} else {
System.setProperty("timestamper.enabled", "false");
}
boolean saved = _context.router().saveConfig();
if (saved)
addFormNotice("Configuration saved successfully");
else
addFormNotice("Error saving the configuration (applied but not saved) - please see the error logs");
if (restartRequired) {
addFormNotice("Performing a soft restart");
_context.router().restart();
addFormNotice("Soft restart complete");
}
}
private void updateRates() {
boolean updated = false;
if ( (_inboundRate != null) && (_inboundRate.length() > 0) ) {
_context.router().setConfigSetting(ConfigNetHelper.PROP_INBOUND_KBPS, _inboundRate);
updated = true;
}
if ( (_outboundRate != null) && (_outboundRate.length() > 0) ) {
_context.router().setConfigSetting(ConfigNetHelper.PROP_OUTBOUND_KBPS, _outboundRate);
updated = true;
}
String inRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_INBOUND_KBPS);
if (_inboundBurst != null) {
int rateKBps = 0;
int burstSeconds = 0;
try {
rateKBps = Integer.parseInt(inRate);
burstSeconds = Integer.parseInt(_inboundBurst);
} catch (NumberFormatException nfe) {
// ignore
}
if ( (rateKBps > 0) && (burstSeconds > 0) ) {
int kb = rateKBps * burstSeconds;
_context.router().setConfigSetting(ConfigNetHelper.PROP_INBOUND_BURST, "" + kb);
updated = true;
}
}
String outRate = _context.router().getConfigSetting(ConfigNetHelper.PROP_OUTBOUND_KBPS);
if (_outboundBurst != null) {
int rateKBps = 0;
int burstSeconds = 0;
try {
rateKBps = Integer.parseInt(outRate);
burstSeconds = Integer.parseInt(_outboundBurst);
} catch (NumberFormatException nfe) {
// ignore
}
if ( (rateKBps > 0) && (burstSeconds > 0) ) {
int kb = rateKBps * burstSeconds;
_context.router().setConfigSetting(ConfigNetHelper.PROP_OUTBOUND_BURST, "" + kb);
updated = true;
}
}
if (updated)
addFormNotice("Updated bandwidth limits");
}
}

View File

@ -30,8 +30,8 @@ public class ConfigNetHelper {
public ConfigNetHelper() {}
/** copied from various private TCP components */
private final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname";
private final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port";
public final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname";
public final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port";
public String getHostname() {
return _context.getProperty(PROP_I2NP_TCP_HOSTNAME);

View File

@ -0,0 +1,109 @@
package net.i2p.router.web;
import java.util.List;
import java.util.ArrayList;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
/**
* Simple form handler base class - does not depend on servlets or jsp,
* but instead the subclasses are populated with javabean properties. e.g.
* <jsp:setProperty name="handler" property="*" />
*
* The form is "processed" after the properties are set and the first output
* property is retrieved - either getNotices() or getErrors().
*
*/
public class FormHandler {
protected RouterContext _context;
private List _errors;
private List _notices;
private boolean _processed;
public FormHandler() {
_errors = new ArrayList();
_notices = new ArrayList();
_processed = false;
}
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
/**
* Override this to perform the final processing (in turn, adding formNotice
* and formError messages, etc)
*
*/
protected void processForm() {}
/**
* Add an error message to display
*/
protected void addFormError(String errorMsg) {
if (errorMsg == null) return;
_errors.add(errorMsg);
}
/**
* Add a non-error message to display
*/
protected void addFormNotice(String msg) {
if (msg == null) return;
_notices.add(msg);
}
/**
* Display any error messages (processing the form if it hasn't
* been yet)
*
*/
public String getErrors() {
return render(_errors);
}
/**
* Display any non-error messages (processing the form if it hasn't
* been yet)
*
*/
public String getNotices() {
return render(_notices);
}
private String render(List source) {
if (!_processed) {
processForm();
_processed = true;
}
if (source.size() <= 0) {
return "";
} else if (source.size() == 1) {
return (String)source.get(0);
} else {
StringBuffer buf = new StringBuffer(512);
buf.append("<ul>\n");
for (int i = 0; i < source.size(); i++) {
buf.append("<li>");
buf.append((String)source.get(i));
buf.append("</li>\n");
}
buf.append("</ul>\n");
return buf.toString();
}
}
}

View File

@ -1,5 +1,4 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@page contentType="text/html" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
@ -9,13 +8,19 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigNetHelper" id="nethelper" scope="request" />
<jsp:setProperty name="nethelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<div class="main" id="main">
<%@include file="confignav.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigNetHandler" id="formhandler" scope="request" />
<jsp:setProperty name="formhandler" property="*" />
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<font color="red"><jsp:getProperty name="formhandler" property="errors" /></font>
<i><jsp:getProperty name="formhandler" property="notices" /></i>
<form action="config.jsp" method="POST">
<b>External hostname/IP address:</b>
<input name="hostname" type="text" size="32" value="<jsp:getProperty name="nethelper" property="hostname" />" />
@ -29,7 +34,10 @@
to <a href="http://www.whatismyip.com/">www.whatismyip.com</a>.</i>
<hr />
<b>Enable internal time synchronization?</b> <input type="checkbox" <jsp:getProperty name="nethelper" property="enableTimeSyncChecked" /> name="enabletimesync" /><br />
<i>If disabled, your machine <b>must</b> be NTP synchronized</i>
<i>If disabled, your machine <b>must</b> be NTP synchronized. This option only
takes effect for the current run - if your machine is always synchronized within
(a few seconds), you can update your configuration so that it doesn't start the
"Timestamper" app (which would make this option irrelevent)</i>
<hr />
<b>Bandwidth limiter</b><br />
<b>Inbound rate</b>:
@ -44,8 +52,12 @@
<hr />
<b>Reseed</b> (from <input name="reseedfrom" type="text" size="40" value="http://dev.i2p.net/i2pdb/" />):
<input type="submit" name="reseed" value="now" /><br />
<i>May take some time to download the peer references</i>
<hr />
<input type="submit" value="Save changes" /> <input type="reset" value="Cancel" />
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
<i>Changing the hostname or TCP port will force a 'soft restart' - dropping your connections
and clients as if the router was stopped and restarted. <b>Please be patient</b> - it may take
a few seconds to complete.</i>
</form>
</div>

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigAdvancedHelper" id="advancedhelper" scope="request" />
<jsp:setProperty name="advancedhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigClientsHelper" id="clientshelper" scope="request" />
<jsp:setProperty name="clientshelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />

View File

@ -11,7 +11,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<%@include file="confignav.jsp" %>

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
hmm. we should probably have some help text here.<br />

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<h2>Welcome to your router console</h2>

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" />

View File

@ -1 +0,0 @@
<%=(null != request.getParameter("i2p.console.notice") ? request.getParameter("i2p.console.notice") : "")%>

View File

@ -9,7 +9,6 @@
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />