diff --git a/core/src/main/groovy/com/muwire/core/Core.groovy b/core/src/main/groovy/com/muwire/core/Core.groovy index 6b3c1e6a..b9b267a2 100644 --- a/core/src/main/groovy/com/muwire/core/Core.groovy +++ b/core/src/main/groovy/com/muwire/core/Core.groovy @@ -37,11 +37,13 @@ import com.muwire.core.hostcache.CacheClient import com.muwire.core.hostcache.HostCache import com.muwire.core.hostcache.HostDiscoveredEvent import com.muwire.core.mesh.MeshManager +import com.muwire.core.search.BrowseManager import com.muwire.core.search.QueryEvent import com.muwire.core.search.ResultsEvent import com.muwire.core.search.ResultsSender import com.muwire.core.search.SearchEvent import com.muwire.core.search.SearchManager +import com.muwire.core.search.UIBrowseEvent import com.muwire.core.search.UIResultBatchEvent import com.muwire.core.trust.TrustEvent import com.muwire.core.trust.TrustService @@ -255,7 +257,7 @@ public class Core { I2PConnector i2pConnector = new I2PConnector(socketManager) log.info "initializing results sender" - ResultsSender resultsSender = new ResultsSender(eventBus, i2pConnector, me) + ResultsSender resultsSender = new ResultsSender(eventBus, i2pConnector, me, props) log.info "initializing search manager" SearchManager searchManager = new SearchManager(eventBus, me, resultsSender) @@ -281,7 +283,7 @@ public class Core { log.info("initializing acceptor") I2PAcceptor i2pAcceptor = new I2PAcceptor(socketManager) connectionAcceptor = new ConnectionAcceptor(eventBus, connectionManager, props, - i2pAcceptor, hostCache, trustService, searchManager, uploadManager, connectionEstablisher) + i2pAcceptor, hostCache, trustService, searchManager, uploadManager, fileManager, connectionEstablisher) log.info("initializing directory watcher") directoryWatcher = new DirectoryWatcher(eventBus, fileManager, home, props) @@ -304,6 +306,11 @@ public class Core { contentManager = new ContentManager() eventBus.register(ContentControlEvent.class, contentManager) eventBus.register(QueryEvent.class, contentManager) + + log.info("initializing browse manager") + BrowseManager browseManager = new BrowseManager(i2pConnector, eventBus) + eventBus.register(UIBrowseEvent.class, browseManager) + } public void startServices() { diff --git a/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy b/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy index 013aecea..d2a40486 100644 --- a/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy +++ b/core/src/main/groovy/com/muwire/core/connection/ConnectionAcceptor.groovy @@ -264,7 +264,7 @@ class ConnectionAcceptor { String header while ((header = DataUtil.readTillRN(dis)) != ""); // ignore headers for now - OutputStream os = e.getOutputStream() + OutputStream os = e.getOutputStream() if (!settings.browseFiles) { os.write("403 Not Allowed\r\n\r\n".getBytes(StandardCharsets.US_ASCII)) os.flush() diff --git a/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy b/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy new file mode 100644 index 00000000..a5fccf7f --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/search/BrowseManager.groovy @@ -0,0 +1,82 @@ +package com.muwire.core.search + +import com.muwire.core.Constants +import com.muwire.core.EventBus +import com.muwire.core.connection.Endpoint +import com.muwire.core.connection.I2PConnector +import com.muwire.core.util.DataUtil + +import groovy.json.JsonSlurper + +import java.nio.charset.StandardCharsets +import java.util.concurrent.Executor +import java.util.concurrent.Executors + +class BrowseManager { + + private final I2PConnector connector + private final EventBus eventBus + + private final Executor browserThread = Executors.newSingleThreadExecutor() + + BrowseManager(I2PConnector connector, EventBus eventBus) { + this.connector = connector + this.eventBus = eventBus + } + + void onUIBrowseEvent(UIBrowseEvent e) { + browserThread.execute({ + Endpoint endpoint = null + try { + eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.CONNECTING)) + endpoint = connector.connect(e.host.destination) + OutputStream os = endpoint.getOutputStream() + os.write("BROWSE\r\n\r\n".getBytes(StandardCharsets.US_ASCII)) + + InputStream is = endpoint.getInputStream() + String code = DataUtil.readTillRN(is) + if (!code.startsWith("200")) + throw new IOException("Invalid code") + + // parse all headers + Map headers = new HashMap<>() + String header + while((header = DataUtil.readTillRN(is)) != "" && headers.size() < Constants.MAX_HEADERS) { + int colon = header.indexOf(':') + if (colon == -1 || colon == header.length() - 1) + throw new IOException("invalid header $header") + String key = header.substring(0, colon) + String value = header.substring(colon + 1) + headers[key] = value.trim() + } + + if (!headers.containsKey("Count")) + throw new IOException("No count header") + + int results = Integer.parseInt(headers['Count']) + + // at this stage, start pulling the results + eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FETCHING)) + + JsonSlurper slurper = new JsonSlurper() + DataInputStream dis = new DataInputStream(is) + UUID uuid = UUID.randomUUID() + for (int i = 0; i < results; i++) { + int size = dis.readUnsignedShort() + byte [] tmp = new byte[size] + dis.readFully(tmp) + def json = slurper.parse(tmp) + UIResultEvent result = ResultsParser.parse(e.host, uuid, json) + eventBus.publish(result) + } + + eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FINISHED)) + + } catch (Exception bad) { + eventBus.publish(new BrowseStatusEvent(status : BrowseStatus.FAILED)) + } finally { + endpoint?.close() + } + } as Runnable) + } +} diff --git a/core/src/main/groovy/com/muwire/core/search/BrowseStatus.java b/core/src/main/groovy/com/muwire/core/search/BrowseStatus.java new file mode 100644 index 00000000..fc91e960 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/search/BrowseStatus.java @@ -0,0 +1,5 @@ +package com.muwire.core.search; + +public enum BrowseStatus { + CONNECTING, FETCHING, FINISHED, FAILED +} diff --git a/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy b/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy new file mode 100644 index 00000000..e03aef5b --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/search/BrowseStatusEvent.groovy @@ -0,0 +1,7 @@ +package com.muwire.core.search + +import com.muwire.core.Event + +class BrowseStatusEvent extends Event { + BrowseStatus status +} diff --git a/core/src/main/groovy/com/muwire/core/search/UIBrowseEvent.groovy b/core/src/main/groovy/com/muwire/core/search/UIBrowseEvent.groovy new file mode 100644 index 00000000..1c11df05 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/search/UIBrowseEvent.groovy @@ -0,0 +1,7 @@ +package com.muwire.core.search + +import com.muwire.core.Persona + +class UIBrowseEvent { + Persona host +}