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}.
/** 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;
/** The number of bytes already written. */
private long progress;
+ /** The bandwidth-measuring input stream. */
+ private BandwidthCountingInputStream inputStream;
+
/**
* Creates a new DCC receiver.
*
* @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;
}
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;
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();
+ }
}
}