client: Add AsNeededBacklogRequester, faster login
authorShane Synan <digitalcircuit36939@gmail.com>
Sun, 28 Jun 2020 05:49:43 +0000 (01:49 -0400)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 4 Oct 2020 16:19:48 +0000 (18:19 +0200)
Add AsNeededBacklogRequester, which behaves exactly like the
FixedBacklogRequester for legacy cores older than v0.13.0
(lacking Feature::BufferActivitySync).  For modern cores, no backlog
is initially fetched.  This should speed up logging in with no loss of
buffer activity signaling.

This breaks the "Show messages from backlog" feature as no backlog is
fetched.  The original always-fetch backlog requesters remain
available for those who prefer having the backlog in the Chat Monitor.

Add a warning to the Chat Monitor settings page when
"Only fetch when needed" Backlog Fetching is enabled.

Don't allow BacklogSettings to return the GlobalUnread backlog
requester type.  The UI for choosing it has been disabled, but it
could have accidentally been selected in the past.  If this had
happened before this change, AsNeeded will be selected instead.

src/client/backlogrequester.cpp
src/client/backlogrequester.h
src/client/backlogsettings.cpp
src/client/backlogsettings.h
src/client/clientbacklogmanager.cpp
src/qtui/settingspages/backlogsettingspage.cpp
src/qtui/settingspages/backlogsettingspage.ui
src/qtui/settingspages/chatmonitorsettingspage.cpp
src/qtui/settingspages/chatmonitorsettingspage.h
src/qtui/settingspages/chatmonitorsettingspage.ui

index 93399b6..26fb486 100644 (file)
@@ -131,3 +131,30 @@ void PerBufferUnreadBacklogRequester::requestBacklog(const BufferIdList& bufferI
         backlogManager->requestBacklog(bufferId, Client::networkModel()->lastSeenMsgId(bufferId), -1, _limit, _additional);
     }
 }
+
+// ========================================
+//  AS NEEDED BACKLOG REQUESTER
+// ========================================
+AsNeededBacklogRequester::AsNeededBacklogRequester(ClientBacklogManager* backlogManager)
+    : BacklogRequester(false, BacklogRequester::AsNeeded, backlogManager)
+{
+    BacklogSettings backlogSettings;
+    _legacyBacklogCount = backlogSettings.asNeededLegacyBacklogAmount();
+}
+
+void AsNeededBacklogRequester::requestBacklog(const BufferIdList& bufferIds)
+{
+    // Check if the core supports activity tracking
+    if (Client::isCoreFeatureEnabled(Quassel::Feature::BufferActivitySync)) {
+        // Don't fetch any backlog, the core will track buffer activity for us
+        return;
+    }
+
+    setWaitingBuffers(bufferIds);
+    backlogManager->emitMessagesRequested(QObject::tr("Requesting a total of up to %1 backlog messages for %2 buffers")
+                                              .arg(_legacyBacklogCount * bufferIds.count())
+                                              .arg(bufferIds.count()));
+    foreach (BufferId bufferId, bufferIds) {
+        backlogManager->requestBacklog(bufferId, -1, -1, _legacyBacklogCount);
+    }
+}
index 7357127..3acd793 100644 (file)
@@ -39,6 +39,7 @@ public:
         InvalidRequester = 0,
         PerBufferFixed,
         PerBufferUnread,
+        AsNeeded,              ///< Only request backlog on cores without Feature::BufferActivitySync
         GlobalUnread
     };
 
@@ -114,3 +115,20 @@ private:
     int _limit;
     int _additional;
 };
+
+// ========================================
+//  AS NEEDED BACKLOG REQUESTER
+// ========================================
+/**
+ * Backlog requester that only fetches initial backlog when the core doesn't support buffer activity
+ * tracking
+ */
+class AsNeededBacklogRequester : public BacklogRequester
+{
+public:
+    AsNeededBacklogRequester(ClientBacklogManager* backlogManager);
+    void requestBacklog(const BufferIdList& bufferIds) override;
+
+private:
+    int _legacyBacklogCount;
+};
index d6a25f7..fda3076 100644 (file)
@@ -26,11 +26,17 @@ BacklogSettings::BacklogSettings()
 
 int BacklogSettings::requesterType() const
 {
-    return localValue("RequesterType", BacklogRequester::PerBufferUnread).toInt();
+    int _requesterType = localValue("RequesterType", BacklogRequester::PerBufferUnread).toInt();
+    if (_requesterType == BacklogRequester::GlobalUnread) {
+        // GlobalUnread is currently disabled; don't allow it to be used.  Reset to default instead.
+        _requesterType = BacklogRequester::PerBufferUnread;
+    }
+    return _requesterType;
 }
 
 void BacklogSettings::setRequesterType(int requesterType)
 {
+    // This settings key is also used within ChatMonitorSettingsPage::ChatMonitorSettingsPage()
     setLocalValue("RequesterType", requesterType);
 }
 
@@ -104,3 +110,15 @@ void BacklogSettings::setPerBufferUnreadBacklogAdditional(int additional)
 {
     return setLocalValue("PerBufferUnreadBacklogAdditional", additional);
 }
