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;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
29 import net.pterodactylus.irc.event.DccDownloadFailed;
30 import net.pterodactylus.irc.event.DccDownloadFinished;
31 import net.pterodactylus.irc.event.DccSendReceived;
32 import net.pterodactylus.xdcc.util.io.BandwidthCountingInputStream;
34 import com.google.common.eventbus.EventBus;
35 import com.google.common.io.Closeables;
36 import com.google.common.util.concurrent.AbstractExecutionThreadService;
39 * Service that receives a file offered by a {@link DccSendReceived}.
41 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
43 public class DccReceiver extends AbstractExecutionThreadService {
46 private static final Logger logger = Logger.getLogger(DccReceiver.class.getName());
49 private final EventBus eventBus;
51 /** The address to connect to. */
52 private final InetAddress inetAddress;
54 /** The port number to connect to. */
55 private final int port;
57 /** The name of the file being offered. */
58 private final String filename;
60 /** The size of the file being offered. */
61 private final long size;
63 /** The output stream to write the file to. */
64 private final OutputStream outputStream;
66 /** The number of bytes already written. */
67 private long progress;
69 /** The bandwidth-measuring input stream. */
70 private BandwidthCountingInputStream inputStream;
73 * Creates a new DCC receiver.
76 * The address to connect to
78 * The port number to connect to
80 * The name of the file being downloaded
82 * The size of the file being downloaded, or {@code -1} if the size is not
85 * The output stream to write the file to
87 public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long size, OutputStream outputStream) {
88 this(eventBus, inetAddress, port, filename, 0, size, outputStream);
92 * Creates a new DCC receiver.
95 * The address to connect to
97 * The port number to connect to
99 * The name of the file being downloaded
101 * The offset at which the download starts in case of a resume
103 * The size of the file being downloaded, or {@code -1} if the size is not
105 * @param outputStream
106 * The output stream to write the file to
108 public DccReceiver(EventBus eventBus, InetAddress inetAddress, int port, String filename, long startOffset, long size, OutputStream outputStream) {
109 this.eventBus = eventBus;
110 this.inetAddress = inetAddress;
112 this.filename = filename;
113 this.progress = startOffset;
115 this.outputStream = outputStream;
123 * Returns the name of the file being downloaded. The name is not used by the
124 * DCC receiver, it only serves as a kind of identifier.
126 * @return The name of the file being downloaded
128 public String filename() {
133 * Returns the size of the file being downloaded. If the size of the file is
134 * not known, {@code -1} is returned.
136 * @return The size of the file being downloaded, or {@code -1} if the size is
144 * Returns the number of bytes that have already been downloaded.
146 * @return The number of bytes that have already been downloaded
148 public long progress() {
153 * Returns the current rate of the download.
155 * @return The current rate of the download, in bytes/second
157 public long currentRate() {
158 return (inputStream != null) ? inputStream.getCurrentRate() : 0;
162 * Returns the overall rate of the download.
164 * @return The overall rate of the download, in bytes/second
166 public long overallRate() {
167 return (inputStream != null) ? inputStream.getOverallRate() : 0;
171 // ABSTRACTEXECUTIONTHREADSERVICE METHODS
175 protected void run() throws IOException {
176 Socket socket = null;
178 socket = new Socket(inetAddress, port);
179 socket.setSoTimeout((int) TimeUnit.MINUTES.toMillis(3));
180 InputStream socketInputStream = socket.getInputStream();
181 inputStream = new BandwidthCountingInputStream(socketInputStream, 5, TimeUnit.SECONDS);
182 byte[] buffer = new byte[65536];
183 while (isRunning() && ((size == -1) || (progress < size))) {
184 int r = inputStream.read(buffer);
189 outputStream.write(buffer, 0, r);
192 outputStream.flush();
193 if ((size == -1) || (progress == size)) {
194 eventBus.post(new DccDownloadFinished(this));
196 eventBus.post(new DccDownloadFailed(this, new IOException("Download aborted.")));
198 } catch (IOException ioe1) {
199 logger.log(Level.WARNING, "I/O error while receiving DCC!", ioe1);
200 eventBus.post(new DccDownloadFailed(this, ioe1));
202 Closeables.close(inputStream, true);
203 if (socket != null) {