tdesktop/Telegram/SourceFiles/data/data_history_messages.cpp
2024-05-30 17:02:02 +04:00

219 lines
No EOL
5.9 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_history_messages.h"
#include "apiwrap.h"
#include "data/data_chat.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "data/data_sparse_ids.h"
#include "history/history.h"
#include "main/main_session.h"
namespace Data {
void HistoryMessages::addNew(MsgId messageId) {
_chat.addNew(messageId);
}
void HistoryMessages::addExisting(MsgId messageId, MsgRange noSkipRange) {
_chat.addExisting(messageId, noSkipRange);
}
void HistoryMessages::addSlice(
std::vector<MsgId> &&messageIds,
MsgRange noSkipRange,
std::optional<int> count) {
_chat.addSlice(std::move(messageIds), noSkipRange, count);
}
void HistoryMessages::removeOne(MsgId messageId) {
_chat.removeOne(messageId);
_oneRemoved.fire_copy(messageId);
}
void HistoryMessages::removeAll() {
_chat.removeAll();
_allRemoved.fire({});
}
void HistoryMessages::invalidateBottom() {
_chat.invalidateBottom();
_bottomInvalidated.fire({});
}
Storage::SparseIdsListResult HistoryMessages::snapshot(
const Storage::SparseIdsListQuery &query) const {
return _chat.snapshot(query);
}
auto HistoryMessages::sliceUpdated() const
-> rpl::producer<Storage::SparseIdsSliceUpdate> {
return _chat.sliceUpdated();
}
rpl::producer<MsgId> HistoryMessages::oneRemoved() const {
return _oneRemoved.events();
}
rpl::producer<> HistoryMessages::allRemoved() const {
return _allRemoved.events();
}
rpl::producer<> HistoryMessages::bottomInvalidated() const {
return _bottomInvalidated.events();
}
rpl::producer<SparseIdsSlice> HistoryViewer(
not_null<History*> history,
MsgId aroundId,
int limitBefore,
int limitAfter) {
Expects(IsServerMsgId(aroundId) || (aroundId == 0));
Expects((aroundId != 0) || (limitBefore == 0 && limitAfter == 0));
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto messages = &history->messages();
auto builder = lifetime.make_state<SparseIdsSliceBuilder>(
aroundId,
limitBefore,
limitAfter);
using RequestAroundInfo = SparseIdsSliceBuilder::AroundData;
builder->insufficientAround(
) | rpl::start_with_next([=](const RequestAroundInfo &info) {
if (!info.aroundId) {
// Ignore messages-count-only requests, because we perform
// them with non-zero limit of messages and end up adding
// a broken slice with several last messages from the chat
// with a non-skip range starting at zero.
return;
}
history->session().api().requestHistory(
history,
info.aroundId,
info.direction);
}, lifetime);
auto pushNextSnapshot = [=] {
consumer.put_next(builder->snapshot());
};
using SliceUpdate = Storage::SparseIdsSliceUpdate;
messages->sliceUpdated(
) | rpl::filter([=](const SliceUpdate &update) {
return builder->applyUpdate(update);
}) | rpl::start_with_next(pushNextSnapshot, lifetime);
messages->oneRemoved(
) | rpl::filter([=](MsgId messageId) {
return builder->removeOne(messageId);
}) | rpl::start_with_next(pushNextSnapshot, lifetime);
messages->allRemoved(
) | rpl::filter([=] {
return builder->removeAll();
}) | rpl::start_with_next(pushNextSnapshot, lifetime);
messages->bottomInvalidated(
) | rpl::filter([=] {
return builder->invalidateBottom();
}) | rpl::start_with_next(pushNextSnapshot, lifetime);
const auto snapshot = messages->snapshot({
aroundId,
limitBefore,
limitAfter,
});
if (snapshot.count || !snapshot.messageIds.empty()) {
if (builder->applyInitial(snapshot)) {
pushNextSnapshot();
}
}
builder->checkInsufficient();
return lifetime;
};
}
rpl::producer<SparseIdsMergedSlice> HistoryMergedViewer(
not_null<History*> history,
/*Universal*/MsgId universalAroundId,
int limitBefore,
int limitAfter) {
const auto migrateFrom = history->peer->migrateFrom();
auto createSimpleViewer = [=](
PeerId peerId,
MsgId topicRootId,
SparseIdsSlice::Key simpleKey,
int limitBefore,
int limitAfter) {
const auto chosen = (history->peer->id == peerId)
? history
: history->owner().history(peerId);
return HistoryViewer(chosen, simpleKey, limitBefore, limitAfter);
};
const auto peerId = history->peer->id;
const auto topicRootId = MsgId();
const auto migratedPeerId = migrateFrom ? migrateFrom->id : PeerId(0);
using Key = SparseIdsMergedSlice::Key;
return SparseIdsMergedSlice::CreateViewer(
Key(peerId, topicRootId, migratedPeerId, universalAroundId),
limitBefore,
limitAfter,
std::move(createSimpleViewer));
}
rpl::producer<MessagesSlice> HistoryMessagesViewer(
not_null<History*> history,
MessagePosition aroundId,
int limitBefore,
int limitAfter) {
const auto computeUnreadAroundId = [&] {
if (const auto migrated = history->migrateFrom()) {
if (const auto around = migrated->loadAroundId()) {
return MsgId(around - ServerMaxMsgId);
}
}
if (const auto around = history->loadAroundId()) {
return around;
}
return MsgId(ServerMaxMsgId - 1);
};
const auto messageId = (aroundId.fullId.msg == ShowAtUnreadMsgId)
? computeUnreadAroundId()
: (aroundId.fullId.msg == ShowAtTheEndMsgId)
? (ServerMaxMsgId - 1)
: (aroundId.fullId.peer == history->peer->id)
? aroundId.fullId.msg
: (aroundId.fullId.msg - ServerMaxMsgId);
return HistoryMergedViewer(
history,
messageId,
limitBefore,
limitAfter
) | rpl::map([=](SparseIdsMergedSlice &&slice) {
auto result = Data::MessagesSlice();
result.fullCount = slice.fullCount();
result.skippedAfter = slice.skippedAfter();
result.skippedBefore = slice.skippedBefore();
const auto count = slice.size();
result.ids.reserve(count);
if (const auto msgId = slice.nearest(messageId)) {
result.nearestToAround = *msgId;
}
for (auto i = 0; i != count; ++i) {
result.ids.push_back(slice[i]);
}
return result;
});
}
} // namespace Data