Add command queue prepend, prioritize PING/PONG
authorShane Synan <digitalcircuit36939@gmail.com>
Wed, 1 Jun 2016 23:00:38 +0000 (19:00 -0400)
committerManuel Nickschas <sputnick@quassel-irc.org>
Mon, 5 Sep 2016 17:21:45 +0000 (19:21 +0200)
Add optional flag to putRawLine and putCmd to put any given lines or
commands to the front of the queue (prepend instead of append).

Enable queue prepend for sending PINGs and PONG replies.  This fixes
the issue where Quassel will ping-timeout when trying to send huge
messages (e.g. 40 lines at once), or multiple commands.

Unfortunately, some IRC servers don't behave properly so Quassel may
still get disconnected.  Hopefully other servers will get fixed soon.

Add more documentation, of course.  Document all the things!

src/core/corebasichandler.cpp
src/core/corebasichandler.h
src/core/corenetwork.cpp
src/core/corenetwork.h
src/core/coresessioneventprocessor.cpp
src/core/coreuserinputhandler.cpp

index cf174d1..073e7a7 100644 (file)
@@ -30,14 +30,14 @@ CoreBasicHandler::CoreBasicHandler(CoreNetwork *parent)
     connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)),
         network(), SLOT(displayMsg(Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)));
 
     connect(this, SIGNAL(displayMsg(Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)),
         network(), SLOT(displayMsg(Message::Type, BufferInfo::Type, const QString &, const QString &, const QString &, Message::Flags)));
 
-    connect(this, SIGNAL(putCmd(QString, const QList<QByteArray> &, const QByteArray &)),
-        network(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &)));
+    connect(this, SIGNAL(putCmd(QString, const QList<QByteArray> &, const QByteArray &, const bool)),
+        network(), SLOT(putCmd(QString, const QList<QByteArray> &, const QByteArray &, const bool)));
 
 
-    connect(this, SIGNAL(putCmd(QString, const QList<QList<QByteArray>> &, const QByteArray &)),
-        network(), SLOT(putCmd(QString, const QList<QList<QByteArray>> &, const QByteArray &)));
+    connect(this, SIGNAL(putCmd(QString, const QList<QList<QByteArray>> &, const QByteArray &, const bool)),
+        network(), SLOT(putCmd(QString, const QList<QList<QByteArray>> &, const QByteArray &, const bool)));
 
 
-    connect(this, SIGNAL(putRawLine(const QByteArray &)),
-        network(), SLOT(putRawLine(const QByteArray &)));
+    connect(this, SIGNAL(putRawLine(const QByteArray &, const bool)),
+        network(), SLOT(putRawLine(const QByteArray &, const bool)));
 }
 
 
 }
 
 
@@ -142,9 +142,9 @@ BufferInfo::Type CoreBasicHandler::typeByTarget(const QString &target) const
 }
 
 
 }
 
 
-void CoreBasicHandler::putCmd(const QString &cmd, const QByteArray &param, const QByteArray &prefix)
+void CoreBasicHandler::putCmd(const QString &cmd, const QByteArray &param, const QByteArray &prefix, const bool prepend)
 {
     QList<QByteArray> list;
     list << param;
 {
     QList<QByteArray> list;
     list << param;
-    emit putCmd(cmd, list, prefix);
+    emit putCmd(cmd, list, prefix, prepend);
 }
 }
index 2e468b7..7d0fcc6 100644 (file)
@@ -54,12 +54,43 @@ public:
 
 signals:
     void displayMsg(Message::Type, BufferInfo::Type, const QString &target, const QString &text, const QString &sender = "", Message::Flags flags = Message::None);
 
 signals:
     void displayMsg(Message::Type, BufferInfo::Type, const QString &target, const QString &text, const QString &sender = "", Message::Flags flags = Message::None);
