mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
Cache topPeers locally.
This commit is contained in:
@@ -9,6 +9,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
ByteArrayWriter::ByteArrayWriter(int expectedSize)
|
||||
: _stream(&_result, QIODevice::WriteOnly) {
|
||||
if (expectedSize) {
|
||||
_result.reserve(expectedSize);
|
||||
}
|
||||
_stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
|
||||
QByteArray ByteArrayWriter::result() && {
|
||||
_stream.device()->close();
|
||||
return std::move(_result);
|
||||
}
|
||||
|
||||
ByteArrayReader::ByteArrayReader(QByteArray data)
|
||||
: _data(std::move(data))
|
||||
, _stream(&_data, QIODevice::ReadOnly) {
|
||||
_stream.setVersion(QDataStream::Qt_5_1);
|
||||
}
|
||||
|
||||
void writeColor(QDataStream &stream, const QColor &color) {
|
||||
stream << (quint32(uchar(color.red()))
|
||||
| (quint32(uchar(color.green())) << 8)
|
||||
|
@@ -14,6 +14,70 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
class ByteArrayWriter final {
|
||||
public:
|
||||
explicit ByteArrayWriter(int expectedSize = 0);
|
||||
|
||||
[[nodiscard]] QDataStream &underlying() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] operator QDataStream &() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] QByteArray result() &&;
|
||||
|
||||
private:
|
||||
QByteArray _result;
|
||||
QDataStream _stream;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ByteArrayWriter &operator<<(ByteArrayWriter &stream, const T &data) {
|
||||
stream.underlying() << data;
|
||||
return stream;
|
||||
}
|
||||
|
||||
class ByteArrayReader final {
|
||||
public:
|
||||
explicit ByteArrayReader(QByteArray data);
|
||||
|
||||
[[nodiscard]] QDataStream &underlying() {
|
||||
return _stream;
|
||||
}
|
||||
[[nodiscard]] operator QDataStream &() {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool atEnd() const {
|
||||
return _stream.atEnd();
|
||||
}
|
||||
[[nodiscard]] bool status() const {
|
||||
return _stream.status();
|
||||
}
|
||||
[[nodiscard]] bool ok() const {
|
||||
return _stream.status() == QDataStream::Ok;
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray _data;
|
||||
QDataStream _stream;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ByteArrayReader &operator>>(ByteArrayReader &stream, T &data) {
|
||||
if (!stream.ok()) {
|
||||
data = T();
|
||||
} else {
|
||||
stream.underlying() >> data;
|
||||
if (!stream.ok()) {
|
||||
data = T();
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline int stringSize(const QString &str) {
|
||||
return sizeof(quint32) + str.size() * sizeof(ushort);
|
||||
}
|
||||
|
@@ -118,12 +118,16 @@ uint32 peerSize(not_null<PeerData*> peer) {
|
||||
+ imageLocationSize(peer->userpicLocation())
|
||||
+ sizeof(qint32); // userpic has video
|
||||
if (const auto user = peer->asUser()) {
|
||||
const auto botInlinePlaceholder = user->isBot()
|
||||
? user->botInfo->inlinePlaceholder
|
||||
: QString();
|
||||
result += stringSize(user->firstName)
|
||||
+ stringSize(user->lastName)
|
||||
+ stringSize(user->phone())
|
||||
+ stringSize(user->username())
|
||||
+ sizeof(quint64) // access
|
||||
+ sizeof(qint32) // flags
|
||||
+ stringSize(botInlinePlaceholder)
|
||||
+ sizeof(quint32) // lastseen
|
||||
+ sizeof(qint32) // contact
|
||||
+ sizeof(qint32); // botInfoVersion
|
||||
|
@@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "core/file_location.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
@@ -42,6 +43,7 @@ using namespace details;
|
||||
using Database = Cache::Database;
|
||||
|
||||
constexpr auto kDelayedWriteTimeout = crl::time(1000);
|
||||
constexpr auto kWriteSearchSuggestionsDelay = 5 * crl::time(1000);
|
||||
|
||||
constexpr auto kStickersVersionTag = quint32(-1);
|
||||
constexpr auto kStickersSerializeVersion = 4;
|
||||
@@ -87,6 +89,7 @@ enum { // Local Storage Keys
|
||||
lskSelfSerialized = 0x15, // serialized self
|
||||
lskMasksKeys = 0x16, // no data
|
||||
lskCustomEmojiKeys = 0x17, // no data
|
||||
lskSearchSuggestions = 0x18, // no data
|
||||
};
|
||||
|
||||
auto EmptyMessageDraftSources()
|
||||
@@ -137,10 +140,13 @@ Account::Account(not_null<Main::Account*> owner, const QString &dataName)
|
||||
, _cacheTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _cacheBigFileTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _writeMapTimer([=] { writeMap(); })
|
||||
, _writeLocationsTimer([=] { writeLocations(); }) {
|
||||
, _writeLocationsTimer([=] { writeLocations(); })
|
||||
, _writeSearchSuggestionsTimer([=] { writeSearchSuggestions(); }) {
|
||||
}
|
||||
|
||||
Account::~Account() {
|
||||
Expects(!_writeSearchSuggestionsTimer.isActive());
|
||||
|
||||
if (_localKey && _mapChanged) {
|
||||
writeMap();
|
||||
}
|
||||
@@ -209,6 +215,7 @@ base::flat_set<QString> Account::collectGoodNames() const {
|
||||
_installedCustomEmojiKey,
|
||||
_featuredCustomEmojiKey,
|
||||
_archivedCustomEmojiKey,
|
||||
_searchSuggestionsKey,
|
||||
};
|
||||
auto result = base::flat_set<QString>{
|
||||
"map0",
|
||||
@@ -294,6 +301,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
quint64 savedGifsKey = 0;
|
||||
quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0;
|
||||
quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0;
|
||||
quint64 searchSuggestionsKey = 0;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
map.stream >> keyType;
|
||||
@@ -399,6 +407,9 @@ Account::ReadMapResult Account::readMapWith(
|
||||
>> featuredCustomEmojiKey
|
||||
>> archivedCustomEmojiKey;
|
||||
} break;
|
||||
case lskSearchSuggestions: {
|
||||
map.stream >> searchSuggestionsKey;
|
||||
} break;
|
||||
default:
|
||||
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
|
||||
return ReadMapResult::Failed;
|
||||
@@ -434,6 +445,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
_settingsKey = userSettingsKey;
|
||||
_recentHashtagsAndBotsKey = recentHashtagsAndBotsKey;
|
||||
_exportSettingsKey = exportSettingsKey;
|
||||
_searchSuggestionsKey = searchSuggestionsKey;
|
||||
_oldMapVersion = mapData.version;
|
||||
|
||||
if (_oldMapVersion < AppVersion) {
|
||||
@@ -539,6 +551,7 @@ void Account::writeMap() {
|
||||
if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) {
|
||||
mapSize += sizeof(quint32) + 3 * sizeof(quint64);
|
||||
}
|
||||
if (_searchSuggestionsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
|
||||
EncryptedDescriptor mapData(mapSize);
|
||||
if (!self.isEmpty()) {
|
||||
@@ -598,12 +611,18 @@ void Account::writeMap() {
|
||||
<< quint64(_featuredCustomEmojiKey)
|
||||
<< quint64(_archivedCustomEmojiKey);
|
||||
}
|
||||
if (_searchSuggestionsKey) {
|
||||
mapData.stream << quint32(lskSearchSuggestions);
|
||||
mapData.stream << quint64(_searchSuggestionsKey);
|
||||
}
|
||||
map.writeEncrypted(mapData, _localKey);
|
||||
|
||||
_mapChanged = false;
|
||||
}
|
||||
|
||||
void Account::reset() {
|
||||
_writeSearchSuggestionsTimer.cancel();
|
||||
|
||||
auto names = collectGoodNames();
|
||||
_draftsMap.clear();
|
||||
_draftCursorsMap.clear();
|
||||
@@ -624,6 +643,7 @@ void Account::reset() {
|
||||
_archivedCustomEmojiKey = 0;
|
||||
_legacyBackgroundKeyDay = _legacyBackgroundKeyNight = 0;
|
||||
_settingsKey = _recentHashtagsAndBotsKey = _exportSettingsKey = 0;
|
||||
_searchSuggestionsKey = 0;
|
||||
_oldMapVersion = 0;
|
||||
_fileLocations.clear();
|
||||
_fileLocationPairs.clear();
|
||||
@@ -2842,6 +2862,73 @@ Export::Settings Account::readExportSettings() {
|
||||
: Export::Settings();
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestionsDelayed() {
|
||||
Expects(_owner->sessionExists());
|
||||
|
||||
if (!_writeSearchSuggestionsTimer.isActive()) {
|
||||
_writeSearchSuggestionsTimer.callOnce(kWriteSearchSuggestionsDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestionsIfNeeded() {
|
||||
if (_writeSearchSuggestionsTimer.isActive()) {
|
||||
_writeSearchSuggestionsTimer.cancel();
|
||||
writeSearchSuggestions();
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSearchSuggestions() {
|
||||
Expects(_owner->sessionExists());
|
||||
|
||||
const auto top = _owner->session().topPeers().serialize();
|
||||
const auto recent = QByteArray();// _owner->session().recentPeers().serialize();
|
||||
if (top.isEmpty() && recent.isEmpty()) {
|
||||
if (_searchSuggestionsKey) {
|
||||
ClearKey(_searchSuggestionsKey, _basePath);
|
||||
_searchSuggestionsKey = 0;
|
||||
writeMapDelayed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!_searchSuggestionsKey) {
|
||||
_searchSuggestionsKey = GenerateKey(_basePath);
|
||||
writeMapQueued();
|
||||
}
|
||||
quint32 size = Serialize::bytearraySize(top)
|
||||
+ Serialize::bytearraySize(recent);
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << top << recent;
|
||||
|
||||
FileWriteDescriptor file(_searchSuggestionsKey, _basePath);
|
||||
file.writeEncrypted(data, _localKey);
|
||||
}
|
||||
|
||||
void Account::readSearchSuggestions() {
|
||||
if (_searchSuggestionsRead) {
|
||||
return;
|
||||
}
|
||||
_searchSuggestionsRead = true;
|
||||
if (!_searchSuggestionsKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileReadDescriptor suggestions;
|
||||
if (!ReadEncryptedFile(suggestions, _searchSuggestionsKey, _basePath, _localKey)) {
|
||||
ClearKey(_searchSuggestionsKey, _basePath);
|
||||
_searchSuggestionsKey = 0;
|
||||
writeMapDelayed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto top = QByteArray();
|
||||
auto recent = QByteArray();
|
||||
suggestions.stream >> top >> recent;
|
||||
if (CheckStreamStatus(suggestions.stream)) {
|
||||
_owner->session().topPeers().applyLocal(top);
|
||||
//_owner->session().recentPeers().applyLocal(recent);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeSelf() {
|
||||
writeMapDelayed();
|
||||
}
|
||||
|
@@ -148,6 +148,11 @@ public:
|
||||
void writeExportSettings(const Export::Settings &settings);
|
||||
[[nodiscard]] Export::Settings readExportSettings();
|
||||
|
||||
void writeSearchSuggestionsDelayed();
|
||||
void writeSearchSuggestionsIfNeeded();
|
||||
void writeSearchSuggestions();
|
||||
void readSearchSuggestions();
|
||||
|
||||
void writeSelf();
|
||||
|
||||
// Read self is special, it can't get session from account, because
|
||||
@@ -291,6 +296,7 @@ private:
|
||||
FileKey _installedCustomEmojiKey = 0;
|
||||
FileKey _featuredCustomEmojiKey = 0;
|
||||
FileKey _archivedCustomEmojiKey = 0;
|
||||
FileKey _searchSuggestionsKey = 0;
|
||||
|
||||
qint64 _cacheTotalSizeLimit = 0;
|
||||
qint64 _cacheBigFileTotalSizeLimit = 0;
|
||||
@@ -301,11 +307,13 @@ private:
|
||||
bool _trustedBotsRead = false;
|
||||
bool _readingUserSettings = false;
|
||||
bool _recentHashtagsAndBotsWereRead = false;
|
||||
bool _searchSuggestionsRead = false;
|
||||
|
||||
int _oldMapVersion = 0;
|
||||
|
||||
base::Timer _writeMapTimer;
|
||||
base::Timer _writeLocationsTimer;
|
||||
base::Timer _writeSearchSuggestionsTimer;
|
||||
bool _mapChanged = false;
|
||||
bool _locationsChanged = false;
|
||||
|
||||
|
Reference in New Issue
Block a user