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:
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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()) {
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user