-    void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray());
-    void putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix = QByteArray());
-    void putRawLine(const QByteArray &msg);
+
+    /**
+     * Sends the raw (encoded) line, adding to the queue if needed, optionally with higher priority.
+     *
+     * @see CoreNetwork::putRawLine()
+     */
+    void putRawLine(const QByteArray &msg, const bool prepend = false);
+
+    /**
+     * Sends the command with encoded parameters, with optional prefix or high priority.
+     *
+     * @see CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray(), const bool prepend = false)
+     */
+    void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray(), const bool prepend = false);
+
+    /**
+     * Sends the command for each set of encoded parameters, with optional prefix or high priority.
+     *
+     * @see CoreNetwork::putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix = QByteArray(), const bool prepend = false)
+     */
+    void putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix = QByteArray(), const bool prepend = false);
 
 protected:
 
 protected:
-    void putCmd(const QString &cmd, const QByteArray &param, const QByteArray &prefix = QByteArray());
+    /**
+     * Sends the command with one parameter, with optional prefix or high priority.
+     *
+     * @param[in] cmd      Command to send, ignoring capitalization
+     * @param[in] param    Parameter for the command, encoded within a QByteArray
+     * @param[in] prefix   Optional command prefix
+     * @param[in] prepend
+     * @parmblock
+     * If true, the command is prepended into the start of the queue, otherwise, it's appended to
+     * the end.  This should be used sparingly, for if either the core or the IRC server cannot
+     * maintain PING/PONG replies, the other side will close the connection.
+     * @endparmblock
+     */
+    void putCmd(const QString &cmd, const QByteArray &param, const QByteArray &prefix = QByteArray(), const bool prepend = false);
 
     inline CoreNetwork *network() const { return _network; }
     inline CoreSession *coreSession() const { return _network->coreSession(); }
 
     inline CoreNetwork *network() const { return _network; }
     inline CoreSession *coreSession() const { return _network->coreSession(); }
index ca935d9..f622eea 100644 (file)
@@ -268,16 +268,21 @@ void CoreNetwork::userInput(BufferInfo buf, QString msg)
 }
 
 
 }
 
 
-void CoreNetwork::putRawLine(QByteArray s)
+void CoreNetwork::putRawLine(const QByteArray s, const bool prepend)
 {
 {
-    if (_tokenBucket > 0)
+    if (_tokenBucket > 0) {
         writeToSocket(s);
         writeToSocket(s);
-    else
-        _msgQueue.append(s);
+    } else {
+        if (prepend) {
+            _msgQueue.prepend(s);
+        } else {
+            _msgQueue.append(s);
+        }
+    }
 }
 
 
 }
 
 
-void CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix)
+void CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix, const bool prepend)
 {
     QByteArray msg;
 
 {
     QByteArray msg;
 
@@ -294,16 +299,16 @@ void CoreNetwork::putCmd(const QString &cmd, const QList<QByteArray> &params, co
         msg += params[i];
     }
 
         msg += params[i];
     }
 
-    putRawLine(msg);
+    putRawLine(msg, prepend);
 }
 
 
 }
 
 
-void CoreNetwork::putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix)
+void CoreNetwork::putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix, const bool prependAll)
 {
     QListIterator<QList<QByteArray>> i(params);
     while (i.hasNext()) {
         QList<QByteArray> msg = i.next();
 {
     QListIterator<QList<QByteArray>> i(params);
     while (i.hasNext()) {
         QList<QByteArray> msg = i.next();
-        putCmd(cmd, msg, prefix);
+        putCmd(cmd, msg, prefix, prependAll);
     }
 }
 
     }
 }
 
index 74540be..669b667 100644 (file)
@@ -159,9 +159,53 @@ public slots:
     void disconnectFromIrc(bool requested = true, const QString &reason = QString(), bool withReconnect = false);
 
     void userInput(BufferInfo bufferInfo, QString msg);
     void disconnectFromIrc(bool requested = true, const QString &reason = QString(), bool withReconnect = false);
 
     void userInput(BufferInfo bufferInfo, QString msg);
