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;
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;
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.ReplyReceived;
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;
//
/**
+ * 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
//
/**
+ * 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.
*
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
//
while (connected) {
Reply reply = connectionHandler.readReply();
+ eventBus.post(new ReplyReceived(this, reply));
logger.finest(String.format("<< %s", reply));
String command = reply.command();
List<String> parameters = reply.parameters();
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. */
} catch (IOException ioe1) {
logger.log(Level.WARNING, "I/O error", ioe1);
eventBus.post(new ConnectionClosed(this, ioe1));
+ } catch (RuntimeException re1) {
+ logger.log(Level.SEVERE, "Runtime error", re1);
+ eventBus.post(new ConnectionClosed(this, re1));
} finally {
established = false;
logger.info("Closing Connection.");
}
} 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);
+ long position = (messageWords.length > 4) ? Optional.fromNullable(Longs.tryParse(messageWords[4])).or(-1L) : -1;
if (port.isPresent()) {
eventBus.post(new DccAcceptReceived(this, client, messageWords[2], port.get(), position));
} else {
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;
* 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"));
}
//
//
/**
+ * 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.
*