_autoWhoCycleTimer.setInterval(_autoWhoInterval * 1000);
_autoWhoCycleTimer.setSingleShot(false);
+ // TokenBucket to avaid sending too much at once
+ _messagesPerSecond = 1;
+ _burstSize = 5;
+ _tokenBucket = 5; // init with a full bucket
+ // TODO:
+ // should be 510 (2 bytes are added when writing to the socket)
+ // maxMsgSize is 510 minus the hostmask which will be added by the server
+ _maxMsgSize = 450;
+
+ _tokenBucketTimer.start(_messagesPerSecond * 1000);
+ _tokenBucketTimer.setSingleShot(false);
+
QHash<QString, QString> channels = coreSession()->persistentChannels(networkId());
foreach(QString chan, channels.keys()) {
_channelKeys[chan.toLower()] = channels[chan];
connect(&_autoReconnectTimer, SIGNAL(timeout()), this, SLOT(doAutoReconnect()));
connect(&_autoWhoTimer, SIGNAL(timeout()), this, SLOT(sendAutoWho()));
connect(&_autoWhoCycleTimer, SIGNAL(timeout()), this, SLOT(startAutoWhoCycle()));
+ connect(&_tokenBucketTimer, SIGNAL(timeout()), this, SLOT(fillBucketAndProcessQueue()));
connect(network, SIGNAL(currentServerSet(const QString &)), this, SLOT(networkInitialized(const QString &)));
connect(network, SIGNAL(useAutoReconnectSet(bool)), this, SLOT(autoReconnectSettingsChanged()));
#ifndef QT_NO_OPENSSL
void NetworkConnection::sslErrors(const QList<QSslError> &sslErrors) {
+ Q_UNUSED(sslErrors)
socket.ignoreSslErrors();
/* TODO errorhandling
QVariantMap errmsg;
}
void NetworkConnection::putRawLine(QByteArray s) {
+ if(_tokenBucket > 0) {
+ // qDebug() << "putRawLine: " << s;
+ writeToSocket(s);
+ } else {
+ _msgQueue.append(s);
+ }
+}
+
+void NetworkConnection::writeToSocket(QByteArray s) {
s += "\r\n";
+ // qDebug() << "writeToSocket: " << s.size();
socket.write(s);
+ _tokenBucket--;
+}
+
+void NetworkConnection::fillBucketAndProcessQueue() {
+ if(_tokenBucket < _burstSize) {
+ _tokenBucket++;
+ }
+
+ while(_msgQueue.size() > 0 && _tokenBucket > 0) {
+ writeToSocket(_msgQueue.takeFirst());
+ }
}
void NetworkConnection::putCmd(const QString &cmd, const QVariantList ¶ms, const QByteArray &prefix) {
if(!params.isEmpty())
msg += " :" + params.last().toByteArray();
+ if(cmd == "PRIVMSG" && params.count() > 1) {
+ QByteArray msghead = "PRIVMSG " + params[0].toByteArray() + " :";
+
+ while (msg.size() > _maxMsgSize) {
+ QByteArray splitter(" .,-");
+ int splitPosition = 0;
+ for(int i = 0; i < splitter.size(); i++) {
+ splitPosition = qMax(splitPosition, msg.lastIndexOf(splitter[i], _maxMsgSize));
+ }
+ if(splitPosition < 300) {
+ splitPosition = _maxMsgSize;
+ }
+ putRawLine(msg.left(splitPosition));
+ msg = msghead + msg.mid(splitPosition);
+ }
+ }
+
putRawLine(msg);
}
IrcChannel *ircchan = network()->ircChannel(chan);
if(!ircchan) continue;
if(_autoWhoNickLimit > 0 && ircchan->ircUsers().count() > _autoWhoNickLimit) continue;
- _autoWhoInProgress.insert(chan);
+ _autoWhoInProgress[chan]++;
putRawLine("WHO " + serverEncode(chan));
if(_autoWhoQueue.isEmpty() && _autoWhoEnabled && !_autoWhoCycleTimer.isActive()) {
// Timer was stopped, means a new cycle is due immediately
}
bool NetworkConnection::setAutoWhoDone(const QString &channel) {
- return _autoWhoInProgress.remove(channel);
+ if(_autoWhoInProgress.value(channel.toLower(), 0) <= 0) return false;
+ _autoWhoInProgress[channel.toLower()]--;
+ return true;
}
void NetworkConnection::setChannelJoined(const QString &channel) {
emit channelJoined(networkId(), channel, _channelKeys[channel.toLower()]);
- _autoWhoQueue.prepend(channel); // prepend so this new chan is the first to be checked
+ _autoWhoQueue.prepend(channel.toLower()); // prepend so this new chan is the first to be checked
}
void NetworkConnection::setChannelParted(const QString &channel) {
removeChannelKey(channel);
- _autoWhoQueue.removeAll(channel);
- _autoWhoInProgress.remove(channel);
+ _autoWhoQueue.removeAll(channel.toLower());
+ _autoWhoInProgress.remove(channel.toLower());
emit channelParted(networkId(), channel);
}