2 * XdccDownloader - DccReceiver.java - Copyright © 2013 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.irc;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.net.InetAddress;
24 import java.net.Socket;
25 import java.util.concurrent.TimeUnit;
27 import net.pterodactylus.irc.event.DccDownloadFailed;
28 import net.pterodactylus.irc.event.DccDownloadFinished;
29 import net.pterodactylus.irc.event.DccSendReceived;
30 import net.pterodactylus.xdcc.util.io.BandwidthCountingInputStream;
32 import com.google.common.eventbus.EventBus;
33 import com.google.common.io.Closeables;
34 import com.google.common.util.concurrent.AbstractExecutionThreadService;
35 import org.apache.log4j.Logger;
38 * Service that receives a file offered by a {@link DccSendReceived}.
40 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
42 public class DccReceiver extends AbstractExecutionThreadService {
45 private static final Logger logger = Logger.getLogger(DccReceiver.class.getName());
48 private final EventBus eventBus;
50 /** The address to connect to. */
51 private final InetAddress inetAddress;
53 /** The port number to connect to. */
54 private final int port;
56 /** The name of the file being offered. */
57 private final String filename;
59 /** The size of the file being offered. */
60 private final long size;
62 /** The output stream to write the file to. */
63 private final OutputStream outputStream;
65 /** The number of bytes already written. */
66 private long progress;
68 /** The bandwidth-measuring input stream. */
69 private BandwidthCountingInputStream inputStream;
72 * Creates a new DCC receiver.
75 * The address to connect to
77 * The port number to connect to
79 * The name of the file being downloaded
81 * The size of the file being downloaded, or {@code -1} if the size is not
84 * The output stream to write the file to
86 public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long size, OutputStream outputStream) {
87 this(eventBus, inetAddress, port, filename, 0, size, outputStream);
91 * Creates a new DCC receiver.
94 * The address to connect to
96 * The port number to connect to
98 * The name of the file being downloaded
100 * The offset at which the download starts in case of a resume
102 * The size of the file being downloaded, or {@code -1} if the size is not
104 * @param outputStream
105 * The output stream to write the file to
107 public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long startOffset, long size, OutputStream outputStream) {
108 this.eventBus = eventBus;
109 this.inetAddress = inetAddress;
111 this.filename = filename;
112 this.progress = startOffset;
114 this.outputStream = outputStream;
122 * Returns the name of the file being downloaded. The name is not used by the
123 * DCC receiver, it only serves as a kind of identifier.
125 * @return The name of the file being downloaded
127 public String filename() {
132 * Returns the size of the file being downloaded. If the size of the file is
133 * not known, {@code -1} is returned.
135 * @return The size of the file being downloaded, or {@code -1} if the size is
143 * Returns the number of bytes that have already been downloaded.
145 * @return The number of bytes that have already been downloaded
147 public long progress() {
152 * Returns the current rate of the download.
154 * @return The current rate of the download, in bytes/second
156 public long currentRate() {
157 return (inputStream != null) ? inputStream.getCurrentRate() : 0;
161 * Returns the overall rate of the download.
163 * @return The overall rate of the download, in bytes/second
165 public long overallRate() {
166 return (inputStream != null) ? inputStream.getOverallRate() : 0;
170 // ABSTRACTEXECUTIONTHREADSERVICE METHODS
174 protected void run() throws IOException {
175 Socket socket = null;
177 socket = new Socket(inetAddress, port);
178 socket.setSoTimeout((int) TimeUnit.MINUTES.toMillis(3));
179 InputStream socketInputStream = socket.getInputStream();
180 inputStream = new BandwidthCountingInputStream(socketInputStream, 5, TimeUnit.SECONDS);
181 byte[] buffer = new byte[65536];
182 while (isRunning() && ((size == -1) || (progress < size))) {
183 int r = inputStream.read(buffer);
188 outputStream.write(buffer, 0, r);
191 outputStream.flush();
192 if ((size == -1) || (progress == size)) {
193 eventBus.post(new DccDownloadFinished(this));
195 eventBus.post(new DccDownloadFailed(this, new IOException("Download aborted.")));
197 } catch (IOException ioe1) {
198 logger.warn("I/O error while receiving DCC!", ioe1);
199 eventBus.post(new DccDownloadFailed(this, ioe1));
201 Closeables.close(inputStream, true);
202 if (socket != null) {