+
+int BacklogSettings::asNeededLegacyBacklogAmount() const
+{
+    // Mimic FixedBacklogAmount defaults.  This is only used on cores lacking
+    // Feature::BufferActivitySync.
+    return localValue("AsNeededLegacyBacklogAmount", 500).toInt();
+}
+
+void BacklogSettings::setAsNeededLegacyBacklogAmount(int amount)
+{
+    return setLocalValue("AsNeededLegacyBacklogAmount", amount);
+}
index aee0376..76f51ad 100644 (file)
@@ -62,4 +62,21 @@ public:
     void setPerBufferUnreadBacklogLimit(int limit);
     int perBufferUnreadBacklogAdditional() const;
     void setPerBufferUnreadBacklogAdditional(int additional);
+
+    /**
+     * Get the initial amount of backlog fetched across all buffers for legacy cores that do not
+     * support Quassel::Feature::BufferActivitySync
+     *
+     * @seealso Quassel::Feature::BufferActivitySync
+     * @return The amount of backlog to fetch per buffer
+     */
+    int asNeededLegacyBacklogAmount() const;
+    /**
+     * Set the initial amount of backlog fetched across all buffers for legacy cores that do not
+     * support Quassel::Feature::BufferActivitySync
+     *
+     * @seealso BacklogSettings::asNeededLegacyBacklogAmount()
+     * @param amount The amount of backlog to fetch per buffer
+     */
+    void setAsNeededLegacyBacklogAmount(int amount);
 };
index 3eafc86..3398f1a 100644 (file)
@@ -97,6 +97,9 @@ void ClientBacklogManager::requestInitialBacklog()
 
     BacklogSettings settings;
     switch (settings.requesterType()) {
+    case BacklogRequester::AsNeeded:
+        _requester = new AsNeededBacklogRequester(this);
+        break;
     case BacklogRequester::GlobalUnread:
         _requester = new GlobalUnreadBacklogRequester(this);
         break;
@@ -144,6 +147,7 @@ void ClientBacklogManager::checkForBacklog(const QList<BufferId>& bufferIds)
         break;
     case BacklogRequester::PerBufferUnread:
     case BacklogRequester::PerBufferFixed:
+    case BacklogRequester::AsNeeded:
     default: {
         BufferIdList buffers = filterNewBufferIds(bufferIds);
         if (!buffers.isEmpty())
index 450e73f..e797861 100644 (file)
@@ -33,7 +33,8 @@ BacklogSettingsPage::BacklogSettingsPage(QWidget* parent)
     // not an auto widget, because we store index + 1
 
     // FIXME: global backlog requester disabled until issues ruled out
-    ui.requesterType->removeItem(2);
+    ui.requesterType->removeItem(3);
+    // If modifying ui.requesterType's item list, set to the index of "Globally unread messages"
 
     connectToWidgetChangedSignal(ui.requesterType, this, &BacklogSettingsPage::widgetHasChanged);
 }
index dd15894..feac9cd 100644 (file)
          <string>Unread messages per chat</string>
         </property>
        </item>
+       <item>
+        <property name="text">
+         <string>Only fetch when needed</string>
+        </property>
+       </item>
        <item>
         <property name="text">
          <string>Globally unread messages</string>
@@ -332,6 +337,91 @@ You can also choose to fetch additional older chatlines to provide a better cont
        </item>
       </layout>
      </widget>
+     <widget class="QWidget" name="page_3">
+      <layout class="QVBoxLayout" name="verticalLayout_5">
+       <item>
+        <widget class="QLabel" name="label_16">
+         <property name="text">
+          <string>&lt;p&gt;On modern cores (v0.13.0 or newer), no backlog will be fetched.  The core keeps track of chat activity automatically.&lt;br/&gt;
+&lt;i&gt;Note: Chat Monitor won't show past messages.&lt;/i&gt;
+&lt;/p&gt;
+&lt;p&gt;On older cores, this requester fetches a fixed amount of lines for each chat window from the backlog.&lt;/p&gt;</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+         <property name="wordWrap">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_6">
+         <item>
+          <widget class="QLabel" name="label_4">
+           <property name="toolTip">
+            <string>Amount of messages per buffer that are requested after the core connection has been established.</string>
+           </property>
+           <property name="text">
+            <string>For legacy cores, initial backlog amount:</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QSpinBox" name="asNeededLegacyBacklogAmount">
+           <property name="specialValueText">
+            <string/>
+           </property>
+           <property name="minimum">
+            <number>0</number>
+           </property>
+           <property name="maximum">
+            <number>99999</number>
+           </property>
+           <property name="singleStep">
+            <number>10</number>
+           </property>
+           <property name="value">
+            <number>500</number>
+           </property>
+           <property name="settingsKey" stdset="0">
+            <string notr="true">AsNeededLegacyBacklogAmount</string>
+           </property>
+           <property name="defaultValue" stdset="0">
+            <number>500</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_6">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>263</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <spacer name="verticalSpacer_5">
+         <property name="orientation">
+          <enum>Qt::Vertical</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>20</width>
+           <height>47</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
      <widget class="QWidget" name="Seite">
       <layout class="QVBoxLayout" name="verticalLayout_4">
        <item>
index 16c3627..414cd6d 100644 (file)
 
 #include "chatmonitorsettingspage.h"
 
+#include <QMessageBox>
 #include <QVariant>
 
+#include "backlogrequester.h"
+#include "backlogsettings.h"
 #include "buffermodel.h"
 #include "bufferview.h"
 #include "bufferviewconfig.h"
@@ -67,6 +70,10 @@ ChatMonitorSettingsPage::ChatMonitorSettingsPage(QWidget* parent)
     connect(ui.alwaysOwn, &QAbstractButton::toggled, this, &ChatMonitorSettingsPage::widgetHasChanged);
     connect(ui.showBacklog, &QAbstractButton::toggled, this, &ChatMonitorSettingsPage::widgetHasChanged);
     connect(ui.includeRead, &QAbstractButton::toggled, this, &ChatMonitorSettingsPage::widgetHasChanged);
+
+    // AsNeededBacklogRequester conflicts with showing backlog in Chat Monitor
+    BacklogSettings backlogSettings;
+    backlogSettings.initAndNotify("RequesterType", this, &ChatMonitorSettingsPage::setRequesterType, BacklogRequester::PerBufferUnread);
 }
 
 bool ChatMonitorSettingsPage::hasDefaults() const
