From 6b97ecef1be59f3746e859dfb4a65f2195a6ee90 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sat, 13 Apr 2013 12:33:43 +0200 Subject: [PATCH] Resume a download if a partial file already exists in the temp directory. --- .../java/net/pterodactylus/xdcc/core/Core.java | 69 +++++++++++++++++++++- .../java/net/pterodactylus/xdcc/data/Download.java | 49 +++++++++++++++ 2 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/pterodactylus/xdcc/core/Core.java b/src/main/java/net/pterodactylus/xdcc/core/Core.java index 64fdbec..251310e 100644 --- a/src/main/java/net/pterodactylus/xdcc/core/Core.java +++ b/src/main/java/net/pterodactylus/xdcc/core/Core.java @@ -38,6 +38,7 @@ import net.pterodactylus.irc.event.ChannelLeft; import net.pterodactylus.irc.event.ChannelMessageReceived; import net.pterodactylus.irc.event.ClientQuit; import net.pterodactylus.irc.event.ConnectionEstablished; +import net.pterodactylus.irc.event.DccAcceptReceived; import net.pterodactylus.irc.event.DccDownloadFailed; import net.pterodactylus.irc.event.DccDownloadFinished; import net.pterodactylus.irc.event.DccSendReceived; @@ -49,6 +50,7 @@ import net.pterodactylus.xdcc.core.event.CoreStarted; import net.pterodactylus.xdcc.core.event.DownloadFailed; import net.pterodactylus.xdcc.core.event.DownloadFinished; import net.pterodactylus.xdcc.core.event.DownloadStarted; +import net.pterodactylus.xdcc.core.event.GenericError; import net.pterodactylus.xdcc.core.event.GenericMessage; import net.pterodactylus.xdcc.core.event.MessageReceived; import net.pterodactylus.xdcc.data.Bot; @@ -433,9 +435,38 @@ public class Core extends AbstractIdleService { return; } - logger.info(String.format("Starting download of %s.", dccSendReceived.filename())); + /* check if the file already exists. */ + File outputFile = new File(temporaryDirectory, dccSendReceived.filename()); + if (outputFile.exists()) { + long existingFileSize = outputFile.length(); + + /* file already complete? */ + if ((dccSendReceived.filesize() > -1) && (existingFileSize >= dccSendReceived.filesize())) { + /* file is apparently already complete. just move it. */ + if (outputFile.renameTo(new File(finalDirectory, download.pack().name()))) { + eventBus.post(new GenericMessage(String.format("File %s already downloaded.", download.pack().name()))); + } else { + eventBus.post(new GenericMessage(String.format("File %s already downloaded but not moved to %s.", download.pack().name(), finalDirectory))); + } + + /* remove download. */ + downloads.remove(download); + return; + } + + /* file not complete yet, DCC resume it. */ + try { + download.remoteAddress(dccSendReceived.inetAddress()).filesize(dccSendReceived.filesize()); + dccSendReceived.connection().sendDccResume(dccSendReceived.source().nick().get(), dccSendReceived.filename(), dccSendReceived.port(), existingFileSize); + } catch (IOException ioe1) { + eventBus.post(new GenericError(String.format("Could not send DCC RESUME %s to %s (%s).", dccSendReceived.filename(), dccSendReceived.source().nick().get(), ioe1.getMessage()))); + } + + return; + } + + /* file does not exist, start the download. */ try { - File outputFile = new File(temporaryDirectory, dccSendReceived.filename()); OutputStream fileOutputStream = new FileOutputStream(outputFile); DccReceiver dccReceiver = new DccReceiver(eventBus, dccSendReceived.inetAddress(), dccSendReceived.port(), dccSendReceived.filename(), dccSendReceived.filesize(), fileOutputStream); download.filename(outputFile.getPath()).outputStream(fileOutputStream).dccReceiver(dccReceiver); @@ -443,7 +474,39 @@ public class Core extends AbstractIdleService { dccReceiver.start(); eventBus.post(new DownloadStarted(download)); } catch (FileNotFoundException fnfe1) { - logger.log(Level.WARNING, "Could not open file for download!", fnfe1); + eventBus.post(new GenericError(String.format("Could not start download of %s from %s (%s).", dccSendReceived.filename(), dccSendReceived.source().nick().get(), fnfe1.getMessage()))); + } + } + + @Subscribe + public void dccAcceptReceived(DccAcceptReceived dccAcceptReceived) { + Optional network = getNetwork(dccAcceptReceived.connection()); + if (!network.isPresent()) { + return; + } + + Download download = downloads.get(dccAcceptReceived.filename()); + if (download == null) { + /* unknown download, ignore. */ + return; + } + + try { + File outputFile = new File(temporaryDirectory, dccAcceptReceived.filename()); + if (outputFile.length() != dccAcceptReceived.position()) { + eventBus.post(new GenericError(String.format("Download %s from %s does not start at the right position!"))); + logger.log(Level.WARNING, String.format("Download %s from %s: have %d bytes but wants to resume from %d!", dccAcceptReceived.filename(), dccAcceptReceived.source(), outputFile.length(), dccAcceptReceived.position())); + + downloads.remove(download); + return; + } + OutputStream outputStream = new FileOutputStream(outputFile, true); + DccReceiver dccReceiver = new DccReceiver(eventBus, download.remoteAddress(), dccAcceptReceived.port(), dccAcceptReceived.filename(), dccAcceptReceived.position(), download.filesize(), outputStream); + download.filename(outputFile.getPath()).outputStream(outputStream).dccReceiver(dccReceiver); + dccReceivers.add(dccReceiver); + dccReceiver.start(); + eventBus.post(new DownloadStarted(download)); + } catch (FileNotFoundException fnfe1) { } } diff --git a/src/main/java/net/pterodactylus/xdcc/data/Download.java b/src/main/java/net/pterodactylus/xdcc/data/Download.java index 2d95537..5190ed0 100644 --- a/src/main/java/net/pterodactylus/xdcc/data/Download.java +++ b/src/main/java/net/pterodactylus/xdcc/data/Download.java @@ -18,6 +18,7 @@ package net.pterodactylus.xdcc.data; import java.io.OutputStream; +import java.net.InetAddress; import net.pterodactylus.irc.DccReceiver; @@ -37,6 +38,12 @@ public class Download { /** The name of the file being downloaded. */ private String filename; + /** The size of the file being downloaded. */ + private long filesize; + + /** The remote address. */ + private InetAddress remoteAddress; + /** The output stream. */ private OutputStream outputStream; @@ -88,6 +95,24 @@ public class Download { } /** + * Returns the size of the file. + * + * @return The size of the file + */ + public long filesize() { + return filesize; + } + + /** + * Returns the remote address to download from. + * + * @return The remote address to download from + */ + public InetAddress remoteAddress() { + return remoteAddress; + } + + /** * The output stream that writes to the file. * * @return The output stream @@ -122,6 +147,30 @@ public class Download { } /** + * Sets the size of the download. + * + * @param filesize + * The size of the download + * @return This download + */ + public Download filesize(long filesize) { + this.filesize = filesize; + return this; + } + + /** + * Sets the remote address of the download. + * + * @param remoteAddress + * The remote address of the download + * @return This download + */ + public Download remoteAddress(InetAddress remoteAddress) { + this.remoteAddress = remoteAddress; + return this; + } + + /** * Sets the output stream the download is being written to * * @param outputStream -- 2.7.4