Simple KV storage in session().local().
This commit is contained in:
@@ -100,6 +100,7 @@ enum { // Local Storage Keys
|
||||
lskInlineBotsDownloads = 0x1b, // no data
|
||||
lskMediaLastPlaybackPositions = 0x1c, // no data
|
||||
lskBotStorages = 0x1d, // data: PeerId botId
|
||||
lskPrefs = 0x1e, // no data
|
||||
};
|
||||
|
||||
auto EmptyMessageDraftSources()
|
||||
@@ -177,6 +178,7 @@ Account::Account(not_null<Main::Account*> owner, const QString &dataName)
|
||||
, _cacheTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _cacheBigFileTotalTimeLimit(Database::Settings().totalTimeLimit)
|
||||
, _writeMapTimer([=] { writeMap(); })
|
||||
, _writePrefsTimer([=] { writePrefs(); })
|
||||
, _writeLocationsTimer([=] { writeLocations(); })
|
||||
, _writeSearchSuggestionsTimer([=] { writeSearchSuggestions(); }) {
|
||||
}
|
||||
@@ -184,8 +186,13 @@ Account::Account(not_null<Main::Account*> owner, const QString &dataName)
|
||||
Account::~Account() {
|
||||
Expects(!_writeSearchSuggestionsTimer.isActive());
|
||||
|
||||
if (_localKey && _mapChanged) {
|
||||
writeMap();
|
||||
if (_localKey) {
|
||||
if (_prefsChanged) {
|
||||
writePrefs();
|
||||
}
|
||||
if (_mapChanged) {
|
||||
writeMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,6 +243,7 @@ void Account::clearLegacyFiles() {
|
||||
|
||||
base::flat_set<QString> Account::collectGoodNames() const {
|
||||
const auto keys = {
|
||||
_prefsKey,
|
||||
_locationsKey,
|
||||
_settingsKey,
|
||||
_installedStickersKey,
|
||||
@@ -342,7 +350,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
base::flat_map<PeerId, bool> draftsNotReadMap;
|
||||
base::flat_map<PeerId, FileKey> botStoragesMap;
|
||||
base::flat_map<PeerId, bool> botStoragesNotReadMap;
|
||||
quint64 locationsKey = 0, reportSpamStatusesKey = 0, trustedPeersKey = 0;
|
||||
quint64 prefsKey = 0, locationsKey = 0, reportSpamStatusesKey = 0, trustedPeersKey = 0;
|
||||
quint64 recentStickersKeyOld = 0;
|
||||
quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
|
||||
quint64 installedMasksKey = 0, recentMasksKey = 0, archivedMasksKey = 0;
|
||||
@@ -398,6 +406,9 @@ Account::ReadMapResult Account::readMapWith(
|
||||
// Just ignore the key, it will be removed as a leaked one.
|
||||
}
|
||||
} break;
|
||||
case lskPrefs: {
|
||||
map.stream >> prefsKey;
|
||||
} break;
|
||||
case lskLocations: {
|
||||
map.stream >> locationsKey;
|
||||
} break;
|
||||
@@ -506,6 +517,7 @@ Account::ReadMapResult Account::readMapWith(
|
||||
_botStoragesMap = botStoragesMap;
|
||||
_botStoragesNotReadMap = botStoragesNotReadMap;
|
||||
|
||||
_prefsKey = prefsKey;
|
||||
_locationsKey = locationsKey;
|
||||
_trustedPeersKey = trustedPeersKey;
|
||||
_recentStickersKeyOld = recentStickersKeyOld;
|
||||
@@ -540,6 +552,9 @@ Account::ReadMapResult Account::readMapWith(
|
||||
_mapChanged = false;
|
||||
}
|
||||
|
||||
if (_prefsKey) {
|
||||
readPrefs();
|
||||
}
|
||||
if (_locationsKey) {
|
||||
readLocations();
|
||||
}
|
||||
@@ -620,6 +635,7 @@ void Account::writeMap() {
|
||||
if (!self.isEmpty()) mapSize += sizeof(quint32) + Serialize::bytearraySize(self);
|
||||
if (!_draftsMap.empty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
|
||||
if (!_draftCursorsMap.empty()) mapSize += sizeof(quint32) * 2 + _draftCursorsMap.size() * sizeof(quint64) * 2;
|
||||
if (_prefsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_trustedPeersKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
@@ -665,6 +681,9 @@ void Account::writeMap() {
|
||||
mapData.stream << quint64(value) << SerializePeerId(key);
|
||||
}
|
||||
}
|
||||
if (_prefsKey) {
|
||||
mapData.stream << quint32(lskPrefs) << quint64(_prefsKey);
|
||||
}
|
||||
if (_locationsKey) {
|
||||
mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
|
||||
}
|
||||
@@ -750,7 +769,7 @@ void Account::reset() {
|
||||
_draftsNotReadMap.clear();
|
||||
_botStoragesMap.clear();
|
||||
_botStoragesNotReadMap.clear();
|
||||
_locationsKey = _trustedPeersKey = 0;
|
||||
_prefsKey = _locationsKey = _trustedPeersKey = 0;
|
||||
_recentStickersKeyOld = 0;
|
||||
_installedStickersKey = 0;
|
||||
_featuredStickersKey = 0;
|
||||
@@ -3657,4 +3676,118 @@ Webview::StorageId TonSiteStorageId() {
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::optional<bool> Account::readPrefImpl<bool>(std::string_view key) {
|
||||
if (const auto data = readPrefGeneric(key)) {
|
||||
return !data->isEmpty();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <>
|
||||
void Account::writePrefImpl<bool>(std::string_view key, bool value) {
|
||||
writePrefGeneric(key, value ? "\x1"_q : QByteArray());
|
||||
}
|
||||
|
||||
void Account::clearPref(std::string_view key) {
|
||||
const auto i = _prefs.find(QByteArray(key.data(), key.size()));
|
||||
if (i == end(_prefs)) {
|
||||
return;
|
||||
}
|
||||
_prefs.erase(i);
|
||||
writePrefsDelayed();
|
||||
}
|
||||
|
||||
void Account::writePrefGeneric(
|
||||
std::string_view key,
|
||||
const QByteArray &value) {
|
||||
const auto raw = QByteArray(key.data(), key.size());
|
||||
if (const auto i = _prefs.find(raw); i != end(_prefs)) {
|
||||
if (i->second == value) {
|
||||
return;
|
||||
}
|
||||
i->second = value;
|
||||
} else {
|
||||
_prefs.emplace(raw, value);
|
||||
}
|
||||
writePrefsDelayed();
|
||||
}
|
||||
|
||||
std::optional<QByteArray> Account::readPrefGeneric(std::string_view key) {
|
||||
const auto i = _prefs.find(QByteArray(key.data(), key.size()));
|
||||
return (i != end(_prefs)) ? i->second : std::optional<QByteArray>();
|
||||
}
|
||||
|
||||
void Account::writePrefsDelayed() {
|
||||
_prefsChanged = true;
|
||||
_writePrefsTimer.callOnce(kDelayedWriteTimeout);
|
||||
}
|
||||
|
||||
void Account::writePrefs() {
|
||||
_writePrefsTimer.cancel();
|
||||
if (!_prefsChanged) {
|
||||
return;
|
||||
}
|
||||
_prefsChanged = false;
|
||||
|
||||
if (_prefs.empty()) {
|
||||
if (_prefsKey) {
|
||||
ClearKey(_prefsKey, _basePath);
|
||||
_prefsKey = 0;
|
||||
writeMapDelayed();
|
||||
}
|
||||
} else {
|
||||
if (!_prefsKey) {
|
||||
_prefsKey = GenerateKey(_basePath);
|
||||
writeMapQueued();
|
||||
}
|
||||
quint32 size = sizeof(quint32);
|
||||
for (const auto &[key, value] : _prefs) {
|
||||
size += 2 * sizeof(quint32) + key.size() + value.size();
|
||||
}
|
||||
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << quint32(_prefs.size());
|
||||
for (const auto &[key, value] : _prefs) {
|
||||
data.stream << quint32(key.size()) << quint32(value.size());
|
||||
data.stream.writeRawData(key.constData(), key.size());
|
||||
data.stream.writeRawData(value.constData(), value.size());
|
||||
}
|
||||
|
||||
FileWriteDescriptor file(_prefsKey, _basePath);
|
||||
file.writeEncrypted(data, _localKey);
|
||||
}
|
||||
}
|
||||
|
||||
void Account::readPrefs() {
|
||||
FileReadDescriptor prefs;
|
||||
if (!ReadEncryptedFile(prefs, _prefsKey, _basePath, _localKey)) {
|
||||
ClearKey(_prefsKey, _basePath);
|
||||
_prefsKey = 0;
|
||||
writeMapDelayed();
|
||||
return;
|
||||
}
|
||||
|
||||
auto count = quint32();
|
||||
prefs.stream >> count;
|
||||
if (prefs.stream.status() != QDataStream::Ok) {
|
||||
return;
|
||||
}
|
||||
auto map = base::flat_map<QByteArray, QByteArray>();
|
||||
map.reserve(count);
|
||||
for (auto i = quint32(); i != count; ++i) {
|
||||
auto keySize = quint32(), valueSize = quint32();
|
||||
prefs.stream >> keySize >> valueSize;
|
||||
auto key = QByteArray(keySize, Qt::Uninitialized);
|
||||
auto value = QByteArray(valueSize, Qt::Uninitialized);
|
||||
prefs.stream.readRawData(key.data(), keySize);
|
||||
prefs.stream.readRawData(value.data(), valueSize);
|
||||
if (prefs.stream.status() != QDataStream::Ok) {
|
||||
return;
|
||||
}
|
||||
map.emplace(std::move(key), std::move(value));
|
||||
}
|
||||
_prefs = std::move(map);
|
||||
}
|
||||
|
||||
} // namespace Storage
|
||||
|
||||
@@ -182,6 +182,19 @@ public:
|
||||
[[nodiscard]] bool hasPeerTrustedPayForMessageEntry(PeerId peerId) const;
|
||||
void clearPeerTrustedPayForMessage(PeerId peerId);
|
||||
|
||||
template <typename Type, typename Other>
|
||||
void writePref(std::string_view key, Other &&value) {
|
||||
writePrefImpl<Type>(key, std::forward<Other>(value));
|
||||
}
|
||||
void clearPref(std::string_view key);
|
||||
|
||||
template <typename Type, typename Other = Type>
|
||||
[[nodiscard]] Type readPref(
|
||||
std::string_view key,
|
||||
Other &&fallback = Type()) {
|
||||
return readPrefImpl<Type>(key).value_or(std::forward<Other>(fallback));
|
||||
}
|
||||
|
||||
void enforceModernStorageIdBots();
|
||||
[[nodiscard]] Webview::StorageId resolveStorageIdBots();
|
||||
[[nodiscard]] Webview::StorageId resolveStorageIdOther();
|
||||
@@ -238,6 +251,10 @@ private:
|
||||
void writeLocationsQueued();
|
||||
void writeLocationsDelayed();
|
||||
|
||||
void readPrefs();
|
||||
void writePrefs();
|
||||
void writePrefsDelayed();
|
||||
|
||||
std::unique_ptr<Main::SessionSettings> readSessionSettings();
|
||||
void writeSessionSettings(Main::SessionSettings *stored);
|
||||
|
||||
@@ -282,6 +299,16 @@ private:
|
||||
Fn<RecentHashtagPack()> getPack,
|
||||
const QString &text);
|
||||
|
||||
template <typename Type>
|
||||
void writePrefImpl(std::string_view key, Type value);
|
||||
|
||||
template <typename Type>
|
||||
[[nodiscard]] std::optional<Type> readPrefImpl(std::string_view key);
|
||||
|
||||
void writePrefGeneric(std::string_view key, const QByteArray &value);
|
||||
[[nodiscard]] std::optional<QByteArray> readPrefGeneric(
|
||||
std::string_view key);
|
||||
|
||||
const not_null<Main::Account*> _owner;
|
||||
const QString _dataName;
|
||||
const FileKey _dataNameKey = 0;
|
||||
@@ -307,6 +334,7 @@ private:
|
||||
QByteArray _downloadsSerialized;
|
||||
Fn<std::optional<QByteArray>()> _downloadsSerialize;
|
||||
|
||||
FileKey _prefsKey = 0;
|
||||
FileKey _locationsKey = 0;
|
||||
FileKey _trustedPeersKey = 0;
|
||||
FileKey _installedStickersKey = 0;
|
||||
@@ -351,12 +379,16 @@ private:
|
||||
Webview::StorageId _webviewStorageIdBots;
|
||||
Webview::StorageId _webviewStorageIdOther;
|
||||
|
||||
base::flat_map<QByteArray, QByteArray> _prefs;
|
||||
|
||||
int _oldMapVersion = 0;
|
||||
|
||||
base::Timer _writeMapTimer;
|
||||
base::Timer _writePrefsTimer;
|
||||
base::Timer _writeLocationsTimer;
|
||||
base::Timer _writeSearchSuggestionsTimer;
|
||||
bool _mapChanged = false;
|
||||
bool _prefsChanged = false;
|
||||
bool _locationsChanged = false;
|
||||
|
||||
QImage _roundPlaceholder;
|
||||
|
||||
Reference in New Issue
Block a user