-    void putRawLine(QByteArray input);
-    void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray());
-    void putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix = QByteArray());
+
+    /**
+     * Sends the raw (encoded) line, adding to the queue if needed, optionally with higher priority.
+     *
+     * @param[in] input   QByteArray of encoded characters
+     * @param[in] prepend
+     * @parmblock
+     * If true, the line is prepended into the start of the queue, otherwise, it's appended to the
+     * end.  This should be used sparingly, for if either the core or the IRC server cannot maintain
+     * PING/PONG replies, the other side will close the connection.
+     * @endparmblock
+     */
+    void putRawLine(const QByteArray input, const bool prepend = false);
+
+    /**
+     * Sends the command with encoded parameters, with optional prefix or high priority.
+     *
+     * @param[in] cmd      Command to send, ignoring capitalization
+     * @param[in] params   Parameters for the command, encoded within a QByteArray
+     * @param[in] prefix   Optional command prefix
+     * @param[in] prepend
+     * @parmblock
+     * If true, the command is prepended into the start of the queue, otherwise, it's appended to
+     * the end.  This should be used sparingly, for if either the core or the IRC server cannot
+     * maintain PING/PONG replies, the other side will close the connection.
+     * @endparmblock
+     */
+    void putCmd(const QString &cmd, const QList<QByteArray> &params, const QByteArray &prefix = QByteArray(), const bool prepend = false);
+
+    /**
+     * Sends the command for each set of encoded parameters, with optional prefix or high priority.
+     *
+     * @param[in] cmd         Command to send, ignoring capitalization
+     * @param[in] params
+     * @parmblock
+     * List of parameter lists for the command, encoded within a QByteArray.  The command will be
+     * sent multiple times, once for each set of params stored within the outer list.
+     * @endparmblock
+     * @param[in] prefix      Optional command prefix
+     * @param[in] prependAll
+     * @parmblock
+     * If true, ALL of the commands are prepended into the start of the queue, otherwise, they're
+     * appended to the end.  This should be used sparingly, for if either the core or the IRC server
+     * cannot maintain PING/PONG replies, the other side will close the connection.
+     * @endparmblock
+     */
+    void putCmd(const QString &cmd, const QList<QList<QByteArray>> &params, const QByteArray &prefix = QByteArray(), const bool prependAll = false);
 
     void setChannelJoined(const QString &channel);
     void setChannelParted(const QString &channel);
 
     void setChannelJoined(const QString &channel);
     void setChannelParted(const QString &channel);
index 8acae81..ae67021 100644 (file)
@@ -515,7 +515,8 @@ void CoreSessionEventProcessor::processIrcEventPing(IrcEvent *e)
 {
     QString param = e->params().count() ? e->params().first() : QString();
     // FIXME use events
 {
     QString param = e->params().count() ? e->params().first() : QString();
     // FIXME use events
-    coreNetwork(e)->putRawLine("PONG " + coreNetwork(e)->serverEncode(param));
+    // Take priority so this won't get stuck behind other queued messages.
+    coreNetwork(e)->putRawLine("PONG " + coreNetwork(e)->serverEncode(param), true);
 }
 
 
 }
 
 
index 608ad96..b5c82c1 100644 (file)
@@ -545,7 +545,8 @@ void CoreUserInputHandler::handlePing(const BufferInfo &bufferInfo, const QStrin
     if (param.isEmpty())
         param = QTime::currentTime().toString("hh:mm:ss.zzz");
 
     if (param.isEmpty())
         param = QTime::currentTime().toString("hh:mm:ss.zzz");
 
-    putCmd("PING", serverEncode(param));
+    // Take priority so this won't get stuck behind other queued messages.
+    putCmd("PING", serverEncode(param), QByteArray(), true);
 }
 
 
 }