Expose input and output rate of connection.
[xudocci.git] / src / main / java / net / pterodactylus / irc / Connection.java
index 58e5365..2feaec4 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.irc;
 
 import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import java.io.BufferedReader;
 import java.io.Closeable;
@@ -44,6 +45,7 @@ import net.pterodactylus.irc.event.ChannelMessageReceived;
 import net.pterodactylus.irc.event.ChannelNicknames;
 import net.pterodactylus.irc.event.ChannelNotJoined;
 import net.pterodactylus.irc.event.ChannelNotJoined.Reason;
+import net.pterodactylus.irc.event.ChannelNoticeReceived;
 import net.pterodactylus.irc.event.ChannelTopic;
 import net.pterodactylus.irc.event.ClientQuit;
 import net.pterodactylus.irc.event.ConnectionClosed;
@@ -56,8 +58,11 @@ import net.pterodactylus.irc.event.NicknameChanged;
 import net.pterodactylus.irc.event.NicknameInUseReceived;
 import net.pterodactylus.irc.event.NoNicknameGivenReceived;
 import net.pterodactylus.irc.event.PrivateMessageReceived;
+import net.pterodactylus.irc.event.PrivateNoticeReceived;
 import net.pterodactylus.irc.event.UnknownReplyReceived;
 import net.pterodactylus.irc.util.RandomNickname;
+import net.pterodactylus.xdcc.util.io.BandwidthCountingInputStream;
+import net.pterodactylus.xdcc.util.io.BandwidthCountingOutputStream;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Maps;
@@ -142,6 +147,22 @@ public class Connection extends AbstractExecutionThreadService implements Servic
        //
 
        /**
+        * Returns the hostname of the remote end of the connection.
+        * @return The remote’s hostname
+        */
+       public String hostname() {
+               return hostname;
+       }
+
+       /**
+        * Returns the port number of the remote end of the connection.
+        * @return The remote’s port number
+        */
+       public int port() {
+               return port;
+       }
+
+       /**
         * Returns whether this connection has already been established.
         *
         * @return {@code true} as long as this connection is established, {@code
@@ -219,6 +240,24 @@ public class Connection extends AbstractExecutionThreadService implements Servic
        //
 
        /**
+        * Returns the current rate of the connection’s incoming side.
+        *
+        * @return The current input rate (in bytes per second)
+        */
+       public long getInputRate() {
+               return (connectionHandler != null) ? connectionHandler.getInputRate() : 0;
+       }
+
+       /**
+        * Returns the current rate of the connection’s outgoing side.
+        *
+        * @return The current output rate (in bytes per second)
+        */
+       public long getOutputRate() {
+               return (connectionHandler != null) ? connectionHandler.getOutputRate() : 0;
+       }
+
+       /**
         * Checks whether the given source is the client represented by this
         * connection.
         *
@@ -276,6 +315,16 @@ public class Connection extends AbstractExecutionThreadService implements Servic
                connectionHandler.sendCommand("PRIVMSG", recipient, String.format("\u0001DCC RESUME %s %d %d\u0001", filename, port, position));
        }
 
+       /**
+        * Closes this connection.
+        *
+        * @throws IOException
+        *              if an I/O error occurs
+        */
+       public void close() throws IOException {
+               connectionHandler.close();
+       }
+
        //
        // ABSTRACTEXECUTIONTHREADSERVICE METHODS
        //
@@ -332,34 +381,23 @@ public class Connection extends AbstractExecutionThreadService implements Servic
                                        String message = parameters.get(1);
                                        if (message.startsWith("\u0001") && message.endsWith("\u0001")) {
                                                /* CTCP! */
-                                               String[] messageWords = message.substring(1, message.length() - 1).split(" +");
-                                               String ctcpCommand = messageWords[0];
-                                               if (ctcpCommand.equalsIgnoreCase("DCC")) {
-                                                       if (messageWords[1].equalsIgnoreCase("SEND")) {
-                                                               Optional<InetAddress> inetAddress = parseInetAddress(messageWords[3]);
-                                                               Optional<Integer> port = Optional.fromNullable(Ints.tryParse(messageWords[4]));
-                                                               long fileSize = Optional.fromNullable(Longs.tryParse(messageWords[5])).or(-1L);
-                                                               if (inetAddress.isPresent() && port.isPresent()) {
-                                                                       eventBus.post(new DccSendReceived(this, reply.source().get(), messageWords[2], inetAddress.get(), port.get(), fileSize));
-                                                               } else {
-                                                                       logger.warning(String.format("Received malformed DCC SEND: “%s”", message));
-                                                               }
-                                                       } else if (messageWords[1].equalsIgnoreCase("ACCEPT")) {
-                                                               Optional<Integer> port = Optional.fromNullable(Ints.tryParse(messageWords[3]));
-                                                               long position = Optional.fromNullable(Longs.tryParse(messageWords[4])).or(-1L);
-                                                               if (port.isPresent()) {
-                                                                       eventBus.post(new DccAcceptReceived(this, reply.source().get(), messageWords[2], port.get(), position));
-                                                               } else {
-                                                                       logger.warning(String.format("Received malformed DCC ACCEPT: “%s”", message));
-                                                               }
-                                                       }
-                                               }
+                                               handleCtcp(reply.source().get(), message);
                                        } else if (!channelTypes.contains(recipient.charAt(0))) {
                                                eventBus.post(new PrivateMessageReceived(this, reply.source().get(), message));
                                        } else {
                                                eventBus.post(new ChannelMessageReceived(this, recipient, reply.source().get(), message));
                                        }
 
