Automatically load recent messages on reconnect (#3878)
* Add working reconnect recent messages * Rename method to messagesUpdated * Use audo declarations * Add docs to new LimitedQueue methods * Add more documentation, try atomic loading flag * Update CHANGELOG.md * Remove unused include * Rename 'reconnected' signal to 'connected' * Reserve before filtering on arbitrary update * Extract recent messages fetching to own class * Use std::atomic_flag instead of std::atomic_bool * Add PostToThread include * Add chatterino.recentmessages logging * Remove unneeded parameters, lambda move capture * Remove TwitchChannel::buildRecentMessages * Add documentation, use more clear method name * Reword changelog entry I think it sounds better like this :) * Rework how filling in missing messages is handled This should hopefully prevent issues with filtered channels with old messages that no longer exist in the underlying channel * Check existing messages when looking for reply * Clean up string distribution in file * Try to improve documentation * Use std::function for RecentMessagesApi * Only trigger filledInMessages if we inserted * Remove old unused lines * Use make_shared<MessageLayout> instead of new MessageLayout * Alphabetize QLogging categories * Reorder CHANGELOG.md
This commit is contained in:
+75
-1
@@ -220,7 +220,7 @@ void Channel::disableAllMessages()
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::addMessagesAtStart(std::vector<MessagePtr> &_messages)
|
||||
void Channel::addMessagesAtStart(const std::vector<MessagePtr> &_messages)
|
||||
{
|
||||
std::vector<MessagePtr> addedMessages =
|
||||
this->messages_.pushFront(_messages);
|
||||
@@ -231,6 +231,80 @@ void Channel::addMessagesAtStart(std::vector<MessagePtr> &_messages)
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::fillInMissingMessages(const std::vector<MessagePtr> &messages)
|
||||
{
|
||||
auto snapshot = this->getMessageSnapshot();
|
||||
|
||||
std::unordered_set<QString> existingMessageIds;
|
||||
existingMessageIds.reserve(snapshot.size());
|
||||
|
||||
// First, collect the ids of every message already present in the channel
|
||||
for (auto &msg : snapshot)
|
||||
{
|
||||
if (msg->flags.has(MessageFlag::System) || msg->id.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
existingMessageIds.insert(msg->id);
|
||||
}
|
||||
|
||||
bool anyInserted = false;
|
||||
|
||||
// Keep track of the last message in the channel. We need this value
|
||||
// to allow concurrent appends to the end of the channel while still
|
||||
// being able to insert just-loaded historical messages at the end
|
||||
// in the correct place.
|
||||
auto lastMsg = snapshot[snapshot.size() - 1];
|
||||
for (auto &msg : messages)
|
||||
{
|
||||
// check if message already exists
|
||||
if (existingMessageIds.count(msg->id) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we get to this point, we know we'll be inserting a message
|
||||
anyInserted = true;
|
||||
|
||||
bool insertedFlag = false;
|
||||
for (auto &snapshotMsg : snapshot)
|
||||
{
|
||||
if (snapshotMsg->flags.has(MessageFlag::System))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg->serverReceivedTime < snapshotMsg->serverReceivedTime)
|
||||
{
|
||||
// We found the first message that comes after the current message.
|
||||
// Therefore, we can put the current message directly before. We
|
||||
// assume that the messages we are filling in are in ascending
|
||||
// order by serverReceivedTime.
|
||||
this->messages_.insertBefore(snapshotMsg, msg);
|
||||
insertedFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!insertedFlag)
|
||||
{
|
||||
// We never found a message already in the channel that came after
|
||||
// the current message. Put it at the end and make sure to update
|
||||
// which message is considered "the end".
|
||||
this->messages_.insertAfter(lastMsg, msg);
|
||||
lastMsg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyInserted)
|
||||
{
|
||||
// We only invoke a signal once at the end of filling all messages to
|
||||
// prevent doing any unnecessary repaints.
|
||||
this->filledInMessages.invoke(messages);
|
||||
}
|
||||
}
|
||||
|
||||
void Channel::replaceMessage(MessagePtr message, MessagePtr replacement)
|
||||
{
|
||||
int index = this->messages_.replaceItem(message, replacement);
|
||||
|
||||
+10
-1
@@ -57,8 +57,12 @@ public:
|
||||
messageAppended;
|
||||
pajlada::Signals::Signal<std::vector<MessagePtr> &> messagesAddedAtStart;
|
||||
pajlada::Signals::Signal<size_t, MessagePtr &> messageReplaced;
|
||||
/// Invoked when some number of messages were filled in using time received
|
||||
pajlada::Signals::Signal<const std::vector<MessagePtr> &> filledInMessages;
|
||||
pajlada::Signals::NoArgSignal destroyed;
|
||||
pajlada::Signals::NoArgSignal displayNameChanged;
|
||||
/// Invoked when AbstractIrcServer::onReadConnected occurs
|
||||
pajlada::Signals::NoArgSignal connected;
|
||||
|
||||
Type getType() const;
|
||||
const QString &getName() const;
|
||||
@@ -75,12 +79,17 @@ public:
|
||||
void addMessage(
|
||||
MessagePtr message,
|
||||
boost::optional<MessageFlags> overridingFlags = boost::none);
|
||||
void addMessagesAtStart(std::vector<MessagePtr> &messages_);
|
||||
void addMessagesAtStart(const std::vector<MessagePtr> &messages_);
|
||||
|
||||
/// Inserts the given messages in order by Message::serverReceivedTime.
|
||||
void fillInMissingMessages(const std::vector<MessagePtr> &messages);
|
||||
|
||||
void addOrReplaceTimeout(MessagePtr message);
|
||||
void disableAllMessages();
|
||||
void replaceMessage(MessagePtr message, MessagePtr replacement);
|
||||
void replaceMessage(size_t index, MessagePtr replacement);
|
||||
void deleteMessage(QString messageID);
|
||||
|
||||
MessagePtr findMessage(QString messageID);
|
||||
|
||||
bool hasMessages() const;
|
||||
|
||||
@@ -16,6 +16,7 @@ Q_LOGGING_CATEGORY(chatterinoEmoji, "chatterino.emoji", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoEnv, "chatterino.env", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoFfzemotes, "chatterino.ffzemotes", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoHelper, "chatterino.helper", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoHighlights, "chatterino.highlights", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoHotkeys, "chatterino.hotkeys", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoHTTP, "chatterino.http", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoImage, "chatterino.image", logThreshold);
|
||||
@@ -30,6 +31,8 @@ Q_LOGGING_CATEGORY(chatterinoNotification, "chatterino.notification",
|
||||
Q_LOGGING_CATEGORY(chatterinoNuulsuploader, "chatterino.nuulsuploader",
|
||||
logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoPubSub, "chatterino.pubsub", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoRecentMessages, "chatterino.recentmessages",
|
||||
logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoStreamlink, "chatterino.streamlink", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoStreamerMode, "chatterino.streamermode",
|
||||
logThreshold);
|
||||
@@ -40,4 +43,3 @@ Q_LOGGING_CATEGORY(chatterinoWebsocket, "chatterino.websocket", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoWidget, "chatterino.widget", logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoWindowmanager, "chatterino.windowmanager",
|
||||
logThreshold);
|
||||
Q_LOGGING_CATEGORY(chatterinoHighlights, "chatterino.highlights", logThreshold);
|
||||
|
||||
@@ -12,6 +12,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoEmoji);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoEnv);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoFfzemotes);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoHelper);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoHighlights);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoHotkeys);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoHTTP);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoImage);
|
||||
@@ -23,6 +24,7 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoNativeMessage);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoNotification);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoNuulsuploader);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoPubSub);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoRecentMessages);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamlink);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoStreamerMode);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoTokenizer);
|
||||
@@ -31,4 +33,3 @@ Q_DECLARE_LOGGING_CATEGORY(chatterinoUpdate);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoWebsocket);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoWidget);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoWindowmanager);
|
||||
Q_DECLARE_LOGGING_CATEGORY(chatterinoHighlights);
|
||||
|
||||
Reference in New Issue
Block a user