[OpenDocString] kdeconnect-kde (cpp)
requestconversationworker.cpp
RequestConversationWorker::RequestConversationWorker(const qint64 &conversationID, int start, int end, ConversationsDbusInterface *interface)
    : // QObject(interface)
    conversationID(conversationID)
    , start(start)
    , parent(interface)
    , m_thread(new QThread)
{
    Q_ASSERT(end >= start && "Not allowed to have a negative-length range");
    howMany = end - start;

    this->moveToThread(m_thread);
    connect(m_thread, &QThread::started, this, &RequestConversationWorker::handleRequestConversation);
    connect(m_thread, &QThread::finished, m_thread, &QObject::deleteLater);
    connect(this, &RequestConversationWorker::finished, m_thread, &QThread::quit);
    connect(this, &RequestConversationWorker::finished, this, &QObject::deleteLater);
}
This constructor builds a conversation object and its m_thread object, and requests it from the beginning of the given range. It takes the conversation id, start and end values, and creates a new m_thread object of the given type, and sets up signal/slot connections for the started and finished events.
void RequestConversationWorker::handleRequestConversation()
{
    auto messagesList = parent->getConversation(conversationID);

    if (messagesList.isEmpty()) {
        // Since there are no messages in the conversation, it's likely that it is a junk ID, but go ahead anyway
        qCWarning(KDECONNECT_CONVERSATIONS) << "Got a conversationID for a conversation with no messages!" << conversationID;
    }

    // In case the remote takes awhile to respond, we should go ahead and do anything we can from the cache
    size_t numHandled = replyForConversation(messagesList, start, howMany);

    if (numHandled < howMany) {
        // In this case, the cache wasn't able to satisfy the request fully. Get more.

        size_t numRemaining = howMany - numHandled;
        parent->updateConversation(conversationID);
        messagesList = parent->getConversation(conversationID);
        // ConversationsDbusInterface::updateConversation blocks until it sees new messages in the requested conversation
        replyForConversation(messagesList, start + numHandled, numRemaining);
    } else {
        // The cache was able to fully satisfy the request but we need to check that it isn't running dry

        size_t numCachedMessages = messagesList.count();
        size_t requestEnd = start + numHandled;
        size_t numRemainingMessages = numCachedMessages - requestEnd;
        double percentRemaining = ((double)numRemainingMessages / numCachedMessages) * 100;

        if (percentRemaining < CACHE_LOW_WATER_MARK_PERCENT || numRemainingMessages < MIN_NUMBER_TO_REQUEST) {
            parent->updateConversation(conversationID);
        }
    }

    Q_EMIT finished();
}
This code is responsible for handling requests that come in a conversation. It first gets the messages list from the conversation, then checks if the request is able to satisfy the request and if it is able to get more messages, it sends them to the parent. Then it checks if the request is able to satisfy the request and if it is running dry, it makes sure the request is not running dry. If the request is able to satisfy the request, it makes sure the parent is still running. If it is not running dry, it assumes that it is called from the parent. It also gets the number of messages in the conversation, and emits a signal finished.
size_t RequestConversationWorker::replyForConversation(const QList &conversation, int start, size_t howMany)
{
    Q_ASSERT(start >= 0);
    // Messages are sorted in ascending order of keys, meaning the front of the list has the oldest
    // messages (smallest timestamp number)
    // Therefore, return the end of the list first (most recent messages)
    size_t i = 0;
    for (auto it = conversation.crbegin() + start; it != conversation.crend(); ++it) {
        if (i >= howMany) {
            break;
        }
        Q_EMIT conversationMessageRead(QDBusVariant(QVariant::fromValue(*it)));
        i++;
    }

    return i;
}
This code creates a reply list from a given conversation, starting from the given start index, and returning howMany messages. It returns the number of messages actually read, and returns it.
void RequestConversationWorker::work()
{
    m_thread->start();
}
This starts the worker thread and marks it for work.