+                               } else if (command.equalsIgnoreCase("NOTICE")) {
+                                       String recipient = parameters.get(0);
+                                       String message = parameters.get(1);
+                                       if (message.startsWith("\u0001") && message.endsWith("\u0001")) {
+                                               /* CTCP! */
+                                               handleCtcp(reply.source().get(), message);
+                                       } else if (!channelTypes.contains(recipient.charAt(0))) {
+                                               eventBus.post(new PrivateNoticeReceived(this, reply));
+                                       } else {
+                                               eventBus.post(new ChannelNoticeReceived(this, reply.source().get(), recipient, message));
                                        }
 
                                /* 43x replies are for nick change errors. */
@@ -488,6 +526,39 @@ public class Connection extends AbstractExecutionThreadService implements Servic
        //
 
        /**
+        * Handles a CTCP message.
+        *
+        * @param client
+        *              The client sending the message
+        * @param message
+        *              The message
+        */
+       private void handleCtcp(Source client, String message) {
+               String[] messageWords = message.substring(1, message.length() - 1).split(" +");
+               String ctcpCommand = messageWords[0];
+               if (ctcpCommand.equalsIgnoreCase("DCC")) {
+                       if (messageWords[1].equalsIgnoreCase("SEND")) {
+                               Optional<InetAddress> inetAddress = parseInetAddress(messageWords[3]);
+                               Optional<Integer> port = Optional.fromNullable(Ints.tryParse(messageWords[4]));
+                               long fileSize = Optional.fromNullable(Longs.tryParse(messageWords[5])).or(-1L);
+                               if (inetAddress.isPresent() && port.isPresent()) {
+                                       eventBus.post(new DccSendReceived(this, client, messageWords[2], inetAddress.get(), port.get(), fileSize));
+                               } else {
+                                       logger.warning(String.format("Received malformed DCC SEND: “%s”", message));
+                               }
+                       } else if (messageWords[1].equalsIgnoreCase("ACCEPT")) {
+                               Optional<Integer> port = Optional.fromNullable(Ints.tryParse(messageWords[3]));
+                               long position = Optional.fromNullable(Longs.tryParse(messageWords[4])).or(-1L);
+                               if (port.isPresent()) {
+                                       eventBus.post(new DccAcceptReceived(this, client, messageWords[2], port.get(), position));
+                               } else {
+                                       logger.warning(String.format("Received malformed DCC ACCEPT: “%s”", message));
+                               }
+                       }
+               }
+       }
+
+       /**
         * Returns an item from the list, or {@link Optional#absent()} if the list is
         * shorter than required for the given index.
         *
@@ -537,7 +608,10 @@ public class Connection extends AbstractExecutionThreadService implements Servic
        private class ConnectionHandler implements Closeable {
 
                /** The output stream of the connection. */
-               private final OutputStream outputStream;
+               private final BandwidthCountingOutputStream outputStream;
+
+               /** The input stream. */
+               private final BandwidthCountingInputStream inputStream;
 
                /** The input stream of the connection. */
                private final BufferedReader inputStreamReader;
@@ -554,8 +628,9 @@ public class Connection extends AbstractExecutionThreadService implements Servic
                 *              if the encoding (currently “UTF-8”) is not valid
                 */
                private ConnectionHandler(InputStream inputStream, OutputStream outputStream) throws UnsupportedEncodingException {
-                       this.outputStream = outputStream;
-                       inputStreamReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+                       this.outputStream = new BandwidthCountingOutputStream(outputStream, 5, SECONDS);
+                       this.inputStream = new BandwidthCountingInputStream(inputStream, 5, SECONDS);
+                       inputStreamReader = new BufferedReader(new InputStreamReader(this.inputStream, "UTF-8"));
                }
 
                //
@@ -563,6 +638,24 @@ public class Connection extends AbstractExecutionThreadService implements Servic
                //
 
                /**
+                * Returns the current rate of the connection’s incoming side.
+                *
+                * @return The current input rate (in bytes per second)
+                */
+               public long getInputRate() {
+                       return inputStream.getCurrentRate();
+               }
+
+               /**
+                * Returns the current rate of the connection’s outgoing side.
+                *
+                * @return The current output rate (in bytes per second)
+                */
+               public long getOutputRate() {
+                       return outputStream.getCurrentRate();
+               }
+
+               /**
                 * Sends a command with the given parameters, skipping all {@link
                 * Optional#absent()} optionals.
                 *