Use log4j for logging.
[xudocci.git] / src / main / java / net / pterodactylus / irc / DccReceiver.java
index 39f236c..e024d4e 100644 (file)
@@ -22,12 +22,17 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.concurrent.TimeUnit;
 
+import net.pterodactylus.irc.event.DccDownloadFailed;
+import net.pterodactylus.irc.event.DccDownloadFinished;
 import net.pterodactylus.irc.event.DccSendReceived;
+import net.pterodactylus.xdcc.util.io.BandwidthCountingInputStream;
 
+import com.google.common.eventbus.EventBus;
+import com.google.common.io.Closeables;
 import com.google.common.util.concurrent.AbstractExecutionThreadService;
+import org.apache.log4j.Logger;
 
 /**
  * Service that receives a file offered by a {@link DccSendReceived}.
@@ -39,6 +44,9 @@ public class DccReceiver extends AbstractExecutionThreadService {
        /** The logger. */
        private static final Logger logger = Logger.getLogger(DccReceiver.class.getName());
 
+       /** The event bus. */
+       private final EventBus eventBus;
+
        /** The address to connect to. */
        private final InetAddress inetAddress;
 
@@ -57,6 +65,9 @@ public class DccReceiver extends AbstractExecutionThreadService {
        /** The number of bytes already written. */
        private long progress;
 
+       /** The bandwidth-measuring input stream. */
+       private BandwidthCountingInputStream inputStream;
+
        /**
         * Creates a new DCC receiver.
         *
@@ -72,10 +83,33 @@ public class DccReceiver extends AbstractExecutionThreadService {
         * @param outputStream
         *              The output stream to write the file to
         */
-       public DccReceiver(InetAddress inetAddress, int port, String filename, long size, OutputStream outputStream) {
+       public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long size, OutputStream outputStream) {
+               this(eventBus, inetAddress, port, filename, 0, size, outputStream);
+       }
+
+       /**
+        * Creates a new DCC receiver.
+        *
+        * @param inetAddress
+        *              The address to connect to
+        * @param port
+        *              The port number to connect to
+        * @param filename
+        *              The name of the file being downloaded
+        * @param startOffset
+        *              The offset at which the download starts in case of a resume
+        * @param size
+        *              The size of the file being downloaded, or {@code -1} if the size is not
+        *              known
+        * @param outputStream
+        *              The output stream to write the file to
+        */
+       public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long startOffset, long size, OutputStream outputStream) {
+               this.eventBus = eventBus;
                this.inetAddress = inetAddress;
                this.port = port;
                this.filename = filename;
+               this.progress = startOffset;
                this.size = size;
                this.outputStream = outputStream;
        }
@@ -114,19 +148,39 @@ public class DccReceiver extends AbstractExecutionThreadService {
                return progress;
        }
 
+       /**
+        * Returns the current rate of the download.
+        *
+        * @return The current rate of the download, in bytes/second
+        */
+       public long currentRate() {
+               return (inputStream != null) ? inputStream.getCurrentRate() : 0;
+       }
+
+       /**
+        * Returns the overall rate of the download.
+        *
+        * @return The overall rate of the download, in bytes/second
+        */
+       public long overallRate() {
+               return (inputStream != null) ? inputStream.getOverallRate() : 0;
+       }
+
        //
        // ABSTRACTEXECUTIONTHREADSERVICE METHODS
        //
 
        @Override
-       protected void run() throws Exception {
+       protected void run() throws IOException {
                Socket socket = null;
                try {
                        socket = new Socket(inetAddress, port);
+                       socket.setSoTimeout((int) TimeUnit.MINUTES.toMillis(3));
                        InputStream socketInputStream = socket.getInputStream();
+                       inputStream = new BandwidthCountingInputStream(socketInputStream, 5, TimeUnit.SECONDS);
                        byte[] buffer = new byte[65536];
-                       while (true) {
-                               int r = socketInputStream.read(buffer);
+                       while (isRunning() && ((size == -1) || (progress < size))) {
+                               int r = inputStream.read(buffer);
                                if (r == -1) {
                                        /* yay, eof! */
                                        break;
@@ -134,10 +188,20 @@ public class DccReceiver extends AbstractExecutionThreadService {
                                outputStream.write(buffer, 0, r);
                                progress += r;
                        }
+                       outputStream.flush();
+                       if ((size == -1) || (progress == size)) {
+                               eventBus.post(new DccDownloadFinished(this));
+                       } else {
+                               eventBus.post(new DccDownloadFailed(this, new IOException("Download aborted.")));
+                       }
                } catch (IOException ioe1) {
-                       logger.log(Level.WARNING, "I/O error while receiving DCC!", ioe1);
+                       logger.warn("I/O error while receiving DCC!", ioe1);
+                       eventBus.post(new DccDownloadFailed(this, ioe1));
                } finally {
-                       socket.close();
+                       Closeables.close(inputStream, true);
+                       if (socket != null) {
+                               socket.close();
+                       }
                }
        }