diff --git a/Telegram/SourceFiles/boxes/local_storage_box.cpp b/Telegram/SourceFiles/boxes/local_storage_box.cpp index ca621bda19..476a2d1650 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.cpp +++ b/Telegram/SourceFiles/boxes/local_storage_box.cpp @@ -37,29 +37,14 @@ void LocalStorageBox::prepare() { } void LocalStorageBox::updateControls() { - auto rowsHeight = 0; - if (_imagesCount > 0 && _audiosCount > 0) { - rowsHeight = 2 * (st::linkFont->height + st::localStorageBoxSkip); - } else { - rowsHeight = st::linkFont->height + st::localStorageBoxSkip; - } - _clear->setVisible(_imagesCount > 0 || _audiosCount > 0); + const auto rowsHeight = st::linkFont->height + st::localStorageBoxSkip; + _clear->setVisible(false); setDimensions(st::boxWidth, st::localStorageBoxSkip + rowsHeight + _clear->height()); _clear->moveToLeft(st::boxPadding.left(), st::localStorageBoxSkip + rowsHeight); update(); } void LocalStorageBox::checkLocalStoredCounts() { - int imagesCount = Local::hasImages() + Local::hasStickers() + Local::hasWebFiles(); - int audiosCount = Local::hasAudios(); - if (imagesCount != _imagesCount || audiosCount != _audiosCount) { - _imagesCount = imagesCount; - _audiosCount = audiosCount; - if (_imagesCount > 0 || _audiosCount > 0) { - _state = State::Normal; - } - updateControls(); - } } void LocalStorageBox::paintEvent(QPaintEvent *e) { @@ -71,19 +56,8 @@ void LocalStorageBox::paintEvent(QPaintEvent *e) { p.setPen(st::windowFg); checkLocalStoredCounts(); auto top = st::localStorageBoxSkip; - if (_imagesCount > 0) { - auto text = lng_settings_images_cached(lt_count, _imagesCount, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize() + Local::storageWebFilesSize())); - p.drawTextLeft(st::boxPadding.left(), top, width(), text); - top += st::boxTextFont->height + st::localStorageBoxSkip; - } - if (_audiosCount > 0) { - auto text = lng_settings_audios_cached(lt_count, _audiosCount, lt_size, formatSizeText(Local::storageAudiosSize())); - p.drawTextLeft(st::boxPadding.left(), top, width(), text); - top += st::boxTextFont->height + st::localStorageBoxSkip; - } else if (_imagesCount <= 0) { - p.drawTextLeft(st::boxPadding.left(), top, width(), lang(lng_settings_no_data_cached)); - top += st::boxTextFont->height + st::localStorageBoxSkip; - } + p.drawTextLeft(st::boxPadding.left(), top, width(), lang(lng_settings_no_data_cached)); + top += st::boxTextFont->height + st::localStorageBoxSkip; auto text = ([this]() -> QString { switch (_state) { case State::Clearing: return lang(lng_local_storage_clearing); diff --git a/Telegram/SourceFiles/boxes/local_storage_box.h b/Telegram/SourceFiles/boxes/local_storage_box.h index ca6679f14d..0bd6c3b292 100644 --- a/Telegram/SourceFiles/boxes/local_storage_box.h +++ b/Telegram/SourceFiles/boxes/local_storage_box.h @@ -43,7 +43,4 @@ private: object_ptr _clear; - int _imagesCount = -1; - int _audiosCount = -1; - }; diff --git a/Telegram/SourceFiles/core/launcher.cpp b/Telegram/SourceFiles/core/launcher.cpp index 794061f8a4..d4bdadc171 100644 --- a/Telegram/SourceFiles/core/launcher.cpp +++ b/Telegram/SourceFiles/core/launcher.cpp @@ -221,7 +221,8 @@ void Launcher::processArguments() { gTestMode = parseResult.contains("-testmode"); Logs::SetDebugEnabled(parseResult.contains("-debug")); gManyInstance = parseResult.contains("-many"); - gKeyFile = parseResult.value("-key", QStringList()).join(QString()); + gKeyFile = parseResult.value("-key", {}).join(QString()).toLower(); + gKeyFile = gKeyFile.replace(QRegularExpression("[^a-z0-9\\-_]"), {}); gLaunchMode = parseResult.contains("-autostart") ? LaunchModeAutoStart : parseResult.contains("-fixprevious") ? LaunchModeFixPrevious : parseResult.contains("-cleanup") ? LaunchModeCleanup @@ -229,8 +230,8 @@ void Launcher::processArguments() { gNoStartUpdate = parseResult.contains("-noupdate"); gStartToSettings = parseResult.contains("-tosettings"); gStartInTray = parseResult.contains("-startintray"); - gSendPaths = parseResult.value("-sendpath", QStringList()); - gWorkingDir = parseResult.value("-workdir", QStringList()).join(QString()); + gSendPaths = parseResult.value("-sendpath", {}); + gWorkingDir = parseResult.value("-workdir", {}).join(QString()); if (!gWorkingDir.isEmpty()) { if (QDir().exists(gWorkingDir)) { _customWorkingDir = true; @@ -238,7 +239,7 @@ void Launcher::processArguments() { gWorkingDir = QString(); } } - gStartUrl = parseResult.value("--", QStringList()).join(QString()); + gStartUrl = parseResult.value("--", {}).join(QString()); } int Launcher::executeApplication() { diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 8f678cfa3b..ab59eaeecd 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/history_media_types.h" #include "window/window_controller.h" +#include "storage/cache/storage_cache_database.h" #include "auth_session.h" #include "mainwindow.h" #include "messenger.h" @@ -1087,6 +1088,16 @@ MediaKey DocumentData::mediaKey() const { return ::mediaKey(locationType(), _dc, id); } +Storage::Cache::Key DocumentData::cacheKey() const { + if (hasWebLocation()) { + return Data::WebDocumentCacheKey(_urlLocation); + } else if (!_access && !_url.isEmpty()) { + return Data::UrlCacheKey(_url); + } else { + return Data::DocumentCacheKey(_dc, id); + } +} + QString DocumentData::composeNameString() const { if (auto songData = song()) { return ComposeNameString( @@ -1207,17 +1218,9 @@ void DocumentData::setWebLocation(const WebFileLocation &location) { void DocumentData::collectLocalData(DocumentData *local) { if (local == this) return; + _session->data().cache().copyIfEmpty(local->cacheKey(), cacheKey()); if (!local->_data.isEmpty()) { _data = local->_data; - if (isVoiceMessage()) { - if (!Local::copyAudio(local->mediaKey(), mediaKey())) { - Local::writeAudio(mediaKey(), _data); - } - } else { - if (!Local::copyStickerImage(local->mediaKey(), mediaKey())) { - Local::writeStickerImage(mediaKey(), _data); - } - } } if (!local->_location.isEmpty()) { _location = local->_location; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 3495078592..1286f38c1b 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -9,6 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_types.h" +namespace Storage { +namespace Cache { +struct Key; +} // namespace Cache +} // namespace Storage + class AuthSession; class mtpFileLoader; @@ -173,6 +179,7 @@ public: void setMimeString(const QString &mime); MediaKey mediaKey() const; + Storage::Cache::Key cacheKey() const; static QString ComposeNameString( const QString &filename, diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 14296ee8ad..43a62fdbe6 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -312,22 +312,20 @@ bool MediaPhoto::updateInlineResultMedia(const MTPMessageMedia &media) { if (media.type() != mtpc_messageMediaPhoto) { return false; } - auto &photo = media.c_messageMediaPhoto(); - if (photo.has_photo() && !photo.has_ttl_seconds()) { - if (auto existing = Auth().data().photo(photo.vphoto)) { - if (existing == _photo) { - return true; - } else { - // collect data - } + auto &data = media.c_messageMediaPhoto(); + if (data.has_photo() && !data.has_ttl_seconds()) { + const auto photo = Auth().data().photo(data.vphoto); + if (photo == _photo) { + return true; + } else { + photo->collectLocalData(_photo); } } else { LOG(("API Error: " "Got MTPMessageMediaPhoto without photo " "or with ttl_seconds in updateInlineResultMedia()")); } - // Can return false if we collect the data. - return true; + return false; } bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) { @@ -347,6 +345,20 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) { if (photo.type() != mtpc_photo) { return false; } + const auto saveImageToCache = []( + const MTPDfileLocation &location, + const ImagePtr &image) { + const auto key = StorageImageLocation(0, 0, location); + if (key.isNull() || image->isNull() || !image->loaded()) { + return; + } + if (image->savedData().isEmpty()) { + image->forget(); + } + Auth().data().cache().putIfEmpty( + Data::StorageCacheKey(key), + image->savedData()); + }; auto &sizes = photo.c_photo().vsizes.v; auto max = 0; const MTPDfileLocation *maxLocation = 0; @@ -369,23 +381,24 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) { if (!loc || loc->type() != mtpc_fileLocation) { continue; } + const auto &location = loc->c_fileLocation(); if (size == 's') { - Local::writeImage(storageKey(loc->c_fileLocation()), _photo->thumb); + saveImageToCache(location, _photo->thumb); } else if (size == 'm') { - Local::writeImage(storageKey(loc->c_fileLocation()), _photo->medium); + saveImageToCache(location, _photo->medium); } else if (size == 'x' && max < 1) { max = 1; - maxLocation = &loc->c_fileLocation(); + maxLocation = &location; } else if (size == 'y' && max < 2) { max = 2; - maxLocation = &loc->c_fileLocation(); + maxLocation = &location; //} else if (size == 'w' && max < 3) { // max = 3; // maxLocation = &loc->c_fileLocation(); } } if (maxLocation) { - Local::writeImage(storageKey(*maxLocation), _photo->full); + saveImageToCache(*maxLocation, _photo->full); } return true; } @@ -637,13 +650,6 @@ bool MediaFile::updateSentMedia(const MTPMessageMedia &media) { return false; } Auth().data().documentConvert(_document, data.vdocument); - if (!_document->data().isEmpty()) { - if (_document->isVoiceMessage()) { - Local::writeAudio(_document->mediaKey(), _document->data()); - } else { - Local::writeStickerImage(_document->mediaKey(), _document->data()); - } - } return true; } diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index b0da46ed0e..daae1656b9 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -111,13 +111,29 @@ void PhotoData::forget() { ImagePtr PhotoData::makeReplyPreview(Data::FileOrigin origin) { if (replyPreview->isNull() && !thumb->isNull()) { - if (thumb->loaded()) { - int w = thumb->width(), h = thumb->height(); + const auto previewFromImage = [&](const ImagePtr &image) { + if (!image->loaded()) { + image->load(origin); + return ImagePtr(); + } + int w = image->width(), h = image->height(); if (w <= 0) w = 1; if (h <= 0) h = 1; - replyPreview = ImagePtr(w > h ? thumb->pix(origin, w * st::msgReplyBarSize.height() / h, st::msgReplyBarSize.height()) : thumb->pix(origin, st::msgReplyBarSize.height()), "PNG"); + return ImagePtr( + (w > h + ? image->pix( + origin, + w * st::msgReplyBarSize.height() / h, + st::msgReplyBarSize.height()) + : image->pix(origin, st::msgReplyBarSize.height())), + "PNG"); + }; + if (thumb->toDelayedStorageImage() + && !full->isNull() + && !full->toDelayedStorageImage()) { + return previewFromImage(full); } else { - thumb->load(origin); + return previewFromImage(thumb); } } return replyPreview; @@ -130,6 +146,21 @@ MTPInputPhoto PhotoData::mtpInput() const { MTP_bytes(fileReference)); } +void PhotoData::collectLocalData(PhotoData *local) { + if (local == this) return; + + const auto copyImage = [](const ImagePtr &src, const ImagePtr &dst) { + if (const auto from = src->cacheKey()) { + if (const auto to = dst->cacheKey()) { + Auth().data().cache().copyIfEmpty(*from, *to); + } + } + }; + copyImage(local->thumb, thumb); + copyImage(local->medium, medium); + copyImage(local->full, full); +} + void PhotoOpenClickHandler::onClickImpl() const { Messenger::Instance().showPhoto(this); } diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index 79768413db..64dcafd19f 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -43,6 +43,12 @@ public: MTPInputPhoto mtpInput() const; + // When we have some client-side generated photo + // (for example for displaying an external inline bot result) + // and it has downloaded full image, we can collect image from it + // to (this) received from the server "same" photo. + void collectLocalData(PhotoData *local); + PhotoId id = 0; uint64 access = 0; QByteArray fileReference; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 8a2d6ce3ff..d3ad605b06 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_element.h" #include "inline_bots/inline_bot_layout_item.h" #include "storage/localstorage.h" +#include "storage/storage_encrypted_file.h" #include "boxes/abstract_box.h" #include "passport/passport_form_controller.h" #include "data/data_media_types.h" @@ -66,12 +67,19 @@ void UpdateImage(ImagePtr &old, ImagePtr now) { Session::Session(not_null session) : _session(session) +, _cache(Local::cachePath(), Local::cacheSettings()) , _groups(this) , _unmuteByFinishedTimer([=] { unmuteByFinished(); }) { + _cache.open(Local::cacheKey()); + setupContactViewsViewer(); setupChannelLeavingViewer(); } +Storage::Cache::Database &Session::cache() { + return _cache; +} + void Session::startExport(PeerData *peer) { startExport(peer ? peer->input : MTP_inputPeerEmpty()); } @@ -1061,6 +1069,7 @@ void Session::documentConvert( Unexpected("Type in Session::documentConvert()."); }(); const auto oldKey = original->mediaKey(); + const auto oldCacheKey = original->cacheKey(); const auto idChanged = (original->id != id); const auto sentSticker = idChanged && (original->sticker() != nullptr); if (idChanged) { @@ -1083,14 +1092,7 @@ void Session::documentConvert( } documentApplyFields(original, data); if (idChanged) { - const auto newKey = original->mediaKey(); - if (oldKey != newKey) { - if (original->isVoiceMessage()) { - Local::copyAudio(oldKey, newKey); - } else if (original->sticker() || original->isAnimation()) { - Local::copyStickerImage(oldKey, newKey); - } - } + cache().moveIfEmpty(oldCacheKey, original->cacheKey()); if (savedGifs().indexOf(original) >= 0) { Local::writeSavedGifs(); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 1f33ef83e7..4c1991d567 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "storage/cache/storage_cache_database.h" #include "chat_helpers/stickers.h" #include "dialogs/dialogs_key.h" #include "data/data_groups.h" @@ -71,6 +72,8 @@ public: TimeMs rememberFor); void forgetPassportCredentials(); + Storage::Cache::Database &cache(); + [[nodiscard]] base::Variable &contactsLoaded() { return _contactsLoaded; } @@ -520,6 +523,8 @@ private: not_null _session; + Storage::Cache::Database _cache; + std::unique_ptr _export; std::unique_ptr _exportPanel; rpl::event_stream _exportViewChanges; diff --git a/Telegram/SourceFiles/data/data_types.cpp b/Telegram/SourceFiles/data/data_types.cpp index 3e71bc1cc5..204d99cfb9 100644 --- a/Telegram/SourceFiles/data/data_types.cpp +++ b/Telegram/SourceFiles/data/data_types.cpp @@ -9,6 +9,72 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document.h" #include "ui/widgets/input_fields.h" +#include "storage/cache/storage_cache_types.h" +#include "base/openssl_help.h" + +namespace Data { +namespace { + +constexpr auto kDocumentCacheTag = 0x0000000000000100ULL; +constexpr auto kDocumentCacheMask = 0x00000000000000FFULL; +constexpr auto kStorageCacheTag = 0x0000010000000000ULL; +constexpr auto kStorageCacheMask = 0x000000FFFFFFFFFFULL; +constexpr auto kWebDocumentCacheTag = 0x0000020000000000ULL; +constexpr auto kWebDocumentCacheMask = 0x000000FFFFFFFFFFULL; +constexpr auto kUrlCacheTag = 0x0000030000000000ULL; +constexpr auto kUrlCacheMask = 0x000000FFFFFFFFFFULL; + +} // namespace + +Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) { + return Storage::Cache::Key{ + Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask), + id + }; +} + +Storage::Cache::Key StorageCacheKey(const StorageImageLocation &location) { + const auto dcId = uint64(location.dc()) & 0xFFULL; + return Storage::Cache::Key{ + Data::kStorageCacheTag | (dcId << 32) | uint32(location.local()), + location.volume() + }; +} + +Storage::Cache::Key WebDocumentCacheKey(const WebFileLocation &location) { + const auto dcId = uint64(location.dc()) & 0xFFULL; + const auto url = location.url(); + const auto hash = openssl::Sha256(bytes::make_span(url)); + const auto bytes = bytes::make_span(hash); + const auto bytes1 = bytes.subspan(0, sizeof(uint32)); + const auto bytes2 = bytes.subspan(sizeof(uint32), sizeof(uint64)); + const auto part1 = *reinterpret_cast(bytes1.data()); + const auto part2 = *reinterpret_cast(bytes2.data()); + return Storage::Cache::Key{ + Data::kWebDocumentCacheTag | (dcId << 32) | part1, + part2 + }; +} + +Storage::Cache::Key UrlCacheKey(const QString &location) { + const auto url = location.toUtf8(); + const auto hash = openssl::Sha256(bytes::make_span(url)); + const auto bytes = bytes::make_span(hash); + const auto bytes1 = bytes.subspan(0, sizeof(uint32)); + const auto bytes2 = bytes.subspan(sizeof(uint32), sizeof(uint64)); + const auto bytes3 = bytes.subspan( + sizeof(uint32) + sizeof(uint64), + sizeof(uint16)); + const auto part1 = *reinterpret_cast(bytes1.data()); + const auto part2 = *reinterpret_cast(bytes2.data()); + const auto part3 = *reinterpret_cast(bytes3.data()); + return Storage::Cache::Key{ + Data::kUrlCacheTag | (uint64(part3) << 32) | part1, + part2 + }; +} + +} // namespace Data void AudioMsgId::setTypeFromAudio() { if (_audio->isVoiceMessage() || _audio->isVideoMessage()) { diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index 4e5f4769d6..f4f4b54933 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -10,6 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/value_ordering.h" #include "ui/text/text.h" // For QFIXED_MAX +namespace Storage { +namespace Cache { +struct Key; +} // namespace Cache +} // namespace Storage + class HistoryItem; using HistoryItemsList = std::vector>; @@ -17,6 +23,9 @@ namespace Ui { class InputField; } // namespace Ui +class StorageImageLocation; +class WebFileLocation; + namespace Data { struct UploadState { @@ -27,6 +36,11 @@ struct UploadState { bool waitingForAlbum = false; }; +Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id); +Storage::Cache::Key StorageCacheKey(const StorageImageLocation &location); +Storage::Cache::Key WebDocumentCacheKey(const WebFileLocation &location); +Storage::Cache::Key UrlCacheKey(const QString &location); + } // namespace Data struct MessageGroupId { diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index 87394c3e42..f7cec2a12b 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -4320,7 +4320,14 @@ HistoryInvoice::HistoryInvoice( } void HistoryInvoice::fillFromData(not_null invoice) { - // init attach + if (invoice->photo) { + _attach = std::make_unique( + _parent, + _parent->data(), + invoice->photo); + } else { + _attach = nullptr; + } auto labelText = [&] { if (invoice->receiptMsgId) { if (invoice->isTest) { diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 1ea33da01b..8c1fcbe92b 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -794,7 +794,7 @@ MainWindow::TempDirState MainWindow::localStorageState() { if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) { return TempDirRemoving; } - return (Local::hasImages() || Local::hasStickers() || Local::hasWebFiles() || Local::hasAudios()) ? TempDirExists : TempDirEmpty; + return TempDirEmpty; } void MainWindow::tempDirDelete(int task) { diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 0da5a7ca09..d90cf6e64a 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -1226,6 +1226,10 @@ void Messenger::loggedOut() { w->setupIntro(); } App::histories().clear(); + if (const auto session = authSession()) { + session->data().cache().close(); + session->data().cache().clear(); + } authSessionDestroy(); if (_mediaView) { hideMediaView(); diff --git a/Telegram/SourceFiles/mtproto/auth_key.h b/Telegram/SourceFiles/mtproto/auth_key.h index dcc84291b0..cf8f7169e8 100644 --- a/Telegram/SourceFiles/mtproto/auth_key.h +++ b/Telegram/SourceFiles/mtproto/auth_key.h @@ -56,6 +56,9 @@ public: void write(QDataStream &to) const { to.writeRawData(reinterpret_cast(_key.data()), _key.size()); } + bytes::const_span data() const { + return _key; + } bool equals(const std::shared_ptr &other) const { return other ? (_key == other->_key) : false; diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 0f4f06ce47..795f3309fe 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -863,7 +863,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con bool selected = (selection == FullSelection); _data->automaticLoad(parent()->fullId(), parent()); - bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()), displayLoading = _data->displayLoading(); + bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); if (displayLoading) { ensureRadial(); @@ -1024,8 +1024,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con TextState Document::getState( QPoint point, StateRequest request) const { - const auto loaded = _data->loaded() - || Local::willStickerImageLoad(_data->mediaKey()); + const auto loaded = _data->loaded(); const auto wthumb = withThumb(); if (_data->isAudioFile()) { diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index d1e2c27c98..91937d2d4d 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -2338,16 +2338,12 @@ void FormController::fillDownloadedFile( if (!i->uploadData) { return; } - Local::writeImage( - StorageKey( - storageMix32To64( - SecureFileLocation, - destination.dcId), - destination.id), - StorageImageSaved(QByteArray::fromRawData( - reinterpret_cast( - i->uploadData->bytes.data()), - i->uploadData->bytes.size()))); + const auto &bytes = i->uploadData->bytes; + Auth().data().cache().put( + Data::DocumentCacheKey(destination.dcId, destination.id), + QByteArray( + reinterpret_cast(bytes.data()), + bytes.size())); } auto FormController::parseValue( diff --git a/Telegram/SourceFiles/storage/cache/storage_cache_database.cpp b/Telegram/SourceFiles/storage/cache/storage_cache_database.cpp index c0f33e012b..33324da10d 100644 --- a/Telegram/SourceFiles/storage/cache/storage_cache_database.cpp +++ b/Telegram/SourceFiles/storage/cache/storage_cache_database.cpp @@ -64,20 +64,20 @@ void Database::remove(const Key &key, FnMut done) { }); } -void Database::copy( - const Key &from, - const Key &to, +void Database::putIfEmpty( + const Key &key, + QByteArray value, FnMut done) { _wrapped.with([ - from, - to, + key, + value = std::move(value), done = std::move(done) ](Implementation &unwrapped) mutable { - unwrapped.copy(from, to, std::move(done)); + unwrapped.putIfEmpty(key, std::move(value), std::move(done)); }); } -void Database::move( +void Database::copyIfEmpty( const Key &from, const Key &to, FnMut done) { @@ -86,7 +86,20 @@ void Database::move( to, done = std::move(done) ](Implementation &unwrapped) mutable { - unwrapped.move(from, to, std::move(done)); + unwrapped.copyIfEmpty(from, to, std::move(done)); + }); +} + +void Database::moveIfEmpty( + const Key &from, + const Key &to, + FnMut done) { + _wrapped.with([ + from, + to, + done = std::move(done) + ](Implementation &unwrapped) mutable { + unwrapped.moveIfEmpty(from, to, std::move(done)); }); } diff --git a/Telegram/SourceFiles/storage/cache/storage_cache_database.h b/Telegram/SourceFiles/storage/cache/storage_cache_database.h index eb4bd4d440..62a5258cd9 100644 --- a/Telegram/SourceFiles/storage/cache/storage_cache_database.h +++ b/Telegram/SourceFiles/storage/cache/storage_cache_database.h @@ -35,11 +35,15 @@ public: void get(const Key &key, FnMut done); void remove(const Key &key, FnMut done = nullptr); - void copy( + void putIfEmpty( + const Key &key, + QByteArray value, + FnMut done = nullptr); + void copyIfEmpty( const Key &from, const Key &to, FnMut done = nullptr); - void move( + void moveIfEmpty( const Key &from, const Key &to, FnMut done = nullptr); diff --git a/Telegram/SourceFiles/storage/cache/storage_cache_database_object.cpp b/Telegram/SourceFiles/storage/cache/storage_cache_database_object.cpp index 830cb0dbd0..1a218f2985 100644 --- a/Telegram/SourceFiles/storage/cache/storage_cache_database_object.cpp +++ b/Telegram/SourceFiles/storage/cache/storage_cache_database_object.cpp @@ -622,9 +622,7 @@ void DatabaseObject::put( QByteArray value, FnMut done) { if (value.isEmpty()) { - remove(key, [done = std::move(done)](Error error) mutable { - done(error); - }); + remove(key, std::move(done)); return; } _removing.erase(key); @@ -645,10 +643,12 @@ void DatabaseObject::put( const auto result = data.open(path, File::Mode::Write, _key); switch (result) { case File::Result::Failed: + remove(key, nullptr); invokeCallback(done, ioError(path)); break; case File::Result::LockFailed: + remove(key, nullptr); invokeCallback(done, Error{ Error::Type::LockFailed, path }); break; @@ -800,8 +800,10 @@ void DatabaseObject::get(const Key &key, FnMut done) { auto result = readValueData(entry.place, entry.size); if (result.isEmpty()) { + remove(key, nullptr); invokeCallback(done, QByteArray()); } else if (CountChecksum(bytes::make_span(result)) != entry.checksum) { + remove(key, nullptr); invokeCallback(done, QByteArray()); } else { invokeCallback(done, std::move(result)); @@ -856,22 +858,41 @@ void DatabaseObject::remove(const Key &key, FnMut done) { } } -void DatabaseObject::copy( +void DatabaseObject::putIfEmpty( + const Key &key, + QByteArray value, + FnMut done) { + if (_map.find(key) != end(_map)) { + invokeCallback(done, Error::NoError()); + return; + } + put(key, std::move(value), std::move(done)); +} + +void DatabaseObject::copyIfEmpty( const Key &from, const Key &to, FnMut done) { + if (_map.find(to) != end(_map)) { + invokeCallback(done, Error::NoError()); + return; + } get(from, [&](QByteArray value) { put(to, value, std::move(done)); }); } -void DatabaseObject::move( +void DatabaseObject::moveIfEmpty( const Key &from, const Key &to, FnMut done) { + if (_map.find(to) != end(_map)) { + invokeCallback(done, Error::NoError()); + return; + } const auto i = _map.find(from); if (i == _map.end()) { - put(to, QByteArray(), std::move(done)); + invokeCallback(done, Error::NoError()); return; } _removing.emplace(from); diff --git a/Telegram/SourceFiles/storage/cache/storage_cache_database_object.h b/Telegram/SourceFiles/storage/cache/storage_cache_database_object.h index 7792f34de0..0bfe9dbe2c 100644 --- a/Telegram/SourceFiles/storage/cache/storage_cache_database_object.h +++ b/Telegram/SourceFiles/storage/cache/storage_cache_database_object.h @@ -37,8 +37,18 @@ public: void get(const Key &key, FnMut done); void remove(const Key &key, FnMut done); - void copy(const Key &from, const Key &to, FnMut done); - void move(const Key &from, const Key &to, FnMut done); + void putIfEmpty( + const Key &key, + QByteArray value, + FnMut done); + void copyIfEmpty( + const Key &from, + const Key &to, + FnMut done); + void moveIfEmpty( + const Key &from, + const Key &to, + FnMut done); void clear(FnMut done); diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 8378aa7a55..95828fb525 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/file_download.h" #include "data/data_document.h" +#include "data/data_session.h" #include "mainwidget.h" #include "mainwindow.h" #include "messenger.h" @@ -36,6 +37,7 @@ void Downloader::clearPriorities() { void Downloader::requestedAmountIncrement(MTP::DcId dcId, int index, int amount) { Expects(index >= 0 && index < MTP::kDownloadSessionsCount); + auto it = _requestedBytesAmount.find(dcId); if (it == _requestedBytesAmount.cend()) { it = _requestedBytesAmount.emplace(dcId, RequestedInDc { { 0 } }).first; @@ -206,16 +208,16 @@ void FileLoader::pause() { } FileLoader::~FileLoader() { - if (_localTaskId) { - Local::cancelTask(_localTaskId); - } removeFromQueue(); } -void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &imageFormat, const QPixmap &imagePixmap) { - _localTaskId = 0; +void FileLoader::localLoaded( + const StorageImageSaved &result, + const QByteArray &imageFormat, + const QPixmap &imagePixmap) { + _localLoading.kill(); if (result.data.isEmpty()) { - _localStatus = LocalFailed; + _localStatus = LocalStatus::NotFound; start(true); return; } @@ -224,7 +226,7 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray & _imageFormat = imageFormat; _imagePixmap = imagePixmap; } - _localStatus = LocalLoaded; + _localStatus = LocalStatus::Loaded; if (!_filename.isEmpty() && _toCache == LoadToCacheAsWell) { if (!_fileIsOpen) _fileIsOpen = _file.open(QIODevice::WriteOnly); if (!_fileIsOpen) { @@ -241,7 +243,8 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray & if (_fileIsOpen) { _file.close(); _fileIsOpen = false; - Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath()); + Platform::File::PostprocessDownloaded( + QFileInfo(_file).absoluteFilePath()); } _downloader->taskFinished().notify(); @@ -254,9 +257,9 @@ void FileLoader::start(bool loadFirst, bool prior) { if (_paused) { _paused = false; } - if (_finished || tryLoadLocal()) return; - - if (_fromCloud == LoadFromLocalOnly) { + if (_finished || tryLoadLocal()) { + return; + } else if (_fromCloud == LoadFromLocalOnly) { cancel(); return; } @@ -357,6 +360,74 @@ void FileLoader::start(bool loadFirst, bool prior) { return startLoading(loadFirst, prior); } +void FileLoader::loadLocal(const Storage::Cache::Key &key) { + const auto readImage = (_locationType != AudioFileLocation); + auto [first, second] = base::make_binary_guard(); + _localLoading = std::move(first); + auto done = [=, guard = std::move(second)]( + QByteArray value, + QImage image, + QByteArray format) mutable { + crl::on_main([ + =, + value = std::move(value), + image = std::move(image), + format = std::move(format), + guard = std::move(guard) + ]() mutable { + if (!guard.alive()) { + return; + } + localLoaded( + StorageImageSaved(std::move(value)), + format, + App::pixmapFromImageInPlace(std::move(image))); + }); + }; + Auth().data().cache().get(key, [=, callback = std::move(done)]( + QByteArray value) mutable { + if (readImage) { + crl::async([ + value = std::move(value), + done = std::move(callback) + ]() mutable { + auto format = QByteArray(); + auto image = App::readImage(value, &format, false); + if (!image.isNull()) { + done(value, image, format); + } else { + done(value, {}, {}); + } + }); + } else { + callback(value, {}, {}); + } + }); +} + +bool FileLoader::tryLoadLocal() { + if (_localStatus == LocalStatus::NotFound + || _localStatus == LocalStatus::Loaded) { + return false; + } else if (_localStatus == LocalStatus::Loading) { + return true; + } + + if (const auto key = cacheKey()) { + loadLocal(*key); + emit progress(this); + } + + if (_localStatus != LocalStatus::NotTried) { + return _finished; + } else if (_localLoading.alive()) { + _localStatus = LocalStatus::Loading; + return true; + } + _localStatus = LocalStatus::NotFound; + return false; +} + void FileLoader::cancel() { cancel(false); } @@ -872,29 +943,19 @@ bool mtpFileLoader::feedPart(int offset, bytes::const_span buffer) { } removeFromQueue(); - if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { - if (_urlLocation) { - Local::writeImage(storageKey(*_urlLocation), StorageImageSaved(_data)); - } else if (_locationType != UnknownFileLocation) { // audio, video, document - auto mkey = mediaKey(_locationType, _dcId, _id); - if (!_filename.isEmpty()) { - Local::writeFileLocation(mkey, FileLocation(_filename)); + if (_localStatus == LocalStatus::NotFound) { + if (_locationType != UnknownFileLocation + && !_filename.isEmpty()) { + Local::writeFileLocation( + mediaKey(_locationType, _dcId, _id), + FileLocation(_filename)); + } + if (_urlLocation + || _locationType == UnknownFileLocation + || _toCache == LoadToCacheAsWell) { + if (const auto key = cacheKey()) { + Auth().data().cache().put(*key, _data); } - if (_toCache == LoadToCacheAsWell) { - if (_locationType == DocumentFileLocation) { - Local::writeStickerImage(mkey, _data); - } else if (_locationType == AudioFileLocation) { - Local::writeAudio(mkey, _data); - } else if (_locationType == SecureFileLocation) { - Local::writeImage( - StorageKey( - storageMix32To64(_locationType, _dcId), - _id), - StorageImageSaved(_data)); - } - } - } else { - Local::writeImage(storageKey(*_location), StorageImageSaved(_data)); } } } @@ -1026,43 +1087,15 @@ void mtpFileLoader::changeCDNParams( makeRequest(offset); } -bool mtpFileLoader::tryLoadLocal() { - if (_localStatus == LocalNotFound || _localStatus == LocalLoaded || _localStatus == LocalFailed) { - return false; - } - if (_localStatus == LocalLoading) { - return true; - } - +base::optional mtpFileLoader::cacheKey() const { if (_urlLocation) { - _localTaskId = Local::startImageLoad(storageKey(*_urlLocation), this); + return Data::WebDocumentCacheKey(*_urlLocation); } else if (_location) { - _localTaskId = Local::startImageLoad(storageKey(*_location), this); - } else { - if (_toCache == LoadToCacheAsWell) { - MediaKey mkey = mediaKey(_locationType, _dcId, _id); - if (_locationType == DocumentFileLocation) { - _localTaskId = Local::startStickerImageLoad(mkey, this); - } else if (_locationType == AudioFileLocation) { - _localTaskId = Local::startAudioLoad(mkey, this); - } else if (_locationType == SecureFileLocation) { - _localTaskId = Local::startImageLoad(StorageKey( - storageMix32To64(_locationType, _dcId), - _id), this); - } - } + return Data::StorageCacheKey(*_location); + } else if (_toCache == LoadToCacheAsWell) { + return Data::DocumentCacheKey(_dcId, _id); } - - emit progress(this); - - if (_localStatus != LocalNotTried) { - return _finished; - } else if (_localTaskId) { - _localStatus = LocalLoading; - return true; - } - _localStatus = LocalNotFound; - return false; + return base::none; } mtpFileLoader::~mtpFileLoader() { @@ -1129,8 +1162,10 @@ void webFileLoader::onFinished(const QByteArray &data) { } removeFromQueue(); - if (_localStatus == LocalNotFound || _localStatus == LocalFailed) { - Local::writeWebFile(_url, _data); + if (_localStatus == LocalStatus::NotFound) { + if (const auto key = cacheKey()) { + Auth().data().cache().put(*key, _data); + } } _downloader->taskFinished().notify(); @@ -1143,23 +1178,8 @@ void webFileLoader::onError() { cancel(true); } -bool webFileLoader::tryLoadLocal() { - if (_localStatus == LocalNotFound || _localStatus == LocalLoaded || _localStatus == LocalFailed) { - return false; - } - if (_localStatus == LocalLoading) { - return true; - } - - _localTaskId = Local::startWebFileLoad(_url, this); - if (_localStatus != LocalNotTried) { - return _finished; - } else if (_localTaskId) { - _localStatus = LocalLoading; - return true; - } - _localStatus = LocalNotFound; - return false; +base::optional webFileLoader::cacheKey() const { + return Data::UrlCacheKey(_url); } void webFileLoader::cancelRequests() { diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index 7ef00e4c5d..94ac563d18 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -8,10 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "base/observer.h" -#include "storage/localimageloader.h" // for TaskId #include "data/data_file_origin.h" +#include "base/binary_guard.h" namespace Storage { +namespace Cache { +struct Key; +} // namespace Cache constexpr auto kMaxFileInMemory = 10 * 1024 * 1024; // 10 MB max file could be hold in memory constexpr auto kMaxVoiceInMemory = 2 * 1024 * 1024; // 2 MB audio is hold in memory and auto loaded @@ -61,14 +64,6 @@ struct StorageImageSaved { }; -enum LocalLoadStatus { - LocalNotTried, - LocalNotFound, - LocalLoading, - LocalLoaded, - LocalFailed, -}; - class mtpFileLoader; class webFileLoader; @@ -119,7 +114,7 @@ public: return _inQueue || _paused; } bool loadingLocal() const { - return (_localStatus == LocalLoading); + return (_localStatus == LocalStatus::Loading); } bool autoLoading() const { return _autoLoading; @@ -129,15 +124,37 @@ public: } virtual ~FileLoader(); - void localLoaded(const StorageImageSaved &result, const QByteArray &imageFormat = QByteArray(), const QPixmap &imagePixmap = QPixmap()); + void localLoaded( + const StorageImageSaved &result, + const QByteArray &imageFormat = QByteArray(), + const QPixmap &imagePixmap = QPixmap()); signals: void progress(FileLoader *loader); void failed(FileLoader *loader, bool started); protected: + enum class LocalStatus { + NotTried, + NotFound, + Loading, + Loaded, + }; + void readImage(const QSize &shrinkBox) const; + bool tryLoadLocal(); + void loadLocal(const Storage::Cache::Key &key); + virtual base::optional cacheKey() const = 0; + virtual void cancelRequests() = 0; + + void startLoading(bool loadFirst, bool prior); + void removeFromQueue(); + void cancel(bool failed); + + void loadNext(); + virtual bool loadPart() = 0; + not_null _downloader; FileLoader *_prev = nullptr; FileLoader *_next = nullptr; @@ -149,17 +166,7 @@ protected: bool _inQueue = false; bool _finished = false; bool _cancelled = false; - mutable LocalLoadStatus _localStatus = LocalNotTried; - - virtual bool tryLoadLocal() = 0; - virtual void cancelRequests() = 0; - - void startLoading(bool loadFirst, bool prior); - void removeFromQueue(); - void cancel(bool failed); - - void loadNext(); - virtual bool loadPart() = 0; + mutable LocalStatus _localStatus = LocalStatus::NotTried; QString _filename; QFile _file; @@ -173,7 +180,7 @@ protected: int32 _size; LocationType _locationType; - TaskId _localTaskId = 0; + base::binary_guard _localLoading; mutable QByteArray _imageFormat; mutable QPixmap _imagePixmap; @@ -238,8 +245,7 @@ private: int limit = 0; QByteArray hash; }; - - bool tryLoadLocal() override; + base::optional cacheKey() const override; void cancelRequests() override; int partSize() const; @@ -307,32 +313,28 @@ class webFileLoader : public FileLoader { Q_OBJECT public: + webFileLoader( + const QString &url, + const QString &to, + LoadFromCloudSetting fromCloud, + bool autoLoading); - webFileLoader(const QString &url, const QString &to, LoadFromCloudSetting fromCloud, bool autoLoading); - - virtual int32 currentOffset(bool includeSkipped = false) const; - virtual webFileLoader *webLoader() { - return this; - } - virtual const webFileLoader *webLoader() const { - return this; - } + int32 currentOffset(bool includeSkipped = false) const override; void onProgress(qint64 already, qint64 size); void onFinished(const QByteArray &data); void onError(); - virtual void stop() { + void stop() override { cancelRequests(); } ~webFileLoader(); protected: - - virtual void cancelRequests(); - virtual bool tryLoadLocal(); - virtual bool loadPart(); + void cancelRequests() override; + base::optional cacheKey() const override; + bool loadPart() override; QString _url; diff --git a/Telegram/SourceFiles/storage/file_upload.cpp b/Telegram/SourceFiles/storage/file_upload.cpp index 4831e062f0..c999c86088 100644 --- a/Telegram/SourceFiles/storage/file_upload.cpp +++ b/Telegram/SourceFiles/storage/file_upload.cpp @@ -126,6 +126,9 @@ void Uploader::uploadMedia(const FullMsgId &msgId, const SendMediaReady &media) : Auth().data().document(media.document, media.photoThumbs.begin().value()); if (!media.data.isEmpty()) { document->setData(media.data); + if (document->saveToCache()) { + Auth().data().cache().put(document->cacheKey(), media.data); + } } if (!media.file.isEmpty()) { document->setLocation(FileLocation(media.file)); @@ -148,6 +151,11 @@ void Uploader::upload( document->uploadingData = std::make_unique(document->size); if (!file->content.isEmpty()) { document->setData(file->content); + if (document->saveToCache()) { + Auth().data().cache().put( + document->cacheKey(), + file->content); + } } if (!file->filepath.isEmpty()) { document->setLocation(FileLocation(file->filepath)); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 21ed750c9e..a4354e27d8 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "storage/serialize_document.h" #include "storage/serialize_common.h" +#include "storage/storage_encrypted_file.h" #include "chat_helpers/stickers.h" #include "data/data_drafts.h" #include "boxes/send_files_box.h" @@ -65,7 +66,7 @@ QString toFilePart(FileKey val) { return result; } -QString _basePath, _userBasePath; +QString _basePath, _userBasePath, _userDbPath; bool _started = false; internal::Manager *_manager = nullptr; @@ -620,9 +621,6 @@ typedef QMap FileLocationPairs; FileLocationPairs _fileLocationPairs; typedef QMap FileLocationAliases; FileLocationAliases _fileLocationAliases; -typedef QMap WebFilesMap; -WebFilesMap _webFilesMap; -uint64 _storageWebFilesSize = 0; FileKey _locationsKey = 0, _reportSpamStatusesKey = 0, _trustedBotsKey = 0; using TrustedBots = OrderedSet; @@ -655,10 +653,6 @@ FileKey _exportSettingsKey = 0; FileKey _savedPeersKey = 0; FileKey _langPackKey = 0; -typedef QMap StorageMap; -StorageMap _imagesMap, _stickerImagesMap, _audiosMap; -qint64 _storageImagesSize = 0, _storageStickersSize = 0, _storageAudiosSize = 0; - bool _mapChanged = false; int32 _oldMapVersion = 0, _oldSettingsVersion = 0; @@ -686,7 +680,7 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) { if (!_working()) return; _manager->writingLocations(); - if (_fileLocations.isEmpty() && _webFilesMap.isEmpty()) { + if (_fileLocations.isEmpty()) { if (_locationsKey) { clearKey(_locationsKey); _locationsKey = 0; @@ -724,12 +718,6 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) { size += sizeof(quint64) * 2 + sizeof(quint64) * 2; } - size += sizeof(quint32); // web files count - for (WebFilesMap::const_iterator i = _webFilesMap.cbegin(), e = _webFilesMap.cend(); i != e; ++i) { - // url + filekey + size - size += Serialize::stringSize(i.key()) + sizeof(quint64) + sizeof(qint32); - } - EncryptedDescriptor data(size); auto legacyTypeField = 0; for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) { @@ -751,11 +739,6 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) { data.stream << quint64(i.key().first) << quint64(i.key().second) << quint64(i.value().first) << quint64(i.value().second); } - data.stream << quint32(_webFilesMap.size()); - for (WebFilesMap::const_iterator i = _webFilesMap.cbegin(), e = _webFilesMap.cend(); i != e; ++i) { - data.stream << i.key() << quint64(i.value().first) << qint32(i.value().second); - } - FileWriteDescriptor file(_locationsKey); file.writeEncrypted(data); } @@ -804,9 +787,6 @@ void _readLocations() { } if (!locations.stream.atEnd()) { - _storageWebFilesSize = 0; - _webFilesMap.clear(); - quint32 webLocationsCount; locations.stream >> webLocationsCount; for (quint32 i = 0; i < webLocationsCount; ++i) { @@ -814,8 +794,7 @@ void _readLocations() { quint64 key; qint32 size; locations.stream >> url >> key >> size; - _webFilesMap.insert(url, FileDesc(key, size)); - _storageWebFilesSize += size; + clearKey(key, FileOption::User); } } } @@ -2071,6 +2050,10 @@ ReadMapState _readMap(const QByteArray &pass) { hashMd5(dataNameUtf8.constData(), dataNameUtf8.size(), dataNameHash); _dataNameKey = dataNameHash[0]; _userBasePath = _basePath + toFilePart(_dataNameKey) + QChar('/'); + _userDbPath = _basePath + + "user_" + cDataFile() + + (cTestMode() ? "[test]" : "") + + '/'; FileReadDescriptor mapData; if (!readFile(mapData, qsl("map"))) { @@ -2113,8 +2096,6 @@ ReadMapState _readMap(const QByteArray &pass) { DraftsMap draftsMap, draftCursorsMap; DraftsNotReadMap draftsNotReadMap; - StorageMap imagesMap, stickerImagesMap, audiosMap; - qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0; quint64 locationsKey = 0, reportSpamStatusesKey = 0, trustedBotsKey = 0; quint64 recentStickersKeyOld = 0; quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0; @@ -2154,8 +2135,7 @@ ReadMapState _readMap(const QByteArray &pass) { quint64 first, second; qint32 size; map.stream >> key >> first >> second >> size; - imagesMap.insert(StorageKey(first, second), FileDesc(key, size)); - storageImagesSize += size; + clearKey(key, FileOption::User); } } break; case lskStickerImages: { @@ -2166,8 +2146,7 @@ ReadMapState _readMap(const QByteArray &pass) { quint64 first, second; qint32 size; map.stream >> key >> first >> second >> size; - stickerImagesMap.insert(StorageKey(first, second), FileDesc(key, size)); - storageStickersSize += size; + clearKey(key, FileOption::User); } } break; case lskAudios: { @@ -2178,8 +2157,7 @@ ReadMapState _readMap(const QByteArray &pass) { quint64 first, second; qint32 size; map.stream >> key >> first >> second >> size; - audiosMap.insert(StorageKey(first, second), FileDesc(key, size)); - storageAudiosSize += size; + clearKey(key, FileOption::User); } } break; case lskLocations: { @@ -2243,13 +2221,6 @@ ReadMapState _readMap(const QByteArray &pass) { _draftCursorsMap = draftCursorsMap; _draftsNotReadMap = draftsNotReadMap; - _imagesMap = imagesMap; - _storageImagesSize = storageImagesSize; - _stickerImagesMap = stickerImagesMap; - _storageStickersSize = storageStickersSize; - _audiosMap = audiosMap; - _storageAudiosSize = storageAudiosSize; - _locationsKey = locationsKey; _reportSpamStatusesKey = reportSpamStatusesKey; _trustedBotsKey = trustedBotsKey; @@ -2328,9 +2299,6 @@ void _writeMap(WriteMapWhen when) { uint32 mapSize = 0; if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2; if (!_draftCursorsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftCursorsMap.size() * sizeof(quint64) * 2; - if (!_imagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _imagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); - if (!_stickerImagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickerImagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); - if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_trustedBotsKey) mapSize += sizeof(quint32) + sizeof(quint64); @@ -2346,16 +2314,6 @@ void _writeMap(WriteMapWhen when) { if (_recentHashtagsAndBotsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_exportSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64); - if (mapSize > 30 * 1024 * 1024) { - CrashReports::SetAnnotation("MapSize", QString("%1,%2,%3,%4,%5" - ).arg(_draftsMap.size() - ).arg(_draftCursorsMap.size() - ).arg(_imagesMap.size() - ).arg(_stickerImagesMap.size() - ).arg(_audiosMap.size() - )); - } - EncryptedDescriptor mapData(mapSize); if (!_draftsMap.isEmpty()) { @@ -2370,24 +2328,6 @@ void _writeMap(WriteMapWhen when) { mapData.stream << quint64(i.value()) << quint64(i.key()); } } - if (!_imagesMap.isEmpty()) { - mapData.stream << quint32(lskImages) << quint32(_imagesMap.size()); - for (StorageMap::const_iterator i = _imagesMap.cbegin(), e = _imagesMap.cend(); i != e; ++i) { - mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second); - } - } - if (!_stickerImagesMap.isEmpty()) { - mapData.stream << quint32(lskStickerImages) << quint32(_stickerImagesMap.size()); - for (StorageMap::const_iterator i = _stickerImagesMap.cbegin(), e = _stickerImagesMap.cend(); i != e; ++i) { - mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second); - } - } - if (!_audiosMap.isEmpty()) { - mapData.stream << quint32(lskAudios) << quint32(_audiosMap.size()); - for (StorageMap::const_iterator i = _audiosMap.cbegin(), e = _audiosMap.cend(); i != e; ++i) { - mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second); - } - } if (_locationsKey) { mapData.stream << quint32(lskLocations) << quint64(_locationsKey); } @@ -2431,10 +2371,6 @@ void _writeMap(WriteMapWhen when) { map.writeEncrypted(mapData); _mapChanged = false; - - if (mapSize > 30 * 1024 * 1024) { - CrashReports::ClearAnnotation("MapSize"); - } } } // namespace @@ -2683,13 +2619,7 @@ void reset() { _fileLocations.clear(); _fileLocationPairs.clear(); _fileLocationAliases.clear(); - _imagesMap.clear(); _draftsNotReadMap.clear(); - _stickerImagesMap.clear(); - _audiosMap.clear(); - _storageImagesSize = _storageStickersSize = _storageAudiosSize = 0; - _webFilesMap.clear(); - _storageWebFilesSize = 0; _locationsKey = _reportSpamStatusesKey = _trustedBotsKey = 0; _recentStickersKeyOld = 0; _installedStickersKey = _featuredStickersKey = _recentStickersKey = _favedStickersKey = _archivedStickersKey = 0; @@ -3011,401 +2941,23 @@ qint32 _storageAudioSize(qint32 rawlen) { return result; } -void writeImage(const StorageKey &location, const ImagePtr &image) { - if (image->isNull() || !image->loaded()) return; - if (_imagesMap.constFind(location) != _imagesMap.cend()) return; +QString cachePath() { + Expects(!_userDbPath.isEmpty()); - image->forget(); - writeImage(location, StorageImageSaved(image->savedData()), false); + return _userDbPath + "cache"; } -void writeImage(const StorageKey &location, const StorageImageSaved &image, bool overwrite) { - if (!_working()) return; - - qint32 size = _storageImageSize(image.data.size()); - StorageMap::const_iterator i = _imagesMap.constFind(location); - if (i == _imagesMap.cend()) { - i = _imagesMap.insert(location, FileDesc(genKey(FileOption::User), size)); - _storageImagesSize += size; - _mapChanged = true; - _writeMap(); - } else if (!overwrite) { - return; - } - - auto legacyTypeField = 0; - - EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + image.data.size()); - data.stream << quint64(location.first) << quint64(location.second) << quint32(legacyTypeField) << image.data; - - FileWriteDescriptor file(i.value().first, FileOption::User); - file.writeEncrypted(data); - if (i.value().second != size) { - _storageImagesSize += size; - _storageImagesSize -= i.value().second; - _imagesMap[location].second = size; - } -} - -class AbstractCachedLoadTask : public Task { -public: - - AbstractCachedLoadTask(const FileKey &key, const StorageKey &location, bool readImageFlag, mtpFileLoader *loader) : - _key(key), _location(location), _readImageFlag(readImageFlag), _loader(loader), _result(0) { - } - void process() { - FileReadDescriptor image; - if (!readEncryptedFile(image, _key, FileOption::User)) { - return; - } - - QByteArray imageData; - quint64 locFirst, locSecond; - quint32 legacyTypeField = 0; - readFromStream(image.stream, locFirst, locSecond, imageData); - - // we're saving files now before we have actual location - //if (locFirst != _location.first || locSecond != _location.second) { - // return; - //} - - _result = new Result(imageData, _readImageFlag); - } - void finish() { - if (_result) { - _loader->localLoaded(_result->image, _result->format, _result->pixmap); - } else { - clearInMap(); - _loader->localLoaded(StorageImageSaved()); - } - } - virtual void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, QByteArray &data) = 0; - virtual void clearInMap() = 0; - virtual ~AbstractCachedLoadTask() { - delete base::take(_result); - } - -protected: - FileKey _key; - StorageKey _location; - bool _readImageFlag; - struct Result { - Result(const QByteArray &data, bool readImageFlag) : image(data) { - if (readImageFlag) { - auto realFormat = QByteArray(); - pixmap = App::pixmapFromImageInPlace(App::readImage(data, &realFormat, false)); - if (!pixmap.isNull()) { - format = realFormat; - } - } - } - StorageImageSaved image; - QByteArray format; - QPixmap pixmap; - - }; - mtpFileLoader *_loader; - Result *_result; - -}; - -class ImageLoadTask : public AbstractCachedLoadTask { -public: - ImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) : - AbstractCachedLoadTask(key, location, true, loader) { - } - void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, QByteArray &data) override { - qint32 legacyTypeField = 0; - stream >> first >> second >> legacyTypeField >> data; - } - void clearInMap() override { - StorageMap::iterator j = _imagesMap.find(_location); - if (j != _imagesMap.cend() && j->first == _key) { - clearKey(_key, FileOption::User); - _storageImagesSize -= j->second; - _imagesMap.erase(j); - } - } -}; - -TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader) { - StorageMap::const_iterator j = _imagesMap.constFind(location); - if (j == _imagesMap.cend() || !_localLoader) { - return 0; - } - return _localLoader->addTask( - std::make_unique(j->first, location, loader)); -} - -bool willImageLoad(const StorageKey &location) { - return _imagesMap.constFind(location) != _imagesMap.cend(); -} - -int32 hasImages() { - return _imagesMap.size(); -} - -qint64 storageImagesSize() { - return _storageImagesSize; -} - -void writeStickerImage(const StorageKey &location, const QByteArray &sticker, bool overwrite) { - if (!_working()) return; - - qint32 size = _storageStickerSize(sticker.size()); - StorageMap::const_iterator i = _stickerImagesMap.constFind(location); - if (i == _stickerImagesMap.cend()) { - i = _stickerImagesMap.insert(location, FileDesc(genKey(FileOption::User), size)); - _storageStickersSize += size; - _mapChanged = true; - _writeMap(); - } else if (!overwrite) { - return; - } - EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + sticker.size()); - data.stream << quint64(location.first) << quint64(location.second) << sticker; - FileWriteDescriptor file(i.value().first, FileOption::User); - file.writeEncrypted(data); - if (i.value().second != size) { - _storageStickersSize += size; - _storageStickersSize -= i.value().second; - _stickerImagesMap[location].second = size; - } -} - -class StickerImageLoadTask : public AbstractCachedLoadTask { -public: - StickerImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) : - AbstractCachedLoadTask(key, location, true, loader) { - } - void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, QByteArray &data) { - stream >> first >> second >> data; - } - void clearInMap() { - auto j = _stickerImagesMap.find(_location); - if (j != _stickerImagesMap.cend() && j->first == _key) { - clearKey(j.value().first, FileOption::User); - _storageStickersSize -= j.value().second; - _stickerImagesMap.erase(j); - } - } -}; - -TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader) { - auto j = _stickerImagesMap.constFind(location); - if (j == _stickerImagesMap.cend() || !_localLoader) { - return 0; - } - return _localLoader->addTask( - std::make_unique(j->first, location, loader)); -} - -bool willStickerImageLoad(const StorageKey &location) { - return _stickerImagesMap.constFind(location) != _stickerImagesMap.cend(); -} - -bool copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation) { - auto i = _stickerImagesMap.constFind(oldLocation); - if (i == _stickerImagesMap.cend()) { - return false; - } - _stickerImagesMap.insert(newLocation, i.value()); - _mapChanged = true; - _writeMap(); - return true; -} - -int32 hasStickers() { - return _stickerImagesMap.size(); -} - -qint64 storageStickersSize() { - return _storageStickersSize; -} - -void writeAudio(const StorageKey &location, const QByteArray &audio, bool overwrite) { - if (!_working()) return; - - qint32 size = _storageAudioSize(audio.size()); - StorageMap::const_iterator i = _audiosMap.constFind(location); - if (i == _audiosMap.cend()) { - i = _audiosMap.insert(location, FileDesc(genKey(FileOption::User), size)); - _storageAudiosSize += size; - _mapChanged = true; - _writeMap(); - } else if (!overwrite) { - return; - } - EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + audio.size()); - data.stream << quint64(location.first) << quint64(location.second) << audio; - FileWriteDescriptor file(i.value().first, FileOption::User); - file.writeEncrypted(data); - if (i.value().second != size) { - _storageAudiosSize += size; - _storageAudiosSize -= i.value().second; - _audiosMap[location].second = size; - } -} - -class AudioLoadTask : public AbstractCachedLoadTask { -public: - AudioLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) : - AbstractCachedLoadTask(key, location, false, loader) { - } - void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, QByteArray &data) { - stream >> first >> second >> data; - } - void clearInMap() { - auto j = _audiosMap.find(_location); - if (j != _audiosMap.cend() && j->first == _key) { - clearKey(j.value().first, FileOption::User); - _storageAudiosSize -= j.value().second; - _audiosMap.erase(j); - } - } -}; - -TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) { - auto j = _audiosMap.constFind(location); - if (j == _audiosMap.cend() || !_localLoader) { - return 0; - } - return _localLoader->addTask( - std::make_unique(j->first, location, loader)); -} - -bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation) { - auto i = _audiosMap.constFind(oldLocation); - if (i == _audiosMap.cend()) { - return false; - } - _audiosMap.insert(newLocation, i.value()); - _mapChanged = true; - _writeMap(); - return true; -} - -bool willAudioLoad(const StorageKey &location) { - return _audiosMap.constFind(location) != _audiosMap.cend(); -} - -int32 hasAudios() { - return _audiosMap.size(); -} - -qint64 storageAudiosSize() { - return _storageAudiosSize; -} - -qint32 _storageWebFileSize(const QString &url, qint32 rawlen) { - // fulllen + url + len + data - qint32 result = sizeof(uint32) + Serialize::stringSize(url) + sizeof(quint32) + rawlen; - if (result & 0x0F) result += 0x10 - (result & 0x0F); - result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5 +Storage::Cache::Database::Settings cacheSettings() { + auto result = Storage::Cache::Database::Settings(); return result; } -void writeWebFile(const QString &url, const QByteArray &content, bool overwrite) { - if (!_working()) return; +Storage::EncryptionKey cacheKey() { + Expects(LocalKey != nullptr); - qint32 size = _storageWebFileSize(url, content.size()); - WebFilesMap::const_iterator i = _webFilesMap.constFind(url); - if (i == _webFilesMap.cend()) { - i = _webFilesMap.insert(url, FileDesc(genKey(FileOption::User), size)); - _storageWebFilesSize += size; - _writeLocations(); - } else if (!overwrite) { - return; - } - EncryptedDescriptor data(Serialize::stringSize(url) + sizeof(quint32) + sizeof(quint32) + content.size()); - data.stream << url << content; - FileWriteDescriptor file(i.value().first, FileOption::User); - file.writeEncrypted(data); - if (i.value().second != size) { - _storageWebFilesSize += size; - _storageWebFilesSize -= i.value().second; - _webFilesMap[url].second = size; - } + return Storage::EncryptionKey(bytes::make_vector(LocalKey->data())); } -class WebFileLoadTask : public Task { -public: - WebFileLoadTask(const FileKey &key, const QString &url, webFileLoader *loader) - : _key(key) - , _url(url) - , _loader(loader) - , _result(0) { - } - void process() { - FileReadDescriptor image; - if (!readEncryptedFile(image, _key, FileOption::User)) { - return; - } - - QByteArray imageData; - QString url; - image.stream >> url >> imageData; - - _result = new Result(imageData); - } - void finish() { - if (_result) { - _loader->localLoaded(_result->image, _result->format, _result->pixmap); - } else { - WebFilesMap::iterator j = _webFilesMap.find(_url); - if (j != _webFilesMap.cend() && j->first == _key) { - clearKey(j.value().first, FileOption::User); - _storageWebFilesSize -= j.value().second; - _webFilesMap.erase(j); - } - _loader->localLoaded(StorageImageSaved()); - } - } - virtual ~WebFileLoadTask() { - delete base::take(_result); - } - -protected: - FileKey _key; - QString _url; - struct Result { - explicit Result(const QByteArray &data) : image(data) { - QByteArray guessFormat; - pixmap = App::pixmapFromImageInPlace(App::readImage(data, &guessFormat, false)); - if (!pixmap.isNull()) { - format = guessFormat; - } - } - StorageImageSaved image; - QByteArray format; - QPixmap pixmap; - - }; - webFileLoader *_loader; - Result *_result; - -}; - -TaskId startWebFileLoad(const QString &url, webFileLoader *loader) { - WebFilesMap::const_iterator j = _webFilesMap.constFind(url); - if (j == _webFilesMap.cend() || !_localLoader) { - return 0; - } - return _localLoader->addTask( - std::make_unique(j->first, url, loader)); -} - -bool willWebFileLoad(const QString &url) { - return _webFilesMap.constFind(url) != _webFilesMap.cend(); -} - -int32 hasWebFiles() { - return _webFilesMap.size(); -} - -qint64 storageWebFilesSize() { - return _storageWebFilesSize; -} class CountWaveformTask : public Task { public: @@ -5136,8 +4688,6 @@ bool decrypt(const void *src, void *dst, uint32 len, const void *key128) { struct ClearManagerData { QThread *thread; - StorageMap images, stickers, audios; - WebFilesMap webFiles; QMutex mutex; QList tasks; bool working; @@ -5155,21 +4705,6 @@ bool ClearManager::addTask(int task) { if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true; if (task == ClearManagerAll) { data->tasks.clear(); - if (!_imagesMap.isEmpty()) { - _imagesMap.clear(); - _storageImagesSize = 0; - _mapChanged = true; - } - if (!_stickerImagesMap.isEmpty()) { - _stickerImagesMap.clear(); - _storageStickersSize = 0; - _mapChanged = true; - } - if (!_audiosMap.isEmpty()) { - _audiosMap.clear(); - _storageAudiosSize = 0; - _mapChanged = true; - } if (!_draftsMap.isEmpty()) { _draftsMap.clear(); _mapChanged = true; @@ -5208,73 +4743,6 @@ bool ClearManager::addTask(int task) { } _writeMap(); } else { - if (task & ClearManagerStorage) { - if (data->images.isEmpty()) { - data->images = _imagesMap; - } else { - for (StorageMap::const_iterator i = _imagesMap.cbegin(), e = _imagesMap.cend(); i != e; ++i) { - StorageKey k = i.key(); - while (data->images.constFind(k) != data->images.cend()) { - ++k.second; - } - data->images.insert(k, i.value()); - } - } - if (!_imagesMap.isEmpty()) { - _imagesMap.clear(); - _storageImagesSize = 0; - _mapChanged = true; - } - if (data->stickers.isEmpty()) { - data->stickers = _stickerImagesMap; - } else { - for (StorageMap::const_iterator i = _stickerImagesMap.cbegin(), e = _stickerImagesMap.cend(); i != e; ++i) { - StorageKey k = i.key(); - while (data->stickers.constFind(k) != data->stickers.cend()) { - ++k.second; - } - data->stickers.insert(k, i.value()); - } - } - if (!_stickerImagesMap.isEmpty()) { - _stickerImagesMap.clear(); - _storageStickersSize = 0; - _mapChanged = true; - } - if (data->webFiles.isEmpty()) { - data->webFiles = _webFilesMap; - } else { - for (WebFilesMap::const_iterator i = _webFilesMap.cbegin(), e = _webFilesMap.cend(); i != e; ++i) { - QString k = i.key(); - while (data->webFiles.constFind(k) != data->webFiles.cend()) { - k += '#'; - } - data->webFiles.insert(k, i.value()); - } - } - if (!_webFilesMap.isEmpty()) { - _webFilesMap.clear(); - _storageWebFilesSize = 0; - _writeLocations(); - } - if (data->audios.isEmpty()) { - data->audios = _audiosMap; - } else { - for (StorageMap::const_iterator i = _audiosMap.cbegin(), e = _audiosMap.cend(); i != e; ++i) { - StorageKey k = i.key(); - while (data->audios.constFind(k) != data->audios.cend()) { - ++k.second; - } - data->audios.insert(k, i.value()); - } - } - if (!_audiosMap.isEmpty()) { - _audiosMap.clear(); - _storageAudiosSize = 0; - _mapChanged = true; - } - _writeMap(); - } for (int32 i = 0, l = data->tasks.size(); i < l; ++i) { if (data->tasks.at(i) == task) return true; } @@ -5319,8 +4787,6 @@ void ClearManager::onStart() { while (true) { int task = 0; bool result = false; - StorageMap images, stickers, audios; - WebFilesMap webFiles; { QMutexLocker lock(&data->mutex); if (data->tasks.isEmpty()) { @@ -5328,10 +4794,6 @@ void ClearManager::onStart() { break; } task = data->tasks.at(0); - images = data->images; - stickers = data->stickers; - audios = data->audios; - webFiles = data->webFiles; } switch (task) { case ClearManagerAll: { @@ -5354,18 +4816,6 @@ void ClearManager::onStart() { result = QDir(cTempDir()).removeRecursively(); break; case ClearManagerStorage: - for (StorageMap::const_iterator i = images.cbegin(), e = images.cend(); i != e; ++i) { - clearKey(i.value().first, FileOption::User); - } - for (StorageMap::const_iterator i = stickers.cbegin(), e = stickers.cend(); i != e; ++i) { - clearKey(i.value().first, FileOption::User); - } - for (StorageMap::const_iterator i = audios.cbegin(), e = audios.cend(); i != e; ++i) { - clearKey(i.value().first, FileOption::User); - } - for (WebFilesMap::const_iterator i = webFiles.cbegin(), e = webFiles.cend(); i != e; ++i) { - clearKey(i.value().first, FileOption::User); - } result = true; break; } diff --git a/Telegram/SourceFiles/storage/localstorage.h b/Telegram/SourceFiles/storage/localstorage.h index f6a10f9b9c..03b291d9be 100644 --- a/Telegram/SourceFiles/storage/localstorage.h +++ b/Telegram/SourceFiles/storage/localstorage.h @@ -8,8 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "storage/file_download.h" +#include "storage/cache/storage_cache_database.h" +#include "storage/localimageloader.h" #include "auth_session.h" +namespace Storage { +class EncryptionKey; +} // namespace Storage + namespace Window { namespace Theme { struct Saved; @@ -98,32 +104,9 @@ bool hasDraft(const PeerId &peer); void writeFileLocation(MediaKey location, const FileLocation &local); FileLocation readFileLocation(MediaKey location, bool check = true); -void writeImage(const StorageKey &location, const ImagePtr &img); -void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true); -TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader); -bool willImageLoad(const StorageKey &location); -int32 hasImages(); -qint64 storageImagesSize(); - -void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true); -TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader); -bool willStickerImageLoad(const StorageKey &location); -bool copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation); -int32 hasStickers(); -qint64 storageStickersSize(); - -void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true); -TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader); -bool willAudioLoad(const StorageKey &location); -bool copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation); -int32 hasAudios(); -qint64 storageAudiosSize(); - -void writeWebFile(const QString &url, const QByteArray &data, bool overwrite = true); -TaskId startWebFileLoad(const QString &url, webFileLoader *loader); -bool willWebFileLoad(const QString &url); -int32 hasWebFiles(); -qint64 storageWebFilesSize(); +QString cachePath(); +Storage::Cache::Database::Settings cacheSettings(); +Storage::EncryptionKey cacheKey(); void countVoiceWaveform(DocumentData *document); diff --git a/Telegram/SourceFiles/ui/images.cpp b/Telegram/SourceFiles/ui/images.cpp index 541e510817..f207e9fcd6 100644 --- a/Telegram/SourceFiles/ui/images.cpp +++ b/Telegram/SourceFiles/ui/images.cpp @@ -9,10 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "storage/localstorage.h" +#include "storage/cache/storage_cache_database.h" #include "platform/platform_specific.h" #include "auth_session.h" #include "history/history_item.h" #include "history/history.h" +#include "data/data_session.h" namespace Images { namespace { @@ -915,6 +917,10 @@ void Image::restore() const { _forgot = false; } +base::optional Image::cacheKey() const { + return base::none; +} + void Image::invalidateSizeCache() const { for (auto &pix : _sizesCache) { if (!pix.isNull()) { @@ -993,9 +999,9 @@ void RemoteImage::loadLocal() { if (_loader) _loader->start(); } -void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) { - QBuffer buffer(&bytes); - +void RemoteImage::setImageBytes( + const QByteArray &bytes, + const QByteArray &bytesFormat) { if (!_data.isNull()) { globalAcquiredSize -= int64(_data.width()) * _data.height() * 4; } @@ -1013,6 +1019,11 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) { _saved = bytes; _format = fmt; _forgot = false; + + const auto location = this->location(); + if (!location.isNull() && !bytes.isEmpty()) { + Auth().data().cache().putIfEmpty(Data::StorageCacheKey(location), bytes); + } } bool RemoteImage::amLoading() const { @@ -1113,13 +1124,18 @@ StorageImage::StorageImage(const StorageImageLocation &location, int32 size) , _size(size) { } -StorageImage::StorageImage(const StorageImageLocation &location, QByteArray &bytes) +StorageImage::StorageImage( + const StorageImageLocation &location, + const QByteArray &bytes) : _location(location) , _size(bytes.size()) { - setData(bytes); - if (!_location.isNull()) { - Local::writeImage(storageKey(_location), StorageImageSaved(bytes)); - } + setImageBytes(bytes); +} + +base::optional StorageImage::cacheKey() const { + return _location.isNull() + ? base::none + : base::make_optional(Data::StorageCacheKey(_location)); } int32 StorageImage::countWidth() const { @@ -1130,10 +1146,6 @@ int32 StorageImage::countHeight() const { return _location.height(); } -bool StorageImage::hasLocalCopy() const { - return Local::willImageLoad(storageKey(_location)); -} - void StorageImage::setInformation(int32 size, int32 width, int32 height) { _size = size; _location.setSize(width, height); @@ -1176,6 +1188,12 @@ WebFileImage::WebFileImage( , _size(size) { } +base::optional WebFileImage::cacheKey() const { + return _location.isNull() + ? base::none + : base::make_optional(Data::WebDocumentCacheKey(_location)); +} + int WebFileImage::countWidth() const { return _width; } @@ -1184,10 +1202,6 @@ int WebFileImage::countHeight() const { return _height; } -bool WebFileImage::hasLocalCopy() const { - return Local::willImageLoad(storageKey(_location)); -} - void WebFileImage::setInformation(int size, int width, int height) { _size = size; _width = width; @@ -1219,13 +1233,13 @@ DelayedStorageImage::DelayedStorageImage(int32 w, int32 h) , _loadCancelled(false) , _loadFromCloud(false) { } - -DelayedStorageImage::DelayedStorageImage(QByteArray &bytes) -: StorageImage(StorageImageLocation(), bytes) -, _loadRequested(false) -, _loadCancelled(false) -, _loadFromCloud(false) { -} +// +//DelayedStorageImage::DelayedStorageImage(QByteArray &bytes) +//: StorageImage(StorageImageLocation(), bytes) +//, _loadRequested(false) +//, _loadCancelled(false) +//, _loadFromCloud(false) { +//} void DelayedStorageImage::setStorageLocation( Data::FileOrigin origin, @@ -1317,6 +1331,10 @@ WebImage::WebImage(const QString &url, int width, int height) , _height(height) { } +base::optional WebImage::cacheKey() const { + return Data::UrlCacheKey(_url); +} + void WebImage::setSize(int width, int height) { _width = width; _height = height; @@ -1330,10 +1348,6 @@ int32 WebImage::countHeight() const { return _height; } -bool WebImage::hasLocalCopy() const { - return Local::willWebFileLoad(_url); -} - void WebImage::setInformation(int32 size, int32 width, int32 height) { _size = size; setSize(width, height); @@ -1404,8 +1418,8 @@ Image *getImage(int32 width, int32 height) { } StorageImage *getImage(const StorageImageLocation &location, int32 size) { - StorageKey key(storageKey(location)); - StorageImages::const_iterator i = storageImages.constFind(key); + const auto key = storageKey(location); + auto i = storageImages.constFind(key); if (i == storageImages.cend()) { i = storageImages.insert(key, new StorageImage(location, size)); } else { @@ -1414,20 +1428,17 @@ StorageImage *getImage(const StorageImageLocation &location, int32 size) { return i.value(); } -StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes) { - StorageKey key(storageKey(location)); - StorageImages::const_iterator i = storageImages.constFind(key); +StorageImage *getImage( + const StorageImageLocation &location, + const QByteArray &bytes) { + const auto key = storageKey(location); + auto i = storageImages.constFind(key); if (i == storageImages.cend()) { - QByteArray bytesArr(bytes); - i = storageImages.insert(key, new StorageImage(location, bytesArr)); + i = storageImages.insert(key, new StorageImage(location, bytes)); } else { i.value()->refreshFileReference(location.fileReference()); if (!i.value()->loaded()) { - QByteArray bytesArr(bytes); - i.value()->setData(bytesArr); - if (!location.isNull()) { - Local::writeImage(key, StorageImageSaved(bytes)); - } + i.value()->setImageBytes(bytes); } } return i.value(); diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 4eae6d1b28..d90d9a635b 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -10,6 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/flags.h" #include "data/data_file_origin.h" +namespace Storage { +namespace Cache { +struct Key; +} // namespace Cache +} // namespace Storage + enum class ImageRoundRadius { None, Large, @@ -372,6 +378,7 @@ public: virtual const StorageImageLocation &location() const { return StorageImageLocation::Null; } + virtual base::optional cacheKey() const; bool isNull() const; @@ -412,10 +419,6 @@ protected: return _data.height(); } - virtual bool hasLocalCopy() const { - return false; - } - mutable QByteArray _saved, _format; mutable bool _forgot; mutable QPixmap _data; @@ -464,8 +467,8 @@ public: float64 progress() const override; int32 loadOffset() const override; - void setData( - QByteArray &bytes, + void setImageBytes( + const QByteArray &bytes, const QByteArray &format = QByteArray()); void load( @@ -507,12 +510,13 @@ private: class StorageImage : public RemoteImage { public: - StorageImage(const StorageImageLocation &location, int32 size = 0); - StorageImage(const StorageImageLocation &location, QByteArray &bytes); + explicit StorageImage(const StorageImageLocation &location, int32 size = 0); + StorageImage(const StorageImageLocation &location, const QByteArray &bytes); const StorageImageLocation &location() const override { return _location; } + base::optional cacheKey() const override; void refreshFileReference(const QByteArray &data) { _location.refreshFileReference(data); } @@ -524,8 +528,6 @@ protected: LoadFromCloudSetting fromCloud, bool autoLoading) override; - bool hasLocalCopy() const override; - int32 countWidth() const override; int32 countHeight() const override; @@ -543,6 +545,8 @@ public: int height, int size = 0); + base::optional cacheKey() const override; + protected: void setInformation(int size, int width, int height) override; FileLoader *createLoader( @@ -554,8 +558,6 @@ protected: return _box; } - bool hasLocalCopy() const override; - int countWidth() const override; int countHeight() const override; @@ -571,7 +573,7 @@ class DelayedStorageImage : public StorageImage { public: DelayedStorageImage(); DelayedStorageImage(int32 w, int32 h); - DelayedStorageImage(QByteArray &bytes); + //DelayedStorageImage(QByteArray &bytes); void setStorageLocation( Data::FileOrigin origin, @@ -617,6 +619,8 @@ public: void setSize(int width, int height); + base::optional cacheKey() const override; + protected: QSize shrinkBox() const override { return _box; @@ -630,8 +634,6 @@ protected: int32 countWidth() const override; int32 countHeight() const override; - bool hasLocalCopy() const override; - private: QString _url; QSize _box; @@ -652,7 +654,7 @@ Image *getImage( const QPixmap &pixmap); Image *getImage(int32 width, int32 height); StorageImage *getImage(const StorageImageLocation &location, int size = 0); -StorageImage *getImage( +StorageImage *getImage( // photoCachedSize const StorageImageLocation &location, const QByteArray &bytes); Image *getImage(const MTPWebDocument &location); diff --git a/Telegram/build/build.bat b/Telegram/build/build.bat index 8d8be3af73..80d8176116 100644 --- a/Telegram/build/build.bat +++ b/Telegram/build/build.bat @@ -250,6 +250,10 @@ if %BuildUWP% neq 0 ( cd "%DeployPath%" 7z a -mx9 %PortableFile% %BinaryName%\ if %errorlevel% neq 0 goto error + + move "%DeployPath%\%BinaryName%\%BinaryName%.exe" "%DeployPath%\" + rmdir "%DeployPath%\%BinaryName%" + if %errorlevel% neq 0 goto error ) set "FinalDeployPath=%FinalReleasePath%\%AppVersionStrMajor%\%AppVersionStrFull%\tsetup"