From 7d9ebb5b0b5b750c4121ef356ca5d82976faada3 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Sat, 7 Dec 2019 23:35:16 +0000 Subject: [PATCH] server side of browse host --- .../muwire/core/search/BrowseManager.groovy | 8 +- .../core/search/BrowseStatusEvent.groovy | 2 + .../main/java/com/muwire/core/Persona.java | 8 +- .../java/com/muwire/webui/BrowseManager.java | 75 +++++++++++ .../java/com/muwire/webui/BrowseServlet.java | 116 ++++++++++++++++++ .../java/com/muwire/webui/MuWireClient.java | 7 ++ webui/templates/web.xml.template | 10 ++ 7 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 webui/src/main/java/com/muwire/webui/BrowseManager.java create mode 100644 webui/src/main/java/com/muwire/webui/BrowseServlet.java diff --git a/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy b/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy index 63c560e7..1af73c6b 100644 --- a/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy +++ b/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy @@ -35,7 +35,7 @@ class BrowseManager { browserThread.execute({ Endpoint endpoint = null try { - eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.CONNECTING)) + eventBus.publish(new BrowseStatusEvent(host : e.host, status : BrowseStatus.CONNECTING)) endpoint = connector.connect(e.host.destination) OutputStream os = endpoint.getOutputStream() os.write("BROWSE\r\n".getBytes(StandardCharsets.US_ASCII)) @@ -58,7 +58,7 @@ class BrowseManager { boolean chat = headers.containsKey("Chat") && Boolean.parseBoolean(headers['Chat']) // at this stage, start pulling the results - eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FETCHING, totalResults : results)) + eventBus.publish(new BrowseStatusEvent(host: e.host, status : BrowseStatus.FETCHING, totalResults : results)) JsonSlurper slurper = new JsonSlurper() DataInputStream dis = new DataInputStream(new GZIPInputStream(is)) @@ -73,11 +73,11 @@ class BrowseManager { eventBus.publish(result) } - eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FINISHED)) + eventBus.publish(new BrowseStatusEvent(host: e.host, status : BrowseStatus.FINISHED)) } catch (Exception bad) { log.log(Level.WARNING, "browse failed", bad) - eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FAILED)) + eventBus.publish(new BrowseStatusEvent(host: e.host, status : BrowseStatus.FAILED)) } finally { endpoint?.close() } diff --git a/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy b/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy index 74804e7f..5703574c 100644 --- a/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy +++ b/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy @@ -1,8 +1,10 @@ package com.muwire.core.search import com.muwire.core.Event +import com.muwire.core.Persona class BrowseStatusEvent extends Event { + Persona host BrowseStatus status int totalResults } diff --git a/core/src/main/java/com/muwire/core/Persona.java b/core/src/main/java/com/muwire/core/Persona.java index 70a3a910..54d9bdb2 100644 --- a/core/src/main/java/com/muwire/core/Persona.java +++ b/core/src/main/java/com/muwire/core/Persona.java @@ -73,10 +73,14 @@ public class Persona { return destination; } - public String toBase64() throws DataFormatException, IOException { + public String toBase64() { if (base64 == null) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - write(baos); + try { + write(baos); + } catch (Exception impossible) { + throw new RuntimeException(impossible); + } base64 = Base64.encode(baos.toByteArray()); } return base64; diff --git a/webui/src/main/java/com/muwire/webui/BrowseManager.java b/webui/src/main/java/com/muwire/webui/BrowseManager.java new file mode 100644 index 00000000..d9d258fa --- /dev/null +++ b/webui/src/main/java/com/muwire/webui/BrowseManager.java @@ -0,0 +1,75 @@ +package com.muwire.webui; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.muwire.core.Core; +import com.muwire.core.Persona; +import com.muwire.core.search.BrowseStatus; +import com.muwire.core.search.BrowseStatusEvent; +import com.muwire.core.search.UIBrowseEvent; +import com.muwire.core.search.UIResultEvent; + +public class BrowseManager { + + private final Core core; + private final Map browses = new ConcurrentHashMap<>(); + + public BrowseManager(Core core) { + this.core = core; + } + + public void onBrowseStatusEvent(BrowseStatusEvent e) { + Browse browse = browses.get(e.getHost()); + if (browse == null) + return; // hmm + browse.status = e.getStatus(); + if (browse.status == BrowseStatus.FETCHING) + browse.totalResults = e.getTotalResults(); + } + + public void onUIResultEvent(UIResultEvent e) { + Browse browse = browses.get(e.getSender()); + if (browse == null) + return; + browse.results.add(e); + } + + void browse(Persona p) { + Browse browse = new Browse(p); + browses.put(p, browse); + UIBrowseEvent event = new UIBrowseEvent(); + event.setHost(p); + core.getEventBus().publish(event); + } + + Map getBrowses(){ + return browses; + } + + static class Browse { + private final Persona persona; + private volatile BrowseStatus status; + private volatile int totalResults; + private final List results = Collections.synchronizedList(new ArrayList<>()); + + Browse(Persona persona) { + this.persona = persona; + } + + public BrowseStatus getStatus() { + return status; + } + + public int getTotalResults() { + return totalResults; + } + + public List getResults() { + return results; + } + } +} diff --git a/webui/src/main/java/com/muwire/webui/BrowseServlet.java b/webui/src/main/java/com/muwire/webui/BrowseServlet.java new file mode 100644 index 00000000..39b683af --- /dev/null +++ b/webui/src/main/java/com/muwire/webui/BrowseServlet.java @@ -0,0 +1,116 @@ +package com.muwire.webui; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.muwire.core.Persona; +import com.muwire.webui.BrowseManager.Browse; + +import net.i2p.data.Base64; +import net.i2p.data.DataHelper; + +public class BrowseServlet extends HttpServlet { + + private BrowseManager browseManager; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String section = req.getParameter("section"); + if (section == null) { + resp.sendError(403, "Bad section param"); + return; + } + + StringBuilder sb = new StringBuilder(); + sb.append(""); + + if (section.equals("status")) { + sb.append(""); + browseManager.getBrowses().forEach( (persona, browse) -> { + sb.append(""); + sb.append("").append(Util.escapeHTMLinXML(persona.getHumanReadableName())).append(""); + sb.append("").append(persona.toBase64()).append(""); + sb.append("").append(browse.getStatus()).append(""); + sb.append("").append(browse.getTotalResults()).append(""); + sb.append("").append(browse.getResults().size()).append(""); + sb.append(""); + }); + sb.append(""); + } else if (section.equals("results")) { + String hostB64 = req.getParameter("host"); + if (hostB64 == null) { + resp.sendError(403,"Bad param"); + return; + } + Persona host; + try { + host = new Persona(new ByteArrayInputStream(Base64.decode(hostB64))); + } catch (Exception bad) { + resp.sendError(403, "Bad param"); + return; + } + + Browse browse = browseManager.getBrowses().get(host); + if (browse == null) + return; // hmm + + sb.append(""); + browse.getResults().forEach(result -> { + sb.append(""); + sb.append("").append(Util.escapeHTMLinXML(result.getName())).append(""); + sb.append("").append(DataHelper.formatSize2Decimal(result.getSize(), false)).append("B").append(""); + if (result.getComment() != null) { + sb.append("").append(Util.escapeHTMLinXML(result.getComment())).append(""); + } + // TODO: add more fields + sb.append(""); + }); + sb.append(""); + } + resp.setContentType("text/xml"); + resp.setCharacterEncoding("UTF-8"); + resp.setDateHeader("Expires", 0); + resp.setHeader("Pragma", "no-cache"); + resp.setHeader("Cache-Control", "no-store, max-age=0, no-cache, must-revalidate"); + byte[] out = sb.toString().getBytes("UTF-8"); + resp.setContentLength(out.length); + resp.getOutputStream().write(out); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String action = req.getParameter("action"); + if (action == null) { + resp.sendError(403,"Bad param"); + return; + } + if (action.equals("browse")) { + String personaB64 = req.getParameter("host"); + if (personaB64 == null) { + resp.sendError(403,"Bad param"); + return; + } + Persona host; + try { + host = new Persona(new ByteArrayInputStream(Base64.decode(personaB64))); + } catch (Exception bad) { + resp.sendError(403,"Bad param"); + return; + } + browseManager.browse(host); + resp.sendRedirect("/MuWire/BrowseHost.jsp"); + } // TODO: implement canceling of browse + } + + @Override + public void init(ServletConfig cfg) throws ServletException { + browseManager = (BrowseManager) cfg.getServletContext().getAttribute("browseManager"); + } + +} diff --git a/webui/src/main/java/com/muwire/webui/MuWireClient.java b/webui/src/main/java/com/muwire/webui/MuWireClient.java index 2abb8746..9f51ea20 100644 --- a/webui/src/main/java/com/muwire/webui/MuWireClient.java +++ b/webui/src/main/java/com/muwire/webui/MuWireClient.java @@ -26,7 +26,9 @@ import com.muwire.core.files.FileDownloadedEvent; import com.muwire.core.files.FileHashedEvent; import com.muwire.core.files.FileHashingEvent; import com.muwire.core.files.FileLoadedEvent; +import com.muwire.core.search.BrowseStatusEvent; import com.muwire.core.search.UIResultBatchEvent; +import com.muwire.core.search.UIResultEvent; import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppState; @@ -133,10 +135,15 @@ public class MuWireClient { core.getEventBus().register(FileDownloadedEvent.class, fileManager); core.getEventBus().register(FileHashingEvent.class, fileManager); + BrowseManager browseManager = new BrowseManager(core); + core.getEventBus().register(BrowseStatusEvent.class, browseManager); + core.getEventBus().register(UIResultEvent.class, browseManager); + servletContext.setAttribute("searchManager", searchManager); servletContext.setAttribute("downloadManager", downloadManager); servletContext.setAttribute("connectionCounter", connectionCounter); servletContext.setAttribute("fileManager", fileManager); + servletContext.setAttribute("browseManager", browseManager); core.getEventBus().publish(new UILoadedEvent()); } diff --git a/webui/templates/web.xml.template b/webui/templates/web.xml.template index 9c718f35..df99f7d8 100644 --- a/webui/templates/web.xml.template +++ b/webui/templates/web.xml.template @@ -31,6 +31,11 @@ com.muwire.webui.FilesServlet + + com.muwire.webui.BrowseServlet + com.muwire.webui.BrowseServlet + + com.muwire.webui.MuWireServlet /index.jsp @@ -51,6 +56,11 @@ /Files + + com.muwire.webui.BrowseServlet + /Browse + + __JASPER__