@@ -279,3 +286,34 @@ void ChatMonitorSettingsPage::switchOperationMode(int idx)
     }
     widgetHasChanged();
 }
+
+void ChatMonitorSettingsPage::setRequesterType(const QVariant& v)
+{
+    bool usingAsNeededRequester = (v.toInt() == BacklogRequester::AsNeeded);
+    ui.showBacklogUnavailableDetails->setVisible(usingAsNeededRequester);
+    if (usingAsNeededRequester) {
+        ui.showBacklog->setText(tr("Show messages from backlog (not available)"));
+    }
+    else {
+        ui.showBacklog->setText(tr("Show messages from backlog"));
+    }
+}
+
+void ChatMonitorSettingsPage::on_showBacklogUnavailableDetails_clicked()
+{
+    // Explain that backlog fetching is disabled, so backlog messages won't show up
+    //
+    // Technically, backlog messages *will* show up once fetched, e.g. after clicking on a buffer.
+    // This might be too trivial of a detail to warrant explaining, though.
+    QMessageBox::information(this,
+                             tr("Messages from backlog are not fetched"),
+                             QString("<p>%1</p><p>%2</p>")
+                                     .arg(tr("No initial backlog will be fetched when using the backlog request method of <i>%1</i>.")
+                                             .arg(tr("Only fetch when needed").replace(" ", "&nbsp;")),
+                                          tr("Configure this in the <i>%1</i> settings page.")
+                                             .arg(tr("Backlog Fetching").replace(" ", "&nbsp;"))
+                                     )
+    );
+    // Re-use translations of "Only fetch when needed" and "Backlog Fetching" as this is a
+    // word-for-word reference, forcing all spaces to be non-breaking
+}
index aaa5c2f..c72f52a 100644 (file)
@@ -49,6 +49,18 @@ private slots:
     void on_deactivateBuffer_clicked();
     void switchOperationMode(int idx);
 
+    /**
+     * Sets the local cache of the current backlog requester type, used to determine if showing
+     * backlog in the Chat Monitor will work
+     *
+     * @seealso BacklogSettings::setRequesterType()
+     */
+    void setRequesterType(const QVariant&);
+
+    /**
+     * Event handler for Show Backlog Unavailable Details button
+     */
+    void on_showBacklogUnavailableDetails_clicked();
 private:
     Ui::ChatMonitorSettingsPage ui;
     QHash<QString, QVariant> settings;
index 61e3e7c..a543908 100644 (file)
@@ -189,14 +189,31 @@ p, li { white-space: pre-wrap; }
     </layout>
    </item>
    <item>
-    <widget class="QCheckBox" name="showBacklog">
-     <property name="toolTip">
-      <string>Display messages from backlog on reconnect</string>
-     </property>
-     <property name="text">
-      <string>Show messages from backlog</string>
-     </property>
-    </widget>
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
+      <widget class="QCheckBox" name="showBacklog">
+       <property name="toolTip">
+        <string>Display messages from backlog on reconnect</string>
+       </property>
+       <property name="text">
+        <string>Show messages from backlog</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="showBacklogUnavailableDetails">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>Details...</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout_3">
@@ -247,6 +264,7 @@ p, li { white-space: pre-wrap; }
   <tabstop>showOwnMessages</tabstop>
   <tabstop>alwaysOwn</tabstop>
   <tabstop>showBacklog</tabstop>
+  <tabstop>showBacklogUnavailableDetails</tabstop>
   <tabstop>includeRead</tabstop>
  </tabstops>
  <resources/>