2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Use Storage::Cache::Database for file caching.

This commit is contained in:
John Preston
2018-08-27 14:35:58 +03:00
parent a58c082cfa
commit 2e7f4c2f21
30 changed files with 537 additions and 888 deletions

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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<AuthSession*> 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();
}

View File

@@ -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<bool> &contactsLoaded() {
return _contactsLoaded;
}
@@ -520,6 +523,8 @@ private:
not_null<AuthSession*> _session;
Storage::Cache::Database _cache;
std::unique_ptr<Export::ControllerWrap> _export;
std::unique_ptr<Export::View::PanelController> _exportPanel;
rpl::event_stream<Export::View::PanelController*> _exportViewChanges;

View File

@@ -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<const uint32*>(bytes1.data());
const auto part2 = *reinterpret_cast<const uint64*>(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<const uint32*>(bytes1.data());
const auto part2 = *reinterpret_cast<const uint64*>(bytes2.data());
const auto part3 = *reinterpret_cast<const uint16*>(bytes3.data());
return Storage::Cache::Key{
Data::kUrlCacheTag | (uint64(part3) << 32) | part1,
part2
};
}
} // namespace Data
void AudioMsgId::setTypeFromAudio() {
if (_audio->isVoiceMessage() || _audio->isVideoMessage()) {

View File

@@ -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<not_null<HistoryItem*>>;
@@ -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 {