Declare I/O exceptions to be thrown.
[xudocci.git] / src / main / java / net / pterodactylus / irc / DccReceiver.java
1 /*
2  * XdccDownloader - DccReceiver.java - Copyright © 2013 David Roden
3  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.pterodactylus.irc;
19
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;
28
29 import net.pterodactylus.irc.event.DccSendReceived;
30 import net.pterodactylus.xdcc.util.io.BandwidthCountingInputStream;
31
32 import com.google.common.io.Closeables;
33 import com.google.common.util.concurrent.AbstractExecutionThreadService;
34
35 /**
36  * Service that receives a file offered by a {@link DccSendReceived}.
37  *
38  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
39  */
40 public class DccReceiver extends AbstractExecutionThreadService {
41
42         /** The logger. */
43         private static final Logger logger = Logger.getLogger(DccReceiver.class.getName());
44
45         /** The address to connect to. */
46         private final InetAddress inetAddress;
47
48         /** The port number to connect to. */
49         private final int port;
50
51         /** The name of the file being offered. */
52         private final String filename;
53
54         /** The size of the file being offered. */
55         private final long size;
56
57         /** The output stream to write the file to. */
58         private final OutputStream outputStream;
59
60         /** The number of bytes already written. */
61         private long progress;
62
63         /** The bandwidth-measuring input stream. */
64         private BandwidthCountingInputStream inputStream;
65
66         /**
67          * Creates a new DCC receiver.
68          *
69          * @param inetAddress
70          *              The address to connect to
71          * @param port
72          *              The port number to connect to
73          * @param filename
74          *              The name of the file being downloaded
75          * @param size
76          *              The size of the file being downloaded, or {@code -1} if the size is not
77          *              known
78          * @param outputStream
79          *              The output stream to write the file to
80          */
81         public DccReceiver(InetAddress inetAddress, int port, String filename, long size, OutputStream outputStream) {
82                 this.inetAddress = inetAddress;
83                 this.port = port;
84                 this.filename = filename;
85                 this.size = size;
86                 this.outputStream = outputStream;
87         }
88
89         //
90         // ACCESSORS
91         //
92
93         /**
94          * Returns the name of the file being downloaded. The name is not used by the
95          * DCC receiver, it only serves as a kind of identifier.
96          *
97          * @return The name of the file being downloaded
98          */
99         public String filename() {
100                 return filename;
101         }
102
103         /**
104          * Returns the size of the file being downloaded. If the size of the file is
105          * not known, {@code -1} is returned.
106          *
107          * @return The size of the file being downloaded, or {@code -1} if the size is
108          *         not known
109          */
110         public long size() {
111                 return size;
112         }
113
114         /**
115          * Returns the number of bytes that have already been downloaded.
116          *
117          * @return The number of bytes that have already been downloaded
118          */
119         public long progress() {
120                 return progress;
121         }
122
123         /**
124          * Returns the current rate of the download.
125          *
126          * @return The current rate of the download, in bytes/second
127          */
128         public long getCurrentRate() {
129                 return inputStream.getCurrentRate();
130         }
131
132         /**
133          * Returns the overall rate of the download.
134          *
135          * @return The overall rate of the download, in bytes/second
136          */
137         public long getOverallRate() {
138                 return inputStream.getOverallRate();
139         }
140
141         //
142         // ABSTRACTEXECUTIONTHREADSERVICE METHODS
143         //
144
145         @Override
146         protected void run() throws IOException {
147                 Socket socket = null;
148                 try {
149                         socket = new Socket(inetAddress, port);
150                         InputStream socketInputStream = socket.getInputStream();
151                         inputStream = new BandwidthCountingInputStream(socketInputStream, 5, TimeUnit.SECONDS);
152                         byte[] buffer = new byte[65536];
153                         while (true) {
154                                 int r = inputStream.read(buffer);
155                                 if (r == -1) {
156                                         /* yay, eof! */
157                                         break;
158                                 }
159                                 outputStream.write(buffer, 0, r);
160                                 progress += r;
161                         }
162                 } catch (IOException ioe1) {
163                         logger.log(Level.WARNING, "I/O error while receiving DCC!", ioe1);
164                 } finally {
165                         Closeables.close(inputStream, true);
166                         socket.close();
167                 }
168         }
169
170 }