From dc343b05a2f26a1730715628272e1b60111dd61f Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Thu, 15 Nov 2018 14:24:46 +0000
Subject: [PATCH] MLab/NDT: Hook test to wizard Make helper the session scope,
 not handler Reduce whitespace in formhandler.jsi Notes on why FormHandler
 can't be session scope Ajax still TODO

---
 .../src/net/i2p/router/web/FormHandler.java   |   2 +
 .../i2p/router/web/helpers/WizardHandler.java | 155 ++++-------------
 .../i2p/router/web/helpers/WizardHelper.java  | 157 ++++++++++++++++++
 apps/routerconsole/jsp/formhandler.jsi        |   8 +-
 apps/routerconsole/jsp/welcome.jsp            |  32 ++--
 5 files changed, 213 insertions(+), 141 deletions(-)

diff --git a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
index eec72e2f62..7681196748 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/FormHandler.java
@@ -18,6 +18,8 @@ import net.i2p.util.Log;
  * The form is "processed" after the properties are set and the first output
  * property is retrieved - either getAll(), getNotices() or getErrors().
  *
+ * This Handler will only process a single POST. The jsp bean must be declared scope=request.
+ *
  */
 public abstract class FormHandler {
     protected RouterContext _context;
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHandler.java
index 7bf50fbddc..646f84e5b3 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHandler.java
@@ -2,9 +2,6 @@ package net.i2p.router.web.helpers;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import com.vuze.plugins.mlab.MLabRunner;
 
 import net.i2p.router.Router;
 import net.i2p.router.transport.FIFOBandwidthRefiller;
@@ -12,28 +9,35 @@ import net.i2p.router.web.FormHandler;
 
 /**
  *  The new user wizard.
- *  This bean has SESSION scope so the results may be retrieved.
- *  All necessary methods are synchronized.
+ *
+ *  This handler has request scope (as all FormHandlers must), so it controls
+ *  the test via the helper, which has session scope.
  *
  *  @since 0.9.38
  */
 public class WizardHandler extends FormHandler {
 
-    // session scope, but it's an underlying singleton
-    private MLabRunner _mlab;
-    // session scope
-    private TestListener _listener;
-
-    @Override
-    public void setContextId(String contextId) {
-        super.setContextId(contextId);
-        _mlab = MLabRunner.getInstance(_context);
-    }
+    private WizardHelper _helper;
     
+    /**
+     *  Bind the helper (scope session) to this handler (scope request)
+     */
+    public void setWizardHelper(WizardHelper helper) {
+        _helper = helper;
+    }
+
     @Override
     protected void processForm() {
+{
+String page = getJettyString("page");
+System.out.println("Action: " + _action + " page: " + page);
+}
         if (_action == null)
             return;
+        if (getJettyString("cancelbw") != null) {
+            cancelNDT();
+            return;
+        }
         if (getJettyString("next") == null)
             return;
         if (_action.equals("blah")) {
@@ -44,7 +48,9 @@ public class WizardHandler extends FormHandler {
                 // Saved in CSSHelper, assume success
                 addFormNoticeNoEscape(_t("Console language saved."));
             }
-            if ("6".equals(page)) {
+            if ("4".equals(page)) {
+                startNDT();
+            } else if ("6".equals(page)) {
                 Map<String, String> changes = new HashMap<String, String>();
                 boolean updated = updateRates(changes);
                 if (updated) {
@@ -116,120 +122,25 @@ public class WizardHandler extends FormHandler {
         return updated; 
     }
 
-    public synchronized boolean isNDTComplete() {
-        return _listener != null && _listener.isComplete();
-    }
-
-    public synchronized boolean isNDTRunning() {
-        return _listener != null && !_listener.isComplete();
-    }
-
-    /**
-     * @return status string or null
-     */
-    public synchronized String getCompletionStatus() {
-        return _listener != null ? _listener.getSummary() : null;
-    }
-
-    /**
-     * @return status string or null
-     */
-    public synchronized String getDetailStatus() {
-        return _listener != null ? _listener.getDetail() : null;
-    }
-
-    /**
-     * @return bytes per second or 0
-     */
-    public long getUpBandwidth() {
-        return getLongResult("up");
-    }
-
-    /**
-     * @return bytes per second or 0
-     */
-    public long getDownBandwidth() {
-        return getLongResult("down");
-    }
-
-    public synchronized long getLongResult(String key) {
-        if (_listener != null) {
-            Map<String, Object> results = _listener.getResults();
-            if (results != null) {
-                Long v = (Long) results.get(key);
-                if (v != null)
-                    return v.longValue();
-            }
-        }
-        return 0;
-    }
-
     /** start the test */
-    public synchronized void startNDT() {
-        if (_mlab.isRunning() || _listener != null && !_listener.isComplete()) {
-            addFormError(_t("Bandwidth test is already running"));
-            return;
-        }
-        _listener = new TestListener();
-        MLabRunner.ToolRun runner = _mlab.runNDT(_listener);
-        if (runner != null) {
+    private void startNDT() {
+        if (_helper == null) {
+            addFormError("Bad state for test");
+        } else if (_helper.startNDT()) {
             addFormNotice(_t("Started bandwidth test"));
         } else {
-            Map<String, Object> map = new HashMap<String, Object>(2);
-            _listener.complete(map);
             addFormError(_t("Bandwidth test is already running"));
         }
     }
 
     /** cancel the test */
-    public synchronized void cancelNDT() {
-        synchronized(WizardHandler.class) {
-            if (!_mlab.isRunning()) {
-                addFormError(_t("Bandwidth test was not running"));
-                return;
-            }
-/****
-TODO
-            if (runner != null)
-                addFormNotice(_t("Started bandwidth test"));
-            else
-                addFormError(_t("Bandwidth test is already running"));
-****/
-        }
-    }
-
-    /** test results */
-    private static class TestListener implements MLabRunner.ToolListener {
-        private String _summary, _detail;
-        private Map<String, Object> _results;
-
-        public synchronized void reportSummary(String str) {
-            _summary = str;
-        }
-
-        public synchronized void reportDetail(String str) {
-            _detail = str;
-        }
-
-        public synchronized void complete(Map<String, Object> results) {
-            _results = results;
-        }
-
-        public synchronized boolean isComplete() {
-            return _results != null;
-        }
-
-        public synchronized String getSummary() {
-            return _summary;
-        }
-
-        public synchronized String getDetail() {
-            return _detail;
-        }
-
-        public synchronized Map<String, Object> getResults() {
-            return _results;
+    private void cancelNDT() {
+        if (_helper == null) {
+            addFormError("Bad state for test");
+        } else if (_helper.cancelNDT()) {
+            addFormNotice(_t("Candelled bandwidth test"));
+        } else {
+            addFormError(_t("Bandwidth test was not running"));
         }
     }
-
 }
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHelper.java
index c3a326d006..f9ea1c346a 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/WizardHelper.java
@@ -1,17 +1,174 @@
 package net.i2p.router.web.helpers;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vuze.plugins.mlab.MLabRunner;
+
+import net.i2p.data.DataHelper;
 import net.i2p.router.web.HelperBase;
 
 /**
  *  The new user wizard.
  *
+ *  This bean has SESSION scope so the results may be retrieved.
+ *  All necessary methods are synchronized.
+ *
  *  @since 0.9.38
  */
 public class WizardHelper extends HelperBase {
 
     public static final String PROP_COMPLETE = "routerconsole.welcomeWizardComplete";
 
+    // session scope, but it's an underlying singleton
+    private MLabRunner _mlab;
+
+    // session scope
+    private TestListener _listener;
+    private MLabRunner.ToolRun _runner;
+
+    /**
+     * Overriden to only do this once.
+     */
+    @Override
+    public void setContextId(String contextId) {
+        if (_context == null) {
+            super.setContextId(contextId);
+            _mlab = MLabRunner.getInstance(_context);
+        }
+    }
+
     public void complete() {
         _context.router().saveConfig(PROP_COMPLETE, "true");
     }
+
+    public synchronized boolean isNDTComplete() {
+        return _listener != null && _listener.isComplete();
+    }
+
+    public synchronized boolean isNDTRunning() {
+        return _listener != null && !_listener.isComplete();
+    }
+
+    /**
+     * @return HTML-escaped status string or ""
+     */
+    public synchronized String getCompletionStatus() {
+        String rv = "";
+        if (_listener != null) {
+            String s = _listener.getSummary();
+            if (s != null)
+                s = DataHelper.escapeHTML(s);
+        }
+        return rv;
+    }
+
+    /**
+     * @return HTML-escaped status string or ""
+     */
+    public synchronized String getDetailStatus() {
+        String rv = "";
+        if (_listener != null) {
+            String s = _listener.getDetail();
+            if (s != null)
+                s = DataHelper.escapeHTML(s);
+        }
+        return rv;
+    }
+
+    /**
+     * @return bytes per second or 0
+     */
+    public long getUpBandwidth() {
+        return getLongResult("up");
+    }
+
+    /**
+     * @return bytes per second or 0
+     */
+    public long getDownBandwidth() {
+        return getLongResult("down");
+    }
+
+    public synchronized long getLongResult(String key) {
+        if (_listener != null) {
+            Map<String, Object> results = _listener.getResults();
+            if (results != null) {
+                Long v = (Long) results.get(key);
+                if (v != null)
+                    return v.longValue();
+            }
+        }
+        return 0;
+    }
+
+    /**
+     *  Start the test. Called from the Handler.
+     *  @return success
+     */
+    synchronized boolean startNDT() {
+        if (_mlab.isRunning() || _listener != null && !_listener.isComplete()) {
+            return false;
+        }
+        _listener = new TestListener();
+        _runner = _mlab.runNDT(_listener);
+        if (_runner != null) {
+            return true;
+        } else {
+            Map<String, Object> map = new HashMap<String, Object>(2);
+            _listener.complete(map);
+            return false;
+        }
+    }
+
+    /**
+     *  Cancel the test. Called from the Handler.
+     *  @return success
+     */
+    synchronized boolean cancelNDT() {
+        if (!_mlab.isRunning()) {
+            return false;
+        }
+        if (_runner != null) {
+            _runner.cancel();
+            _runner = null;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /** test results */
+    private static class TestListener implements MLabRunner.ToolListener {
+        private String _summary, _detail;
+        private Map<String, Object> _results;
+
+        public synchronized void reportSummary(String str) {
+            _summary = str;
+        }
+
+        public synchronized void reportDetail(String str) {
+            _detail = str;
+        }
+
+        public synchronized void complete(Map<String, Object> results) {
+            _results = results;
+        }
+
+        public synchronized boolean isComplete() {
+            return _results != null;
+        }
+
+        public synchronized String getSummary() {
+            return _summary;
+        }
+
+        public synchronized String getDetail() {
+            return _detail;
+        }
+
+        public synchronized Map<String, Object> getResults() {
+            return _results;
+        }
+    }
 }
diff --git a/apps/routerconsole/jsp/formhandler.jsi b/apps/routerconsole/jsp/formhandler.jsi
index e168cc7373..21ced430b0 100644
--- a/apps/routerconsole/jsp/formhandler.jsi
+++ b/apps/routerconsole/jsp/formhandler.jsi
@@ -50,13 +50,9 @@
         // Put all the params in the map, some handlers use this instead of individual setters
         // We also call all of the setters below.
         formhandler.setSettings(request.getParameterMap());
-%>
-<jsp:setProperty name="formhandler" property="*" />
-<%
+%><jsp:setProperty name="formhandler" property="*" /><%
     }
-%>
-<jsp:getProperty name="formhandler" property="allMessages" />
-<%
+%><jsp:getProperty name="formhandler" property="allMessages" /><%
 
     // Only call this once per page, do not getProperty("newNonce") elsewhere,
     // use the variable instead.
diff --git a/apps/routerconsole/jsp/welcome.jsp b/apps/routerconsole/jsp/welcome.jsp
index 906040c6b8..a7c9edf950 100644
--- a/apps/routerconsole/jsp/welcome.jsp
+++ b/apps/routerconsole/jsp/welcome.jsp
@@ -1,4 +1,8 @@
-<%@page contentType="text/html"%><%@page pageEncoding="UTF-8"%><jsp:useBean class="net.i2p.router.web.helpers.WizardHelper" id="wizhelper" scope="request" /><%
+<%@page contentType="text/html"%><%@page pageEncoding="UTF-8"%><jsp:useBean class="net.i2p.router.web.helpers.WizardHelper" id="wizhelper" scope="session" /><%
+    // note that for the helper we use a session scope, not a request scope,
+    // so that we can access the NDT test results.
+    // The MLabHelper singleton will prevent multiple simultaneous tests, even across sessions.
+
     // page ID
     final int LAST_PAGE = 7;
     String pg = request.getParameter("page");
@@ -59,6 +63,7 @@
 <%@include file="css.jsi" %>
 <%=intl.title("New Install Wizard")%>
 <%
+    wizhelper.setContextId(i2pcontextId);
     if (ipg == 4) {
 %>
 <script src="/js/ajax.js" type="text/javascript"></script>
@@ -84,19 +89,17 @@
 %>
 <h2><%=intl._t("New Install Wizard")%> <%=ipg%>/<%=LAST_PAGE%></h2>
 <div id="wizard">
-<%--
-    // note that for the handler we use a session scope, not a page scope,
-    // so that we can access the NDT test results.
-    // The MLabHelper singleton will prevent multiple simultaneous tests, even across sessions.
---%>
-<jsp:useBean class="net.i2p.router.web.helpers.WizardHandler" id="formhandler" scope="session" />
+<jsp:useBean class="net.i2p.router.web.helpers.WizardHandler" id="formhandler" scope="request" />
+<%
+    // Bind the session-scope Helper to the request-scope Handler
+    formhandler.setWizardHelper(wizhelper);
+%>
 <%@include file="formhandler.jsi" %>
 <form action="" method="POST">
 <input type="hidden" name="nonce" value="<%=pageNonce%>">
 <input type="hidden" name="action" value="blah" >
 <input type="hidden" name="page" value="<%=(ipg + 1)%>" >
 <%
-
     if (ipg == 1) {
         // language selection
 %>
@@ -141,7 +144,7 @@
         // Bandwidth test in progress (w/ AJAX)
 %>
 <h3><%=intl._t("Bandwidth Test in Progress")%></h3>
-<p>TODO</p>
+<p>Ajax TODO - wait 60 seconds then click next</p>
 <%
 
     } else if (ipg == 5) {
@@ -152,9 +155,12 @@
 <jsp:setProperty name="nethelper" property="contextId" value="<%=i2pcontextId%>" />
 <h3><%=intl._t("Bandwidth Test Results")%></h3>
 <table class="configtable">
-<tr><td>
-Test results go here
-</td></tr>
+<tr><td><%=intl._t("Test running?")%></td><td><%=wizhelper.isNDTRunning()%></td></tr>
+<tr><td><%=intl._t("Test complete?")%></td><td><%=wizhelper.isNDTComplete()%></td></tr>
+<tr><td><%=intl._t("Completion status")%></td><td><%=wizhelper.getCompletionStatus()%></td></tr>
+<tr><td><%=intl._t("Details")%></td><td><%=wizhelper.getDetailStatus()%></td></tr>
+<tr><td><%=intl._t("Upstream Bandwidth")%></td><td><%=net.i2p.data.DataHelper.formatSize2Decimal(wizhelper.getUpBandwidth())%>Bps</td></tr>
+<tr><td><%=intl._t("Downstream Bandwidth")%></td><td><%=net.i2p.data.DataHelper.formatSize2Decimal(wizhelper.getDownBandwidth())%>Bps</td></tr>
 </table>
 <h3><%=intl._t("Bandwidth Configuration")%></h3>
 <table id="bandwidthconfig" class="configtable">
@@ -245,6 +251,6 @@ Test results go here
 <%
     }
 %>
-</td></tr></table>
+</td></tr></table></div>
 </form>
 </div></body></html>
-- 
GitLab