diff --git a/core/src/main/groovy/com/muwire/core/Constants.groovy b/core/src/main/groovy/com/muwire/core/Constants.groovy index 0c9b3c54..25553df9 100644 --- a/core/src/main/groovy/com/muwire/core/Constants.groovy +++ b/core/src/main/groovy/com/muwire/core/Constants.groovy @@ -8,4 +8,6 @@ class Constants { public static final int MAX_HEADER_SIZE = 0x1 << 14 public static final int MAX_HEADERS = 16 + + public static final float DOWNLOAD_SEQUENTIAL_RATIO = 0.8f } diff --git a/core/src/main/groovy/com/muwire/core/Core.groovy b/core/src/main/groovy/com/muwire/core/Core.groovy index 996c1b62..430a28e0 100644 --- a/core/src/main/groovy/com/muwire/core/Core.groovy +++ b/core/src/main/groovy/com/muwire/core/Core.groovy @@ -11,6 +11,8 @@ import com.muwire.core.connection.I2PAcceptor import com.muwire.core.connection.I2PConnector import com.muwire.core.connection.LeafConnectionManager import com.muwire.core.connection.UltrapeerConnectionManager +import com.muwire.core.download.DownloadManager +import com.muwire.core.download.UIDownloadEvent import com.muwire.core.files.FileDownloadedEvent import com.muwire.core.files.FileHashedEvent import com.muwire.core.files.FileHasher @@ -179,6 +181,10 @@ class Core { eventBus.register(QueryEvent.class, searchManager) eventBus.register(ResultsEvent.class, searchManager) + log.info("initializing download manager") + DownloadManager downloadManager = new DownloadManager(eventBus, i2pConnector) + eventBus.register(UIDownloadEvent.class, downloadManager) + log.info("initializing upload manager") UploadManager uploadManager = new UploadManager(eventBus, fileManager) diff --git a/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy b/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy new file mode 100644 index 00000000..835bff44 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy @@ -0,0 +1,33 @@ +package com.muwire.core.download + +import com.muwire.core.connection.I2PConnector +import com.muwire.core.EventBus + +import java.util.concurrent.Executor +import java.util.concurrent.Executors + +public class DownloadManager { + + private final EventBus eventBus + private final I2PConnector connector + private final Executor executor + + public DownloadManager(EventBus eventBus, I2PConnector connector) { + this.eventBus = eventBus + this.connector = connector + this.executor = Executors.newCachedThreadPool({ r -> + Thread rv = new Thread(r) + rv.setName("download-worker") + rv.setDaemon(true) + rv + }) + } + + + public void onUIDownloadEvent(UIDownloadEvent e) { + def downloader = new Downloader(e.target, e.result.size, + e.result.infohash, e.result.pieceSize, connector, e.result.sender.destination) + executor.execute({downloader.download()} as Runnable) + eventBus.publish(new DownloadStartedEvent(downloader : downloader)) + } +} diff --git a/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy b/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy index 24a933f9..0153b73a 100644 --- a/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy +++ b/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy @@ -138,4 +138,8 @@ class DownloadSession { try { channel?.close() } catch (IOException ignore) {} } } + + synchronized int positionInPiece() { + mapped.position() + } } diff --git a/core/src/main/groovy/com/muwire/core/download/DownloadStartedEvent.groovy b/core/src/main/groovy/com/muwire/core/download/DownloadStartedEvent.groovy new file mode 100644 index 00000000..95424717 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/download/DownloadStartedEvent.groovy @@ -0,0 +1,7 @@ +package com.muwire.core.download + +import com.muwire.core.Event + +class DownloadStartedEvent extends Event { + Downloader downloader +} diff --git a/core/src/main/groovy/com/muwire/core/download/Downloader.groovy b/core/src/main/groovy/com/muwire/core/download/Downloader.groovy new file mode 100644 index 00000000..f25e0afb --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/download/Downloader.groovy @@ -0,0 +1,66 @@ +package com.muwire.core.download + +import com.muwire.core.InfoHash +import com.muwire.core.connection.Endpoint +import com.muwire.core.Constants +import com.muwire.core.connection.I2PConnector + +import net.i2p.data.Destination + +public class Downloader { + public enum DownloadState { CONNECTING, DOWNLOADING, FINISHED } + + private final File file + private final Pieces pieces + private final long length + private final InfoHash infoHash + private final int pieceSize + private final I2PConnector connector + private final Destination destination + + private Endpoint endpoint + private volatile DownloadSession currentSession + private volatile DownloadState currentState + + public Downloader(File file, long length, InfoHash infoHash, int pieceSizePow2, I2PConnector connector, Destination destination) { + this.file = file + this.infoHash = infoHash + this.length = length + this.connector = connector + this.destination = destination + this.pieceSize = 1 << pieceSizePow2 + + int nPieces + if (length % pieceSize == 0) + nPieces = length / pieceSize + else + nPieces = length / pieceSize + 1 + + pieces = new Pieces(nPieces, Constants.DOWNLOAD_SEQUENTIAL_RATIO) + currentState = DownloadState.CONNECTING + } + + void download() { + Endpoint endpoint = connector.connect(destination) + currentState = DownloadState.DOWNLOADING + while(!pieces.isComplete()) { + currentSession = new DownloadSession(pieces, infoHash, endpoint, file, pieceSize, length) + currentSession.request() + } + currentState = DownloadState.FINISHED + } + + public long donePieces() { + pieces.donePieces() + } + + public int positionInPiece() { + if (currentSession == null) + return 0 + currentSession.positionInPiece() + } + + public DownloadState getCurrentState() { + currentState + } +} diff --git a/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy b/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy new file mode 100644 index 00000000..86e8ff29 --- /dev/null +++ b/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy @@ -0,0 +1,10 @@ +package com.muwire.core.download + +import com.muwire.core.Event +import com.muwire.core.search.UIResultEvent + +class UIDownloadEvent extends Event { + + UIResultEvent result + File target +}