mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-21 15:47:38 +00:00
Use Storage::Cache::Database for file caching.
This commit is contained in:
parent
a58c082cfa
commit
2e7f4c2f21
@ -37,29 +37,14 @@ void LocalStorageBox::prepare() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LocalStorageBox::updateControls() {
|
void LocalStorageBox::updateControls() {
|
||||||
auto rowsHeight = 0;
|
const auto rowsHeight = st::linkFont->height + st::localStorageBoxSkip;
|
||||||
if (_imagesCount > 0 && _audiosCount > 0) {
|
_clear->setVisible(false);
|
||||||
rowsHeight = 2 * (st::linkFont->height + st::localStorageBoxSkip);
|
|
||||||
} else {
|
|
||||||
rowsHeight = st::linkFont->height + st::localStorageBoxSkip;
|
|
||||||
}
|
|
||||||
_clear->setVisible(_imagesCount > 0 || _audiosCount > 0);
|
|
||||||
setDimensions(st::boxWidth, st::localStorageBoxSkip + rowsHeight + _clear->height());
|
setDimensions(st::boxWidth, st::localStorageBoxSkip + rowsHeight + _clear->height());
|
||||||
_clear->moveToLeft(st::boxPadding.left(), st::localStorageBoxSkip + rowsHeight);
|
_clear->moveToLeft(st::boxPadding.left(), st::localStorageBoxSkip + rowsHeight);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalStorageBox::checkLocalStoredCounts() {
|
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) {
|
void LocalStorageBox::paintEvent(QPaintEvent *e) {
|
||||||
@ -71,19 +56,8 @@ void LocalStorageBox::paintEvent(QPaintEvent *e) {
|
|||||||
p.setPen(st::windowFg);
|
p.setPen(st::windowFg);
|
||||||
checkLocalStoredCounts();
|
checkLocalStoredCounts();
|
||||||
auto top = st::localStorageBoxSkip;
|
auto top = st::localStorageBoxSkip;
|
||||||
if (_imagesCount > 0) {
|
p.drawTextLeft(st::boxPadding.left(), top, width(), lang(lng_settings_no_data_cached));
|
||||||
auto text = lng_settings_images_cached(lt_count, _imagesCount, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize() + Local::storageWebFilesSize()));
|
top += st::boxTextFont->height + st::localStorageBoxSkip;
|
||||||
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;
|
|
||||||
}
|
|
||||||
auto text = ([this]() -> QString {
|
auto text = ([this]() -> QString {
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case State::Clearing: return lang(lng_local_storage_clearing);
|
case State::Clearing: return lang(lng_local_storage_clearing);
|
||||||
|
@ -43,7 +43,4 @@ private:
|
|||||||
|
|
||||||
object_ptr<Ui::LinkButton> _clear;
|
object_ptr<Ui::LinkButton> _clear;
|
||||||
|
|
||||||
int _imagesCount = -1;
|
|
||||||
int _audiosCount = -1;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -221,7 +221,8 @@ void Launcher::processArguments() {
|
|||||||
gTestMode = parseResult.contains("-testmode");
|
gTestMode = parseResult.contains("-testmode");
|
||||||
Logs::SetDebugEnabled(parseResult.contains("-debug"));
|
Logs::SetDebugEnabled(parseResult.contains("-debug"));
|
||||||
gManyInstance = parseResult.contains("-many");
|
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
|
gLaunchMode = parseResult.contains("-autostart") ? LaunchModeAutoStart
|
||||||
: parseResult.contains("-fixprevious") ? LaunchModeFixPrevious
|
: parseResult.contains("-fixprevious") ? LaunchModeFixPrevious
|
||||||
: parseResult.contains("-cleanup") ? LaunchModeCleanup
|
: parseResult.contains("-cleanup") ? LaunchModeCleanup
|
||||||
@ -229,8 +230,8 @@ void Launcher::processArguments() {
|
|||||||
gNoStartUpdate = parseResult.contains("-noupdate");
|
gNoStartUpdate = parseResult.contains("-noupdate");
|
||||||
gStartToSettings = parseResult.contains("-tosettings");
|
gStartToSettings = parseResult.contains("-tosettings");
|
||||||
gStartInTray = parseResult.contains("-startintray");
|
gStartInTray = parseResult.contains("-startintray");
|
||||||
gSendPaths = parseResult.value("-sendpath", QStringList());
|
gSendPaths = parseResult.value("-sendpath", {});
|
||||||
gWorkingDir = parseResult.value("-workdir", QStringList()).join(QString());
|
gWorkingDir = parseResult.value("-workdir", {}).join(QString());
|
||||||
if (!gWorkingDir.isEmpty()) {
|
if (!gWorkingDir.isEmpty()) {
|
||||||
if (QDir().exists(gWorkingDir)) {
|
if (QDir().exists(gWorkingDir)) {
|
||||||
_customWorkingDir = true;
|
_customWorkingDir = true;
|
||||||
@ -238,7 +239,7 @@ void Launcher::processArguments() {
|
|||||||
gWorkingDir = QString();
|
gWorkingDir = QString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gStartUrl = parseResult.value("--", QStringList()).join(QString());
|
gStartUrl = parseResult.value("--", {}).join(QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Launcher::executeApplication() {
|
int Launcher::executeApplication() {
|
||||||
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
|
#include "storage/cache/storage_cache_database.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
@ -1087,6 +1088,16 @@ MediaKey DocumentData::mediaKey() const {
|
|||||||
return ::mediaKey(locationType(), _dc, id);
|
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 {
|
QString DocumentData::composeNameString() const {
|
||||||
if (auto songData = song()) {
|
if (auto songData = song()) {
|
||||||
return ComposeNameString(
|
return ComposeNameString(
|
||||||
@ -1207,17 +1218,9 @@ void DocumentData::setWebLocation(const WebFileLocation &location) {
|
|||||||
void DocumentData::collectLocalData(DocumentData *local) {
|
void DocumentData::collectLocalData(DocumentData *local) {
|
||||||
if (local == this) return;
|
if (local == this) return;
|
||||||
|
|
||||||
|
_session->data().cache().copyIfEmpty(local->cacheKey(), cacheKey());
|
||||||
if (!local->_data.isEmpty()) {
|
if (!local->_data.isEmpty()) {
|
||||||
_data = local->_data;
|
_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()) {
|
if (!local->_location.isEmpty()) {
|
||||||
_location = local->_location;
|
_location = local->_location;
|
||||||
|
@ -9,6 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include "data/data_types.h"
|
#include "data/data_types.h"
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Cache {
|
||||||
|
struct Key;
|
||||||
|
} // namespace Cache
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
class AuthSession;
|
class AuthSession;
|
||||||
class mtpFileLoader;
|
class mtpFileLoader;
|
||||||
|
|
||||||
@ -173,6 +179,7 @@ public:
|
|||||||
void setMimeString(const QString &mime);
|
void setMimeString(const QString &mime);
|
||||||
|
|
||||||
MediaKey mediaKey() const;
|
MediaKey mediaKey() const;
|
||||||
|
Storage::Cache::Key cacheKey() const;
|
||||||
|
|
||||||
static QString ComposeNameString(
|
static QString ComposeNameString(
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
|
@ -312,22 +312,20 @@ bool MediaPhoto::updateInlineResultMedia(const MTPMessageMedia &media) {
|
|||||||
if (media.type() != mtpc_messageMediaPhoto) {
|
if (media.type() != mtpc_messageMediaPhoto) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto &photo = media.c_messageMediaPhoto();
|
auto &data = media.c_messageMediaPhoto();
|
||||||
if (photo.has_photo() && !photo.has_ttl_seconds()) {
|
if (data.has_photo() && !data.has_ttl_seconds()) {
|
||||||
if (auto existing = Auth().data().photo(photo.vphoto)) {
|
const auto photo = Auth().data().photo(data.vphoto);
|
||||||
if (existing == _photo) {
|
if (photo == _photo) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// collect data
|
photo->collectLocalData(_photo);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(("API Error: "
|
LOG(("API Error: "
|
||||||
"Got MTPMessageMediaPhoto without photo "
|
"Got MTPMessageMediaPhoto without photo "
|
||||||
"or with ttl_seconds in updateInlineResultMedia()"));
|
"or with ttl_seconds in updateInlineResultMedia()"));
|
||||||
}
|
}
|
||||||
// Can return false if we collect the data.
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
@ -347,6 +345,20 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
|||||||
if (photo.type() != mtpc_photo) {
|
if (photo.type() != mtpc_photo) {
|
||||||
return false;
|
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 &sizes = photo.c_photo().vsizes.v;
|
||||||
auto max = 0;
|
auto max = 0;
|
||||||
const MTPDfileLocation *maxLocation = 0;
|
const MTPDfileLocation *maxLocation = 0;
|
||||||
@ -369,23 +381,24 @@ bool MediaPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
|||||||
if (!loc || loc->type() != mtpc_fileLocation) {
|
if (!loc || loc->type() != mtpc_fileLocation) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const auto &location = loc->c_fileLocation();
|
||||||
if (size == 's') {
|
if (size == 's') {
|
||||||
Local::writeImage(storageKey(loc->c_fileLocation()), _photo->thumb);
|
saveImageToCache(location, _photo->thumb);
|
||||||
} else if (size == 'm') {
|
} else if (size == 'm') {
|
||||||
Local::writeImage(storageKey(loc->c_fileLocation()), _photo->medium);
|
saveImageToCache(location, _photo->medium);
|
||||||
} else if (size == 'x' && max < 1) {
|
} else if (size == 'x' && max < 1) {
|
||||||
max = 1;
|
max = 1;
|
||||||
maxLocation = &loc->c_fileLocation();
|
maxLocation = &location;
|
||||||
} else if (size == 'y' && max < 2) {
|
} else if (size == 'y' && max < 2) {
|
||||||
max = 2;
|
max = 2;
|
||||||
maxLocation = &loc->c_fileLocation();
|
maxLocation = &location;
|
||||||
//} else if (size == 'w' && max < 3) {
|
//} else if (size == 'w' && max < 3) {
|
||||||
// max = 3;
|
// max = 3;
|
||||||
// maxLocation = &loc->c_fileLocation();
|
// maxLocation = &loc->c_fileLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxLocation) {
|
if (maxLocation) {
|
||||||
Local::writeImage(storageKey(*maxLocation), _photo->full);
|
saveImageToCache(*maxLocation, _photo->full);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -637,13 +650,6 @@ bool MediaFile::updateSentMedia(const MTPMessageMedia &media) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Auth().data().documentConvert(_document, data.vdocument);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,13 +111,29 @@ void PhotoData::forget() {
|
|||||||
|
|
||||||
ImagePtr PhotoData::makeReplyPreview(Data::FileOrigin origin) {
|
ImagePtr PhotoData::makeReplyPreview(Data::FileOrigin origin) {
|
||||||
if (replyPreview->isNull() && !thumb->isNull()) {
|
if (replyPreview->isNull() && !thumb->isNull()) {
|
||||||
if (thumb->loaded()) {
|
const auto previewFromImage = [&](const ImagePtr &image) {
|
||||||
int w = thumb->width(), h = thumb->height();
|
if (!image->loaded()) {
|
||||||
|
image->load(origin);
|
||||||
|
return ImagePtr();
|
||||||
|
}
|
||||||
|
int w = image->width(), h = image->height();
|
||||||
if (w <= 0) w = 1;
|
if (w <= 0) w = 1;
|
||||||
if (h <= 0) h = 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 {
|
} else {
|
||||||
thumb->load(origin);
|
return previewFromImage(thumb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return replyPreview;
|
return replyPreview;
|
||||||
@ -130,6 +146,21 @@ MTPInputPhoto PhotoData::mtpInput() const {
|
|||||||
MTP_bytes(fileReference));
|
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 {
|
void PhotoOpenClickHandler::onClickImpl() const {
|
||||||
Messenger::Instance().showPhoto(this);
|
Messenger::Instance().showPhoto(this);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,12 @@ public:
|
|||||||
|
|
||||||
MTPInputPhoto mtpInput() const;
|
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;
|
PhotoId id = 0;
|
||||||
uint64 access = 0;
|
uint64 access = 0;
|
||||||
QByteArray fileReference;
|
QByteArray fileReference;
|
||||||
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "history/view/history_view_element.h"
|
#include "history/view/history_view_element.h"
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
#include "storage/storage_encrypted_file.h"
|
||||||
#include "boxes/abstract_box.h"
|
#include "boxes/abstract_box.h"
|
||||||
#include "passport/passport_form_controller.h"
|
#include "passport/passport_form_controller.h"
|
||||||
#include "data/data_media_types.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(not_null<AuthSession*> session)
|
||||||
: _session(session)
|
: _session(session)
|
||||||
|
, _cache(Local::cachePath(), Local::cacheSettings())
|
||||||
, _groups(this)
|
, _groups(this)
|
||||||
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
, _unmuteByFinishedTimer([=] { unmuteByFinished(); }) {
|
||||||
|
_cache.open(Local::cacheKey());
|
||||||
|
|
||||||
setupContactViewsViewer();
|
setupContactViewsViewer();
|
||||||
setupChannelLeavingViewer();
|
setupChannelLeavingViewer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Storage::Cache::Database &Session::cache() {
|
||||||
|
return _cache;
|
||||||
|
}
|
||||||
|
|
||||||
void Session::startExport(PeerData *peer) {
|
void Session::startExport(PeerData *peer) {
|
||||||
startExport(peer ? peer->input : MTP_inputPeerEmpty());
|
startExport(peer ? peer->input : MTP_inputPeerEmpty());
|
||||||
}
|
}
|
||||||
@ -1061,6 +1069,7 @@ void Session::documentConvert(
|
|||||||
Unexpected("Type in Session::documentConvert().");
|
Unexpected("Type in Session::documentConvert().");
|
||||||
}();
|
}();
|
||||||
const auto oldKey = original->mediaKey();
|
const auto oldKey = original->mediaKey();
|
||||||
|
const auto oldCacheKey = original->cacheKey();
|
||||||
const auto idChanged = (original->id != id);
|
const auto idChanged = (original->id != id);
|
||||||
const auto sentSticker = idChanged && (original->sticker() != nullptr);
|
const auto sentSticker = idChanged && (original->sticker() != nullptr);
|
||||||
if (idChanged) {
|
if (idChanged) {
|
||||||
@ -1083,14 +1092,7 @@ void Session::documentConvert(
|
|||||||
}
|
}
|
||||||
documentApplyFields(original, data);
|
documentApplyFields(original, data);
|
||||||
if (idChanged) {
|
if (idChanged) {
|
||||||
const auto newKey = original->mediaKey();
|
cache().moveIfEmpty(oldCacheKey, original->cacheKey());
|
||||||
if (oldKey != newKey) {
|
|
||||||
if (original->isVoiceMessage()) {
|
|
||||||
Local::copyAudio(oldKey, newKey);
|
|
||||||
} else if (original->sticker() || original->isAnimation()) {
|
|
||||||
Local::copyStickerImage(oldKey, newKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (savedGifs().indexOf(original) >= 0) {
|
if (savedGifs().indexOf(original) >= 0) {
|
||||||
Local::writeSavedGifs();
|
Local::writeSavedGifs();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "storage/cache/storage_cache_database.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "data/data_groups.h"
|
#include "data/data_groups.h"
|
||||||
@ -71,6 +72,8 @@ public:
|
|||||||
TimeMs rememberFor);
|
TimeMs rememberFor);
|
||||||
void forgetPassportCredentials();
|
void forgetPassportCredentials();
|
||||||
|
|
||||||
|
Storage::Cache::Database &cache();
|
||||||
|
|
||||||
[[nodiscard]] base::Variable<bool> &contactsLoaded() {
|
[[nodiscard]] base::Variable<bool> &contactsLoaded() {
|
||||||
return _contactsLoaded;
|
return _contactsLoaded;
|
||||||
}
|
}
|
||||||
@ -520,6 +523,8 @@ private:
|
|||||||
|
|
||||||
not_null<AuthSession*> _session;
|
not_null<AuthSession*> _session;
|
||||||
|
|
||||||
|
Storage::Cache::Database _cache;
|
||||||
|
|
||||||
std::unique_ptr<Export::ControllerWrap> _export;
|
std::unique_ptr<Export::ControllerWrap> _export;
|
||||||
std::unique_ptr<Export::View::PanelController> _exportPanel;
|
std::unique_ptr<Export::View::PanelController> _exportPanel;
|
||||||
rpl::event_stream<Export::View::PanelController*> _exportViewChanges;
|
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 "data/data_document.h"
|
||||||
#include "ui/widgets/input_fields.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() {
|
void AudioMsgId::setTypeFromAudio() {
|
||||||
if (_audio->isVoiceMessage() || _audio->isVideoMessage()) {
|
if (_audio->isVoiceMessage() || _audio->isVideoMessage()) {
|
||||||
|
@ -10,6 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "base/value_ordering.h"
|
#include "base/value_ordering.h"
|
||||||
#include "ui/text/text.h" // For QFIXED_MAX
|
#include "ui/text/text.h" // For QFIXED_MAX
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Cache {
|
||||||
|
struct Key;
|
||||||
|
} // namespace Cache
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
using HistoryItemsList = std::vector<not_null<HistoryItem*>>;
|
using HistoryItemsList = std::vector<not_null<HistoryItem*>>;
|
||||||
|
|
||||||
@ -17,6 +23,9 @@ namespace Ui {
|
|||||||
class InputField;
|
class InputField;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
class StorageImageLocation;
|
||||||
|
class WebFileLocation;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
struct UploadState {
|
struct UploadState {
|
||||||
@ -27,6 +36,11 @@ struct UploadState {
|
|||||||
bool waitingForAlbum = false;
|
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
|
} // namespace Data
|
||||||
|
|
||||||
struct MessageGroupId {
|
struct MessageGroupId {
|
||||||
|
@ -4320,7 +4320,14 @@ HistoryInvoice::HistoryInvoice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInvoice::fillFromData(not_null<Data::Invoice*> invoice) {
|
void HistoryInvoice::fillFromData(not_null<Data::Invoice*> invoice) {
|
||||||
// init attach
|
if (invoice->photo) {
|
||||||
|
_attach = std::make_unique<HistoryPhoto>(
|
||||||
|
_parent,
|
||||||
|
_parent->data(),
|
||||||
|
invoice->photo);
|
||||||
|
} else {
|
||||||
|
_attach = nullptr;
|
||||||
|
}
|
||||||
auto labelText = [&] {
|
auto labelText = [&] {
|
||||||
if (invoice->receiptMsgId) {
|
if (invoice->receiptMsgId) {
|
||||||
if (invoice->isTest) {
|
if (invoice->isTest) {
|
||||||
|
@ -794,7 +794,7 @@ MainWindow::TempDirState MainWindow::localStorageState() {
|
|||||||
if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
|
if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
|
||||||
return TempDirRemoving;
|
return TempDirRemoving;
|
||||||
}
|
}
|
||||||
return (Local::hasImages() || Local::hasStickers() || Local::hasWebFiles() || Local::hasAudios()) ? TempDirExists : TempDirEmpty;
|
return TempDirEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::tempDirDelete(int task) {
|
void MainWindow::tempDirDelete(int task) {
|
||||||
|
@ -1226,6 +1226,10 @@ void Messenger::loggedOut() {
|
|||||||
w->setupIntro();
|
w->setupIntro();
|
||||||
}
|
}
|
||||||
App::histories().clear();
|
App::histories().clear();
|
||||||
|
if (const auto session = authSession()) {
|
||||||
|
session->data().cache().close();
|
||||||
|
session->data().cache().clear();
|
||||||
|
}
|
||||||
authSessionDestroy();
|
authSessionDestroy();
|
||||||
if (_mediaView) {
|
if (_mediaView) {
|
||||||
hideMediaView();
|
hideMediaView();
|
||||||
|
@ -56,6 +56,9 @@ public:
|
|||||||
void write(QDataStream &to) const {
|
void write(QDataStream &to) const {
|
||||||
to.writeRawData(reinterpret_cast<const char*>(_key.data()), _key.size());
|
to.writeRawData(reinterpret_cast<const char*>(_key.data()), _key.size());
|
||||||
}
|
}
|
||||||
|
bytes::const_span data() const {
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
bool equals(const std::shared_ptr<AuthKey> &other) const {
|
bool equals(const std::shared_ptr<AuthKey> &other) const {
|
||||||
return other ? (_key == other->_key) : false;
|
return other ? (_key == other->_key) : false;
|
||||||
|
@ -863,7 +863,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
|||||||
bool selected = (selection == FullSelection);
|
bool selected = (selection == FullSelection);
|
||||||
|
|
||||||
_data->automaticLoad(parent()->fullId(), parent());
|
_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) {
|
if (displayLoading) {
|
||||||
ensureRadial();
|
ensureRadial();
|
||||||
@ -1024,8 +1024,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
|||||||
TextState Document::getState(
|
TextState Document::getState(
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const {
|
StateRequest request) const {
|
||||||
const auto loaded = _data->loaded()
|
const auto loaded = _data->loaded();
|
||||||
|| Local::willStickerImageLoad(_data->mediaKey());
|
|
||||||
const auto wthumb = withThumb();
|
const auto wthumb = withThumb();
|
||||||
|
|
||||||
if (_data->isAudioFile()) {
|
if (_data->isAudioFile()) {
|
||||||
|
@ -2338,16 +2338,12 @@ void FormController::fillDownloadedFile(
|
|||||||
if (!i->uploadData) {
|
if (!i->uploadData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Local::writeImage(
|
const auto &bytes = i->uploadData->bytes;
|
||||||
StorageKey(
|
Auth().data().cache().put(
|
||||||
storageMix32To64(
|
Data::DocumentCacheKey(destination.dcId, destination.id),
|
||||||
SecureFileLocation,
|
QByteArray(
|
||||||
destination.dcId),
|
reinterpret_cast<const char*>(bytes.data()),
|
||||||
destination.id),
|
bytes.size()));
|
||||||
StorageImageSaved(QByteArray::fromRawData(
|
|
||||||
reinterpret_cast<const char*>(
|
|
||||||
i->uploadData->bytes.data()),
|
|
||||||
i->uploadData->bytes.size())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FormController::parseValue(
|
auto FormController::parseValue(
|
||||||
|
@ -64,20 +64,20 @@ void Database::remove(const Key &key, FnMut<void(Error)> done) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::copy(
|
void Database::putIfEmpty(
|
||||||
const Key &from,
|
const Key &key,
|
||||||
const Key &to,
|
QByteArray value,
|
||||||
FnMut<void(Error)> done) {
|
FnMut<void(Error)> done) {
|
||||||
_wrapped.with([
|
_wrapped.with([
|
||||||
from,
|
key,
|
||||||
to,
|
value = std::move(value),
|
||||||
done = std::move(done)
|
done = std::move(done)
|
||||||
](Implementation &unwrapped) mutable {
|
](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 &from,
|
||||||
const Key &to,
|
const Key &to,
|
||||||
FnMut<void(Error)> done) {
|
FnMut<void(Error)> done) {
|
||||||
@ -86,7 +86,20 @@ void Database::move(
|
|||||||
to,
|
to,
|
||||||
done = std::move(done)
|
done = std::move(done)
|
||||||
](Implementation &unwrapped) mutable {
|
](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<void(Error)> done) {
|
||||||
|
_wrapped.with([
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
done = std::move(done)
|
||||||
|
](Implementation &unwrapped) mutable {
|
||||||
|
unwrapped.moveIfEmpty(from, to, std::move(done));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,11 +35,15 @@ public:
|
|||||||
void get(const Key &key, FnMut<void(QByteArray)> done);
|
void get(const Key &key, FnMut<void(QByteArray)> done);
|
||||||
void remove(const Key &key, FnMut<void(Error)> done = nullptr);
|
void remove(const Key &key, FnMut<void(Error)> done = nullptr);
|
||||||
|
|
||||||
void copy(
|
void putIfEmpty(
|
||||||
|
const Key &key,
|
||||||
|
QByteArray value,
|
||||||
|
FnMut<void(Error)> done = nullptr);
|
||||||
|
void copyIfEmpty(
|
||||||
const Key &from,
|
const Key &from,
|
||||||
const Key &to,
|
const Key &to,
|
||||||
FnMut<void(Error)> done = nullptr);
|
FnMut<void(Error)> done = nullptr);
|
||||||
void move(
|
void moveIfEmpty(
|
||||||
const Key &from,
|
const Key &from,
|
||||||
const Key &to,
|
const Key &to,
|
||||||
FnMut<void(Error)> done = nullptr);
|
FnMut<void(Error)> done = nullptr);
|
||||||
|
@ -622,9 +622,7 @@ void DatabaseObject::put(
|
|||||||
QByteArray value,
|
QByteArray value,
|
||||||
FnMut<void(Error)> done) {
|
FnMut<void(Error)> done) {
|
||||||
if (value.isEmpty()) {
|
if (value.isEmpty()) {
|
||||||
remove(key, [done = std::move(done)](Error error) mutable {
|
remove(key, std::move(done));
|
||||||
done(error);
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_removing.erase(key);
|
_removing.erase(key);
|
||||||
@ -645,10 +643,12 @@ void DatabaseObject::put(
|
|||||||
const auto result = data.open(path, File::Mode::Write, _key);
|
const auto result = data.open(path, File::Mode::Write, _key);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case File::Result::Failed:
|
case File::Result::Failed:
|
||||||
|
remove(key, nullptr);
|
||||||
invokeCallback(done, ioError(path));
|
invokeCallback(done, ioError(path));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case File::Result::LockFailed:
|
case File::Result::LockFailed:
|
||||||
|
remove(key, nullptr);
|
||||||
invokeCallback(done, Error{ Error::Type::LockFailed, path });
|
invokeCallback(done, Error{ Error::Type::LockFailed, path });
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -800,8 +800,10 @@ void DatabaseObject::get(const Key &key, FnMut<void(QByteArray)> done) {
|
|||||||
|
|
||||||
auto result = readValueData(entry.place, entry.size);
|
auto result = readValueData(entry.place, entry.size);
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
|
remove(key, nullptr);
|
||||||
invokeCallback(done, QByteArray());
|
invokeCallback(done, QByteArray());
|
||||||
} else if (CountChecksum(bytes::make_span(result)) != entry.checksum) {
|
} else if (CountChecksum(bytes::make_span(result)) != entry.checksum) {
|
||||||
|
remove(key, nullptr);
|
||||||
invokeCallback(done, QByteArray());
|
invokeCallback(done, QByteArray());
|
||||||
} else {
|
} else {
|
||||||
invokeCallback(done, std::move(result));
|
invokeCallback(done, std::move(result));
|
||||||
@ -856,22 +858,41 @@ void DatabaseObject::remove(const Key &key, FnMut<void(Error)> done) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseObject::copy(
|
void DatabaseObject::putIfEmpty(
|
||||||
|
const Key &key,
|
||||||
|
QByteArray value,
|
||||||
|
FnMut<void(Error)> 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 &from,
|
||||||
const Key &to,
|
const Key &to,
|
||||||
FnMut<void(Error)> done) {
|
FnMut<void(Error)> done) {
|
||||||
|
if (_map.find(to) != end(_map)) {
|
||||||
|
invokeCallback(done, Error::NoError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
get(from, [&](QByteArray value) {
|
get(from, [&](QByteArray value) {
|
||||||
put(to, value, std::move(done));
|
put(to, value, std::move(done));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseObject::move(
|
void DatabaseObject::moveIfEmpty(
|
||||||
const Key &from,
|
const Key &from,
|
||||||
const Key &to,
|
const Key &to,
|
||||||
FnMut<void(Error)> done) {
|
FnMut<void(Error)> done) {
|
||||||
|
if (_map.find(to) != end(_map)) {
|
||||||
|
invokeCallback(done, Error::NoError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto i = _map.find(from);
|
const auto i = _map.find(from);
|
||||||
if (i == _map.end()) {
|
if (i == _map.end()) {
|
||||||
put(to, QByteArray(), std::move(done));
|
invokeCallback(done, Error::NoError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_removing.emplace(from);
|
_removing.emplace(from);
|
||||||
|
@ -37,8 +37,18 @@ public:
|
|||||||
void get(const Key &key, FnMut<void(QByteArray)> done);
|
void get(const Key &key, FnMut<void(QByteArray)> done);
|
||||||
void remove(const Key &key, FnMut<void(Error)> done);
|
void remove(const Key &key, FnMut<void(Error)> done);
|
||||||
|
|
||||||
void copy(const Key &from, const Key &to, FnMut<void(Error)> done);
|
void putIfEmpty(
|
||||||
void move(const Key &from, const Key &to, FnMut<void(Error)> done);
|
const Key &key,
|
||||||
|
QByteArray value,
|
||||||
|
FnMut<void(Error)> done);
|
||||||
|
void copyIfEmpty(
|
||||||
|
const Key &from,
|
||||||
|
const Key &to,
|
||||||
|
FnMut<void(Error)> done);
|
||||||
|
void moveIfEmpty(
|
||||||
|
const Key &from,
|
||||||
|
const Key &to,
|
||||||
|
FnMut<void(Error)> done);
|
||||||
|
|
||||||
void clear(FnMut<void(Error)> done);
|
void clear(FnMut<void(Error)> done);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "storage/file_download.h"
|
#include "storage/file_download.h"
|
||||||
|
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
@ -36,6 +37,7 @@ void Downloader::clearPriorities() {
|
|||||||
|
|
||||||
void Downloader::requestedAmountIncrement(MTP::DcId dcId, int index, int amount) {
|
void Downloader::requestedAmountIncrement(MTP::DcId dcId, int index, int amount) {
|
||||||
Expects(index >= 0 && index < MTP::kDownloadSessionsCount);
|
Expects(index >= 0 && index < MTP::kDownloadSessionsCount);
|
||||||
|
|
||||||
auto it = _requestedBytesAmount.find(dcId);
|
auto it = _requestedBytesAmount.find(dcId);
|
||||||
if (it == _requestedBytesAmount.cend()) {
|
if (it == _requestedBytesAmount.cend()) {
|
||||||
it = _requestedBytesAmount.emplace(dcId, RequestedInDc { { 0 } }).first;
|
it = _requestedBytesAmount.emplace(dcId, RequestedInDc { { 0 } }).first;
|
||||||
@ -206,16 +208,16 @@ void FileLoader::pause() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileLoader::~FileLoader() {
|
FileLoader::~FileLoader() {
|
||||||
if (_localTaskId) {
|
|
||||||
Local::cancelTask(_localTaskId);
|
|
||||||
}
|
|
||||||
removeFromQueue();
|
removeFromQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &imageFormat, const QPixmap &imagePixmap) {
|
void FileLoader::localLoaded(
|
||||||
_localTaskId = 0;
|
const StorageImageSaved &result,
|
||||||
|
const QByteArray &imageFormat,
|
||||||
|
const QPixmap &imagePixmap) {
|
||||||
|
_localLoading.kill();
|
||||||
if (result.data.isEmpty()) {
|
if (result.data.isEmpty()) {
|
||||||
_localStatus = LocalFailed;
|
_localStatus = LocalStatus::NotFound;
|
||||||
start(true);
|
start(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -224,7 +226,7 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
|
|||||||
_imageFormat = imageFormat;
|
_imageFormat = imageFormat;
|
||||||
_imagePixmap = imagePixmap;
|
_imagePixmap = imagePixmap;
|
||||||
}
|
}
|
||||||
_localStatus = LocalLoaded;
|
_localStatus = LocalStatus::Loaded;
|
||||||
if (!_filename.isEmpty() && _toCache == LoadToCacheAsWell) {
|
if (!_filename.isEmpty() && _toCache == LoadToCacheAsWell) {
|
||||||
if (!_fileIsOpen) _fileIsOpen = _file.open(QIODevice::WriteOnly);
|
if (!_fileIsOpen) _fileIsOpen = _file.open(QIODevice::WriteOnly);
|
||||||
if (!_fileIsOpen) {
|
if (!_fileIsOpen) {
|
||||||
@ -241,7 +243,8 @@ void FileLoader::localLoaded(const StorageImageSaved &result, const QByteArray &
|
|||||||
if (_fileIsOpen) {
|
if (_fileIsOpen) {
|
||||||
_file.close();
|
_file.close();
|
||||||
_fileIsOpen = false;
|
_fileIsOpen = false;
|
||||||
Platform::File::PostprocessDownloaded(QFileInfo(_file).absoluteFilePath());
|
Platform::File::PostprocessDownloaded(
|
||||||
|
QFileInfo(_file).absoluteFilePath());
|
||||||
}
|
}
|
||||||
_downloader->taskFinished().notify();
|
_downloader->taskFinished().notify();
|
||||||
|
|
||||||
@ -254,9 +257,9 @@ void FileLoader::start(bool loadFirst, bool prior) {
|
|||||||
if (_paused) {
|
if (_paused) {
|
||||||
_paused = false;
|
_paused = false;
|
||||||
}
|
}
|
||||||
if (_finished || tryLoadLocal()) return;
|
if (_finished || tryLoadLocal()) {
|
||||||
|
return;
|
||||||
if (_fromCloud == LoadFromLocalOnly) {
|
} else if (_fromCloud == LoadFromLocalOnly) {
|
||||||
cancel();
|
cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -357,6 +360,74 @@ void FileLoader::start(bool loadFirst, bool prior) {
|
|||||||
return startLoading(loadFirst, 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() {
|
void FileLoader::cancel() {
|
||||||
cancel(false);
|
cancel(false);
|
||||||
}
|
}
|
||||||
@ -872,29 +943,19 @@ bool mtpFileLoader::feedPart(int offset, bytes::const_span buffer) {
|
|||||||
}
|
}
|
||||||
removeFromQueue();
|
removeFromQueue();
|
||||||
|
|
||||||
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
|
if (_localStatus == LocalStatus::NotFound) {
|
||||||
if (_urlLocation) {
|
if (_locationType != UnknownFileLocation
|
||||||
Local::writeImage(storageKey(*_urlLocation), StorageImageSaved(_data));
|
&& !_filename.isEmpty()) {
|
||||||
} else if (_locationType != UnknownFileLocation) { // audio, video, document
|
Local::writeFileLocation(
|
||||||
auto mkey = mediaKey(_locationType, _dcId, _id);
|
mediaKey(_locationType, _dcId, _id),
|
||||||
if (!_filename.isEmpty()) {
|
FileLocation(_filename));
|
||||||
Local::writeFileLocation(mkey, 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);
|
makeRequest(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mtpFileLoader::tryLoadLocal() {
|
base::optional<Storage::Cache::Key> mtpFileLoader::cacheKey() const {
|
||||||
if (_localStatus == LocalNotFound || _localStatus == LocalLoaded || _localStatus == LocalFailed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (_localStatus == LocalLoading) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_urlLocation) {
|
if (_urlLocation) {
|
||||||
_localTaskId = Local::startImageLoad(storageKey(*_urlLocation), this);
|
return Data::WebDocumentCacheKey(*_urlLocation);
|
||||||
} else if (_location) {
|
} else if (_location) {
|
||||||
_localTaskId = Local::startImageLoad(storageKey(*_location), this);
|
return Data::StorageCacheKey(*_location);
|
||||||
} else {
|
} else if (_toCache == LoadToCacheAsWell) {
|
||||||
if (_toCache == LoadToCacheAsWell) {
|
return Data::DocumentCacheKey(_dcId, _id);
|
||||||
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 base::none;
|
||||||
emit progress(this);
|
|
||||||
|
|
||||||
if (_localStatus != LocalNotTried) {
|
|
||||||
return _finished;
|
|
||||||
} else if (_localTaskId) {
|
|
||||||
_localStatus = LocalLoading;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_localStatus = LocalNotFound;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtpFileLoader::~mtpFileLoader() {
|
mtpFileLoader::~mtpFileLoader() {
|
||||||
@ -1129,8 +1162,10 @@ void webFileLoader::onFinished(const QByteArray &data) {
|
|||||||
}
|
}
|
||||||
removeFromQueue();
|
removeFromQueue();
|
||||||
|
|
||||||
if (_localStatus == LocalNotFound || _localStatus == LocalFailed) {
|
if (_localStatus == LocalStatus::NotFound) {
|
||||||
Local::writeWebFile(_url, _data);
|
if (const auto key = cacheKey()) {
|
||||||
|
Auth().data().cache().put(*key, _data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_downloader->taskFinished().notify();
|
_downloader->taskFinished().notify();
|
||||||
|
|
||||||
@ -1143,23 +1178,8 @@ void webFileLoader::onError() {
|
|||||||
cancel(true);
|
cancel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool webFileLoader::tryLoadLocal() {
|
base::optional<Storage::Cache::Key> webFileLoader::cacheKey() const {
|
||||||
if (_localStatus == LocalNotFound || _localStatus == LocalLoaded || _localStatus == LocalFailed) {
|
return Data::UrlCacheKey(_url);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void webFileLoader::cancelRequests() {
|
void webFileLoader::cancelRequests() {
|
||||||
|
@ -8,10 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/observer.h"
|
#include "base/observer.h"
|
||||||
#include "storage/localimageloader.h" // for TaskId
|
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "base/binary_guard.h"
|
||||||
|
|
||||||
namespace Storage {
|
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 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
|
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 mtpFileLoader;
|
||||||
class webFileLoader;
|
class webFileLoader;
|
||||||
|
|
||||||
@ -119,7 +114,7 @@ public:
|
|||||||
return _inQueue || _paused;
|
return _inQueue || _paused;
|
||||||
}
|
}
|
||||||
bool loadingLocal() const {
|
bool loadingLocal() const {
|
||||||
return (_localStatus == LocalLoading);
|
return (_localStatus == LocalStatus::Loading);
|
||||||
}
|
}
|
||||||
bool autoLoading() const {
|
bool autoLoading() const {
|
||||||
return _autoLoading;
|
return _autoLoading;
|
||||||
@ -129,15 +124,37 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~FileLoader();
|
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:
|
signals:
|
||||||
void progress(FileLoader *loader);
|
void progress(FileLoader *loader);
|
||||||
void failed(FileLoader *loader, bool started);
|
void failed(FileLoader *loader, bool started);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class LocalStatus {
|
||||||
|
NotTried,
|
||||||
|
NotFound,
|
||||||
|
Loading,
|
||||||
|
Loaded,
|
||||||
|
};
|
||||||
|
|
||||||
void readImage(const QSize &shrinkBox) const;
|
void readImage(const QSize &shrinkBox) const;
|
||||||
|
|
||||||
|
bool tryLoadLocal();
|
||||||
|
void loadLocal(const Storage::Cache::Key &key);
|
||||||
|
virtual base::optional<Storage::Cache::Key> 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<Storage::Downloader*> _downloader;
|
not_null<Storage::Downloader*> _downloader;
|
||||||
FileLoader *_prev = nullptr;
|
FileLoader *_prev = nullptr;
|
||||||
FileLoader *_next = nullptr;
|
FileLoader *_next = nullptr;
|
||||||
@ -149,17 +166,7 @@ protected:
|
|||||||
bool _inQueue = false;
|
bool _inQueue = false;
|
||||||
bool _finished = false;
|
bool _finished = false;
|
||||||
bool _cancelled = false;
|
bool _cancelled = false;
|
||||||
mutable LocalLoadStatus _localStatus = LocalNotTried;
|
mutable LocalStatus _localStatus = LocalStatus::NotTried;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
QString _filename;
|
QString _filename;
|
||||||
QFile _file;
|
QFile _file;
|
||||||
@ -173,7 +180,7 @@ protected:
|
|||||||
int32 _size;
|
int32 _size;
|
||||||
LocationType _locationType;
|
LocationType _locationType;
|
||||||
|
|
||||||
TaskId _localTaskId = 0;
|
base::binary_guard _localLoading;
|
||||||
mutable QByteArray _imageFormat;
|
mutable QByteArray _imageFormat;
|
||||||
mutable QPixmap _imagePixmap;
|
mutable QPixmap _imagePixmap;
|
||||||
|
|
||||||
@ -238,8 +245,7 @@ private:
|
|||||||
int limit = 0;
|
int limit = 0;
|
||||||
QByteArray hash;
|
QByteArray hash;
|
||||||
};
|
};
|
||||||
|
base::optional<Storage::Cache::Key> cacheKey() const override;
|
||||||
bool tryLoadLocal() override;
|
|
||||||
void cancelRequests() override;
|
void cancelRequests() override;
|
||||||
|
|
||||||
int partSize() const;
|
int partSize() const;
|
||||||
@ -307,32 +313,28 @@ class webFileLoader : public FileLoader {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
webFileLoader(
|
||||||
|
const QString &url,
|
||||||
|
const QString &to,
|
||||||
|
LoadFromCloudSetting fromCloud,
|
||||||
|
bool autoLoading);
|
||||||
|
|
||||||
webFileLoader(const QString &url, const QString &to, LoadFromCloudSetting fromCloud, bool autoLoading);
|
int32 currentOffset(bool includeSkipped = false) const override;
|
||||||
|
|
||||||
virtual int32 currentOffset(bool includeSkipped = false) const;
|
|
||||||
virtual webFileLoader *webLoader() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
virtual const webFileLoader *webLoader() const {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onProgress(qint64 already, qint64 size);
|
void onProgress(qint64 already, qint64 size);
|
||||||
void onFinished(const QByteArray &data);
|
void onFinished(const QByteArray &data);
|
||||||
void onError();
|
void onError();
|
||||||
|
|
||||||
virtual void stop() {
|
void stop() override {
|
||||||
cancelRequests();
|
cancelRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
~webFileLoader();
|
~webFileLoader();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void cancelRequests() override;
|
||||||
virtual void cancelRequests();
|
base::optional<Storage::Cache::Key> cacheKey() const override;
|
||||||
virtual bool tryLoadLocal();
|
bool loadPart() override;
|
||||||
virtual bool loadPart();
|
|
||||||
|
|
||||||
QString _url;
|
QString _url;
|
||||||
|
|
||||||
|
@ -126,6 +126,9 @@ void Uploader::uploadMedia(const FullMsgId &msgId, const SendMediaReady &media)
|
|||||||
: Auth().data().document(media.document, media.photoThumbs.begin().value());
|
: Auth().data().document(media.document, media.photoThumbs.begin().value());
|
||||||
if (!media.data.isEmpty()) {
|
if (!media.data.isEmpty()) {
|
||||||
document->setData(media.data);
|
document->setData(media.data);
|
||||||
|
if (document->saveToCache()) {
|
||||||
|
Auth().data().cache().put(document->cacheKey(), media.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!media.file.isEmpty()) {
|
if (!media.file.isEmpty()) {
|
||||||
document->setLocation(FileLocation(media.file));
|
document->setLocation(FileLocation(media.file));
|
||||||
@ -148,6 +151,11 @@ void Uploader::upload(
|
|||||||
document->uploadingData = std::make_unique<Data::UploadState>(document->size);
|
document->uploadingData = std::make_unique<Data::UploadState>(document->size);
|
||||||
if (!file->content.isEmpty()) {
|
if (!file->content.isEmpty()) {
|
||||||
document->setData(file->content);
|
document->setData(file->content);
|
||||||
|
if (document->saveToCache()) {
|
||||||
|
Auth().data().cache().put(
|
||||||
|
document->cacheKey(),
|
||||||
|
file->content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!file->filepath.isEmpty()) {
|
if (!file->filepath.isEmpty()) {
|
||||||
document->setLocation(FileLocation(file->filepath));
|
document->setLocation(FileLocation(file->filepath));
|
||||||
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include "storage/serialize_document.h"
|
#include "storage/serialize_document.h"
|
||||||
#include "storage/serialize_common.h"
|
#include "storage/serialize_common.h"
|
||||||
|
#include "storage/storage_encrypted_file.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "boxes/send_files_box.h"
|
#include "boxes/send_files_box.h"
|
||||||
@ -65,7 +66,7 @@ QString toFilePart(FileKey val) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString _basePath, _userBasePath;
|
QString _basePath, _userBasePath, _userDbPath;
|
||||||
|
|
||||||
bool _started = false;
|
bool _started = false;
|
||||||
internal::Manager *_manager = nullptr;
|
internal::Manager *_manager = nullptr;
|
||||||
@ -620,9 +621,6 @@ typedef QMap<QString, FileLocationPair> FileLocationPairs;
|
|||||||
FileLocationPairs _fileLocationPairs;
|
FileLocationPairs _fileLocationPairs;
|
||||||
typedef QMap<MediaKey, MediaKey> FileLocationAliases;
|
typedef QMap<MediaKey, MediaKey> FileLocationAliases;
|
||||||
FileLocationAliases _fileLocationAliases;
|
FileLocationAliases _fileLocationAliases;
|
||||||
typedef QMap<QString, FileDesc> WebFilesMap;
|
|
||||||
WebFilesMap _webFilesMap;
|
|
||||||
uint64 _storageWebFilesSize = 0;
|
|
||||||
FileKey _locationsKey = 0, _reportSpamStatusesKey = 0, _trustedBotsKey = 0;
|
FileKey _locationsKey = 0, _reportSpamStatusesKey = 0, _trustedBotsKey = 0;
|
||||||
|
|
||||||
using TrustedBots = OrderedSet<uint64>;
|
using TrustedBots = OrderedSet<uint64>;
|
||||||
@ -655,10 +653,6 @@ FileKey _exportSettingsKey = 0;
|
|||||||
FileKey _savedPeersKey = 0;
|
FileKey _savedPeersKey = 0;
|
||||||
FileKey _langPackKey = 0;
|
FileKey _langPackKey = 0;
|
||||||
|
|
||||||
typedef QMap<StorageKey, FileDesc> StorageMap;
|
|
||||||
StorageMap _imagesMap, _stickerImagesMap, _audiosMap;
|
|
||||||
qint64 _storageImagesSize = 0, _storageStickersSize = 0, _storageAudiosSize = 0;
|
|
||||||
|
|
||||||
bool _mapChanged = false;
|
bool _mapChanged = false;
|
||||||
int32 _oldMapVersion = 0, _oldSettingsVersion = 0;
|
int32 _oldMapVersion = 0, _oldSettingsVersion = 0;
|
||||||
|
|
||||||
@ -686,7 +680,7 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) {
|
|||||||
if (!_working()) return;
|
if (!_working()) return;
|
||||||
|
|
||||||
_manager->writingLocations();
|
_manager->writingLocations();
|
||||||
if (_fileLocations.isEmpty() && _webFilesMap.isEmpty()) {
|
if (_fileLocations.isEmpty()) {
|
||||||
if (_locationsKey) {
|
if (_locationsKey) {
|
||||||
clearKey(_locationsKey);
|
clearKey(_locationsKey);
|
||||||
_locationsKey = 0;
|
_locationsKey = 0;
|
||||||
@ -724,12 +718,6 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) {
|
|||||||
size += sizeof(quint64) * 2 + sizeof(quint64) * 2;
|
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);
|
EncryptedDescriptor data(size);
|
||||||
auto legacyTypeField = 0;
|
auto legacyTypeField = 0;
|
||||||
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
|
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 << 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);
|
FileWriteDescriptor file(_locationsKey);
|
||||||
file.writeEncrypted(data);
|
file.writeEncrypted(data);
|
||||||
}
|
}
|
||||||
@ -804,9 +787,6 @@ void _readLocations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!locations.stream.atEnd()) {
|
if (!locations.stream.atEnd()) {
|
||||||
_storageWebFilesSize = 0;
|
|
||||||
_webFilesMap.clear();
|
|
||||||
|
|
||||||
quint32 webLocationsCount;
|
quint32 webLocationsCount;
|
||||||
locations.stream >> webLocationsCount;
|
locations.stream >> webLocationsCount;
|
||||||
for (quint32 i = 0; i < webLocationsCount; ++i) {
|
for (quint32 i = 0; i < webLocationsCount; ++i) {
|
||||||
@ -814,8 +794,7 @@ void _readLocations() {
|
|||||||
quint64 key;
|
quint64 key;
|
||||||
qint32 size;
|
qint32 size;
|
||||||
locations.stream >> url >> key >> size;
|
locations.stream >> url >> key >> size;
|
||||||
_webFilesMap.insert(url, FileDesc(key, size));
|
clearKey(key, FileOption::User);
|
||||||
_storageWebFilesSize += size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2071,6 +2050,10 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
hashMd5(dataNameUtf8.constData(), dataNameUtf8.size(), dataNameHash);
|
hashMd5(dataNameUtf8.constData(), dataNameUtf8.size(), dataNameHash);
|
||||||
_dataNameKey = dataNameHash[0];
|
_dataNameKey = dataNameHash[0];
|
||||||
_userBasePath = _basePath + toFilePart(_dataNameKey) + QChar('/');
|
_userBasePath = _basePath + toFilePart(_dataNameKey) + QChar('/');
|
||||||
|
_userDbPath = _basePath
|
||||||
|
+ "user_" + cDataFile()
|
||||||
|
+ (cTestMode() ? "[test]" : "")
|
||||||
|
+ '/';
|
||||||
|
|
||||||
FileReadDescriptor mapData;
|
FileReadDescriptor mapData;
|
||||||
if (!readFile(mapData, qsl("map"))) {
|
if (!readFile(mapData, qsl("map"))) {
|
||||||
@ -2113,8 +2096,6 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
|
|
||||||
DraftsMap draftsMap, draftCursorsMap;
|
DraftsMap draftsMap, draftCursorsMap;
|
||||||
DraftsNotReadMap draftsNotReadMap;
|
DraftsNotReadMap draftsNotReadMap;
|
||||||
StorageMap imagesMap, stickerImagesMap, audiosMap;
|
|
||||||
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
|
|
||||||
quint64 locationsKey = 0, reportSpamStatusesKey = 0, trustedBotsKey = 0;
|
quint64 locationsKey = 0, reportSpamStatusesKey = 0, trustedBotsKey = 0;
|
||||||
quint64 recentStickersKeyOld = 0;
|
quint64 recentStickersKeyOld = 0;
|
||||||
quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
|
quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0;
|
||||||
@ -2154,8 +2135,7 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
quint64 first, second;
|
quint64 first, second;
|
||||||
qint32 size;
|
qint32 size;
|
||||||
map.stream >> key >> first >> second >> size;
|
map.stream >> key >> first >> second >> size;
|
||||||
imagesMap.insert(StorageKey(first, second), FileDesc(key, size));
|
clearKey(key, FileOption::User);
|
||||||
storageImagesSize += size;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case lskStickerImages: {
|
case lskStickerImages: {
|
||||||
@ -2166,8 +2146,7 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
quint64 first, second;
|
quint64 first, second;
|
||||||
qint32 size;
|
qint32 size;
|
||||||
map.stream >> key >> first >> second >> size;
|
map.stream >> key >> first >> second >> size;
|
||||||
stickerImagesMap.insert(StorageKey(first, second), FileDesc(key, size));
|
clearKey(key, FileOption::User);
|
||||||
storageStickersSize += size;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case lskAudios: {
|
case lskAudios: {
|
||||||
@ -2178,8 +2157,7 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
quint64 first, second;
|
quint64 first, second;
|
||||||
qint32 size;
|
qint32 size;
|
||||||
map.stream >> key >> first >> second >> size;
|
map.stream >> key >> first >> second >> size;
|
||||||
audiosMap.insert(StorageKey(first, second), FileDesc(key, size));
|
clearKey(key, FileOption::User);
|
||||||
storageAudiosSize += size;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case lskLocations: {
|
case lskLocations: {
|
||||||
@ -2243,13 +2221,6 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||||||
_draftCursorsMap = draftCursorsMap;
|
_draftCursorsMap = draftCursorsMap;
|
||||||
_draftsNotReadMap = draftsNotReadMap;
|
_draftsNotReadMap = draftsNotReadMap;
|
||||||
|
|
||||||
_imagesMap = imagesMap;
|
|
||||||
_storageImagesSize = storageImagesSize;
|
|
||||||
_stickerImagesMap = stickerImagesMap;
|
|
||||||
_storageStickersSize = storageStickersSize;
|
|
||||||
_audiosMap = audiosMap;
|
|
||||||
_storageAudiosSize = storageAudiosSize;
|
|
||||||
|
|
||||||
_locationsKey = locationsKey;
|
_locationsKey = locationsKey;
|
||||||
_reportSpamStatusesKey = reportSpamStatusesKey;
|
_reportSpamStatusesKey = reportSpamStatusesKey;
|
||||||
_trustedBotsKey = trustedBotsKey;
|
_trustedBotsKey = trustedBotsKey;
|
||||||
@ -2328,9 +2299,6 @@ void _writeMap(WriteMapWhen when) {
|
|||||||
uint32 mapSize = 0;
|
uint32 mapSize = 0;
|
||||||
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
|
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 (!_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 (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||||
if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
if (_reportSpamStatusesKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||||
if (_trustedBotsKey) 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 (_recentHashtagsAndBotsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||||
if (_exportSettingsKey) 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);
|
EncryptedDescriptor mapData(mapSize);
|
||||||
|
|
||||||
if (!_draftsMap.isEmpty()) {
|
if (!_draftsMap.isEmpty()) {
|
||||||
@ -2370,24 +2328,6 @@ void _writeMap(WriteMapWhen when) {
|
|||||||
mapData.stream << quint64(i.value()) << quint64(i.key());
|
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) {
|
if (_locationsKey) {
|
||||||
mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
|
mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
|
||||||
}
|
}
|
||||||
@ -2431,10 +2371,6 @@ void _writeMap(WriteMapWhen when) {
|
|||||||
map.writeEncrypted(mapData);
|
map.writeEncrypted(mapData);
|
||||||
|
|
||||||
_mapChanged = false;
|
_mapChanged = false;
|
||||||
|
|
||||||
if (mapSize > 30 * 1024 * 1024) {
|
|
||||||
CrashReports::ClearAnnotation("MapSize");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -2683,13 +2619,7 @@ void reset() {
|
|||||||
_fileLocations.clear();
|
_fileLocations.clear();
|
||||||
_fileLocationPairs.clear();
|
_fileLocationPairs.clear();
|
||||||
_fileLocationAliases.clear();
|
_fileLocationAliases.clear();
|
||||||
_imagesMap.clear();
|
|
||||||
_draftsNotReadMap.clear();
|
_draftsNotReadMap.clear();
|
||||||
_stickerImagesMap.clear();
|
|
||||||
_audiosMap.clear();
|
|
||||||
_storageImagesSize = _storageStickersSize = _storageAudiosSize = 0;
|
|
||||||
_webFilesMap.clear();
|
|
||||||
_storageWebFilesSize = 0;
|
|
||||||
_locationsKey = _reportSpamStatusesKey = _trustedBotsKey = 0;
|
_locationsKey = _reportSpamStatusesKey = _trustedBotsKey = 0;
|
||||||
_recentStickersKeyOld = 0;
|
_recentStickersKeyOld = 0;
|
||||||
_installedStickersKey = _featuredStickersKey = _recentStickersKey = _favedStickersKey = _archivedStickersKey = 0;
|
_installedStickersKey = _featuredStickersKey = _recentStickersKey = _favedStickersKey = _archivedStickersKey = 0;
|
||||||
@ -3011,401 +2941,23 @@ qint32 _storageAudioSize(qint32 rawlen) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeImage(const StorageKey &location, const ImagePtr &image) {
|
QString cachePath() {
|
||||||
if (image->isNull() || !image->loaded()) return;
|
Expects(!_userDbPath.isEmpty());
|
||||||
if (_imagesMap.constFind(location) != _imagesMap.cend()) return;
|
|
||||||
|
|
||||||
image->forget();
|
return _userDbPath + "cache";
|
||||||
writeImage(location, StorageImageSaved(image->savedData()), false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeImage(const StorageKey &location, const StorageImageSaved &image, bool overwrite) {
|
Storage::Cache::Database::Settings cacheSettings() {
|
||||||
if (!_working()) return;
|
auto result = Storage::Cache::Database::Settings();
|
||||||
|
|
||||||
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<ImageLoadTask>(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<StickerImageLoadTask>(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<AudioLoadTask>(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
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeWebFile(const QString &url, const QByteArray &content, bool overwrite) {
|
Storage::EncryptionKey cacheKey() {
|
||||||
if (!_working()) return;
|
Expects(LocalKey != nullptr);
|
||||||
|
|
||||||
qint32 size = _storageWebFileSize(url, content.size());
|
return Storage::EncryptionKey(bytes::make_vector(LocalKey->data()));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<WebFileLoadTask>(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 {
|
class CountWaveformTask : public Task {
|
||||||
public:
|
public:
|
||||||
@ -5136,8 +4688,6 @@ bool decrypt(const void *src, void *dst, uint32 len, const void *key128) {
|
|||||||
|
|
||||||
struct ClearManagerData {
|
struct ClearManagerData {
|
||||||
QThread *thread;
|
QThread *thread;
|
||||||
StorageMap images, stickers, audios;
|
|
||||||
WebFilesMap webFiles;
|
|
||||||
QMutex mutex;
|
QMutex mutex;
|
||||||
QList<int> tasks;
|
QList<int> tasks;
|
||||||
bool working;
|
bool working;
|
||||||
@ -5155,21 +4705,6 @@ bool ClearManager::addTask(int task) {
|
|||||||
if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true;
|
if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true;
|
||||||
if (task == ClearManagerAll) {
|
if (task == ClearManagerAll) {
|
||||||
data->tasks.clear();
|
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()) {
|
if (!_draftsMap.isEmpty()) {
|
||||||
_draftsMap.clear();
|
_draftsMap.clear();
|
||||||
_mapChanged = true;
|
_mapChanged = true;
|
||||||
@ -5208,73 +4743,6 @@ bool ClearManager::addTask(int task) {
|
|||||||
}
|
}
|
||||||
_writeMap();
|
_writeMap();
|
||||||
} else {
|
} 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) {
|
for (int32 i = 0, l = data->tasks.size(); i < l; ++i) {
|
||||||
if (data->tasks.at(i) == task) return true;
|
if (data->tasks.at(i) == task) return true;
|
||||||
}
|
}
|
||||||
@ -5319,8 +4787,6 @@ void ClearManager::onStart() {
|
|||||||
while (true) {
|
while (true) {
|
||||||
int task = 0;
|
int task = 0;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
StorageMap images, stickers, audios;
|
|
||||||
WebFilesMap webFiles;
|
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&data->mutex);
|
QMutexLocker lock(&data->mutex);
|
||||||
if (data->tasks.isEmpty()) {
|
if (data->tasks.isEmpty()) {
|
||||||
@ -5328,10 +4794,6 @@ void ClearManager::onStart() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
task = data->tasks.at(0);
|
task = data->tasks.at(0);
|
||||||
images = data->images;
|
|
||||||
stickers = data->stickers;
|
|
||||||
audios = data->audios;
|
|
||||||
webFiles = data->webFiles;
|
|
||||||
}
|
}
|
||||||
switch (task) {
|
switch (task) {
|
||||||
case ClearManagerAll: {
|
case ClearManagerAll: {
|
||||||
@ -5354,18 +4816,6 @@ void ClearManager::onStart() {
|
|||||||
result = QDir(cTempDir()).removeRecursively();
|
result = QDir(cTempDir()).removeRecursively();
|
||||||
break;
|
break;
|
||||||
case ClearManagerStorage:
|
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;
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "storage/file_download.h"
|
#include "storage/file_download.h"
|
||||||
|
#include "storage/cache/storage_cache_database.h"
|
||||||
|
#include "storage/localimageloader.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
class EncryptionKey;
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
namespace Theme {
|
namespace Theme {
|
||||||
struct Saved;
|
struct Saved;
|
||||||
@ -98,32 +104,9 @@ bool hasDraft(const PeerId &peer);
|
|||||||
void writeFileLocation(MediaKey location, const FileLocation &local);
|
void writeFileLocation(MediaKey location, const FileLocation &local);
|
||||||
FileLocation readFileLocation(MediaKey location, bool check = true);
|
FileLocation readFileLocation(MediaKey location, bool check = true);
|
||||||
|
|
||||||
void writeImage(const StorageKey &location, const ImagePtr &img);
|
QString cachePath();
|
||||||
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
|
Storage::Cache::Database::Settings cacheSettings();
|
||||||
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
Storage::EncryptionKey cacheKey();
|
||||||
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();
|
|
||||||
|
|
||||||
void countVoiceWaveform(DocumentData *document);
|
void countVoiceWaveform(DocumentData *document);
|
||||||
|
|
||||||
|
@ -9,10 +9,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
#include "storage/cache/storage_cache_database.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
|
||||||
namespace Images {
|
namespace Images {
|
||||||
namespace {
|
namespace {
|
||||||
@ -915,6 +917,10 @@ void Image::restore() const {
|
|||||||
_forgot = false;
|
_forgot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::optional<Storage::Cache::Key> Image::cacheKey() const {
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
|
||||||
void Image::invalidateSizeCache() const {
|
void Image::invalidateSizeCache() const {
|
||||||
for (auto &pix : _sizesCache) {
|
for (auto &pix : _sizesCache) {
|
||||||
if (!pix.isNull()) {
|
if (!pix.isNull()) {
|
||||||
@ -993,9 +999,9 @@ void RemoteImage::loadLocal() {
|
|||||||
if (_loader) _loader->start();
|
if (_loader) _loader->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
|
void RemoteImage::setImageBytes(
|
||||||
QBuffer buffer(&bytes);
|
const QByteArray &bytes,
|
||||||
|
const QByteArray &bytesFormat) {
|
||||||
if (!_data.isNull()) {
|
if (!_data.isNull()) {
|
||||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||||
}
|
}
|
||||||
@ -1013,6 +1019,11 @@ void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
|
|||||||
_saved = bytes;
|
_saved = bytes;
|
||||||
_format = fmt;
|
_format = fmt;
|
||||||
_forgot = false;
|
_forgot = false;
|
||||||
|
|
||||||
|
const auto location = this->location();
|
||||||
|
if (!location.isNull() && !bytes.isEmpty()) {
|
||||||
|
Auth().data().cache().putIfEmpty(Data::StorageCacheKey(location), bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteImage::amLoading() const {
|
bool RemoteImage::amLoading() const {
|
||||||
@ -1113,13 +1124,18 @@ StorageImage::StorageImage(const StorageImageLocation &location, int32 size)
|
|||||||
, _size(size) {
|
, _size(size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageImage::StorageImage(const StorageImageLocation &location, QByteArray &bytes)
|
StorageImage::StorageImage(
|
||||||
|
const StorageImageLocation &location,
|
||||||
|
const QByteArray &bytes)
|
||||||
: _location(location)
|
: _location(location)
|
||||||
, _size(bytes.size()) {
|
, _size(bytes.size()) {
|
||||||
setData(bytes);
|
setImageBytes(bytes);
|
||||||
if (!_location.isNull()) {
|
}
|
||||||
Local::writeImage(storageKey(_location), StorageImageSaved(bytes));
|
|
||||||
}
|
base::optional<Storage::Cache::Key> StorageImage::cacheKey() const {
|
||||||
|
return _location.isNull()
|
||||||
|
? base::none
|
||||||
|
: base::make_optional(Data::StorageCacheKey(_location));
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 StorageImage::countWidth() const {
|
int32 StorageImage::countWidth() const {
|
||||||
@ -1130,10 +1146,6 @@ int32 StorageImage::countHeight() const {
|
|||||||
return _location.height();
|
return _location.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StorageImage::hasLocalCopy() const {
|
|
||||||
return Local::willImageLoad(storageKey(_location));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StorageImage::setInformation(int32 size, int32 width, int32 height) {
|
void StorageImage::setInformation(int32 size, int32 width, int32 height) {
|
||||||
_size = size;
|
_size = size;
|
||||||
_location.setSize(width, height);
|
_location.setSize(width, height);
|
||||||
@ -1176,6 +1188,12 @@ WebFileImage::WebFileImage(
|
|||||||
, _size(size) {
|
, _size(size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::optional<Storage::Cache::Key> WebFileImage::cacheKey() const {
|
||||||
|
return _location.isNull()
|
||||||
|
? base::none
|
||||||
|
: base::make_optional(Data::WebDocumentCacheKey(_location));
|
||||||
|
}
|
||||||
|
|
||||||
int WebFileImage::countWidth() const {
|
int WebFileImage::countWidth() const {
|
||||||
return _width;
|
return _width;
|
||||||
}
|
}
|
||||||
@ -1184,10 +1202,6 @@ int WebFileImage::countHeight() const {
|
|||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebFileImage::hasLocalCopy() const {
|
|
||||||
return Local::willImageLoad(storageKey(_location));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFileImage::setInformation(int size, int width, int height) {
|
void WebFileImage::setInformation(int size, int width, int height) {
|
||||||
_size = size;
|
_size = size;
|
||||||
_width = width;
|
_width = width;
|
||||||
@ -1219,13 +1233,13 @@ DelayedStorageImage::DelayedStorageImage(int32 w, int32 h)
|
|||||||
, _loadCancelled(false)
|
, _loadCancelled(false)
|
||||||
, _loadFromCloud(false) {
|
, _loadFromCloud(false) {
|
||||||
}
|
}
|
||||||
|
//
|
||||||
DelayedStorageImage::DelayedStorageImage(QByteArray &bytes)
|
//DelayedStorageImage::DelayedStorageImage(QByteArray &bytes)
|
||||||
: StorageImage(StorageImageLocation(), bytes)
|
//: StorageImage(StorageImageLocation(), bytes)
|
||||||
, _loadRequested(false)
|
//, _loadRequested(false)
|
||||||
, _loadCancelled(false)
|
//, _loadCancelled(false)
|
||||||
, _loadFromCloud(false) {
|
//, _loadFromCloud(false) {
|
||||||
}
|
//}
|
||||||
|
|
||||||
void DelayedStorageImage::setStorageLocation(
|
void DelayedStorageImage::setStorageLocation(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
@ -1317,6 +1331,10 @@ WebImage::WebImage(const QString &url, int width, int height)
|
|||||||
, _height(height) {
|
, _height(height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::optional<Storage::Cache::Key> WebImage::cacheKey() const {
|
||||||
|
return Data::UrlCacheKey(_url);
|
||||||
|
}
|
||||||
|
|
||||||
void WebImage::setSize(int width, int height) {
|
void WebImage::setSize(int width, int height) {
|
||||||
_width = width;
|
_width = width;
|
||||||
_height = height;
|
_height = height;
|
||||||
@ -1330,10 +1348,6 @@ int32 WebImage::countHeight() const {
|
|||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebImage::hasLocalCopy() const {
|
|
||||||
return Local::willWebFileLoad(_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebImage::setInformation(int32 size, int32 width, int32 height) {
|
void WebImage::setInformation(int32 size, int32 width, int32 height) {
|
||||||
_size = size;
|
_size = size;
|
||||||
setSize(width, height);
|
setSize(width, height);
|
||||||
@ -1404,8 +1418,8 @@ Image *getImage(int32 width, int32 height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
||||||
StorageKey key(storageKey(location));
|
const auto key = storageKey(location);
|
||||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
auto i = storageImages.constFind(key);
|
||||||
if (i == storageImages.cend()) {
|
if (i == storageImages.cend()) {
|
||||||
i = storageImages.insert(key, new StorageImage(location, size));
|
i = storageImages.insert(key, new StorageImage(location, size));
|
||||||
} else {
|
} else {
|
||||||
@ -1414,20 +1428,17 @@ StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
|||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes) {
|
StorageImage *getImage(
|
||||||
StorageKey key(storageKey(location));
|
const StorageImageLocation &location,
|
||||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
const QByteArray &bytes) {
|
||||||
|
const auto key = storageKey(location);
|
||||||
|
auto i = storageImages.constFind(key);
|
||||||
if (i == storageImages.cend()) {
|
if (i == storageImages.cend()) {
|
||||||
QByteArray bytesArr(bytes);
|
i = storageImages.insert(key, new StorageImage(location, bytes));
|
||||||
i = storageImages.insert(key, new StorageImage(location, bytesArr));
|
|
||||||
} else {
|
} else {
|
||||||
i.value()->refreshFileReference(location.fileReference());
|
i.value()->refreshFileReference(location.fileReference());
|
||||||
if (!i.value()->loaded()) {
|
if (!i.value()->loaded()) {
|
||||||
QByteArray bytesArr(bytes);
|
i.value()->setImageBytes(bytes);
|
||||||
i.value()->setData(bytesArr);
|
|
||||||
if (!location.isNull()) {
|
|
||||||
Local::writeImage(key, StorageImageSaved(bytes));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return i.value();
|
return i.value();
|
||||||
|
@ -10,6 +10,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Cache {
|
||||||
|
struct Key;
|
||||||
|
} // namespace Cache
|
||||||
|
} // namespace Storage
|
||||||
|
|
||||||
enum class ImageRoundRadius {
|
enum class ImageRoundRadius {
|
||||||
None,
|
None,
|
||||||
Large,
|
Large,
|
||||||
@ -372,6 +378,7 @@ public:
|
|||||||
virtual const StorageImageLocation &location() const {
|
virtual const StorageImageLocation &location() const {
|
||||||
return StorageImageLocation::Null;
|
return StorageImageLocation::Null;
|
||||||
}
|
}
|
||||||
|
virtual base::optional<Storage::Cache::Key> cacheKey() const;
|
||||||
|
|
||||||
bool isNull() const;
|
bool isNull() const;
|
||||||
|
|
||||||
@ -412,10 +419,6 @@ protected:
|
|||||||
return _data.height();
|
return _data.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool hasLocalCopy() const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutable QByteArray _saved, _format;
|
mutable QByteArray _saved, _format;
|
||||||
mutable bool _forgot;
|
mutable bool _forgot;
|
||||||
mutable QPixmap _data;
|
mutable QPixmap _data;
|
||||||
@ -464,8 +467,8 @@ public:
|
|||||||
float64 progress() const override;
|
float64 progress() const override;
|
||||||
int32 loadOffset() const override;
|
int32 loadOffset() const override;
|
||||||
|
|
||||||
void setData(
|
void setImageBytes(
|
||||||
QByteArray &bytes,
|
const QByteArray &bytes,
|
||||||
const QByteArray &format = QByteArray());
|
const QByteArray &format = QByteArray());
|
||||||
|
|
||||||
void load(
|
void load(
|
||||||
@ -507,12 +510,13 @@ private:
|
|||||||
|
|
||||||
class StorageImage : public RemoteImage {
|
class StorageImage : public RemoteImage {
|
||||||
public:
|
public:
|
||||||
StorageImage(const StorageImageLocation &location, int32 size = 0);
|
explicit StorageImage(const StorageImageLocation &location, int32 size = 0);
|
||||||
StorageImage(const StorageImageLocation &location, QByteArray &bytes);
|
StorageImage(const StorageImageLocation &location, const QByteArray &bytes);
|
||||||
|
|
||||||
const StorageImageLocation &location() const override {
|
const StorageImageLocation &location() const override {
|
||||||
return _location;
|
return _location;
|
||||||
}
|
}
|
||||||
|
base::optional<Storage::Cache::Key> cacheKey() const override;
|
||||||
void refreshFileReference(const QByteArray &data) {
|
void refreshFileReference(const QByteArray &data) {
|
||||||
_location.refreshFileReference(data);
|
_location.refreshFileReference(data);
|
||||||
}
|
}
|
||||||
@ -524,8 +528,6 @@ protected:
|
|||||||
LoadFromCloudSetting fromCloud,
|
LoadFromCloudSetting fromCloud,
|
||||||
bool autoLoading) override;
|
bool autoLoading) override;
|
||||||
|
|
||||||
bool hasLocalCopy() const override;
|
|
||||||
|
|
||||||
int32 countWidth() const override;
|
int32 countWidth() const override;
|
||||||
int32 countHeight() const override;
|
int32 countHeight() const override;
|
||||||
|
|
||||||
@ -543,6 +545,8 @@ public:
|
|||||||
int height,
|
int height,
|
||||||
int size = 0);
|
int size = 0);
|
||||||
|
|
||||||
|
base::optional<Storage::Cache::Key> cacheKey() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setInformation(int size, int width, int height) override;
|
void setInformation(int size, int width, int height) override;
|
||||||
FileLoader *createLoader(
|
FileLoader *createLoader(
|
||||||
@ -554,8 +558,6 @@ protected:
|
|||||||
return _box;
|
return _box;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasLocalCopy() const override;
|
|
||||||
|
|
||||||
int countWidth() const override;
|
int countWidth() const override;
|
||||||
int countHeight() const override;
|
int countHeight() const override;
|
||||||
|
|
||||||
@ -571,7 +573,7 @@ class DelayedStorageImage : public StorageImage {
|
|||||||
public:
|
public:
|
||||||
DelayedStorageImage();
|
DelayedStorageImage();
|
||||||
DelayedStorageImage(int32 w, int32 h);
|
DelayedStorageImage(int32 w, int32 h);
|
||||||
DelayedStorageImage(QByteArray &bytes);
|
//DelayedStorageImage(QByteArray &bytes);
|
||||||
|
|
||||||
void setStorageLocation(
|
void setStorageLocation(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
@ -617,6 +619,8 @@ public:
|
|||||||
|
|
||||||
void setSize(int width, int height);
|
void setSize(int width, int height);
|
||||||
|
|
||||||
|
base::optional<Storage::Cache::Key> cacheKey() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSize shrinkBox() const override {
|
QSize shrinkBox() const override {
|
||||||
return _box;
|
return _box;
|
||||||
@ -630,8 +634,6 @@ protected:
|
|||||||
int32 countWidth() const override;
|
int32 countWidth() const override;
|
||||||
int32 countHeight() const override;
|
int32 countHeight() const override;
|
||||||
|
|
||||||
bool hasLocalCopy() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _url;
|
QString _url;
|
||||||
QSize _box;
|
QSize _box;
|
||||||
@ -652,7 +654,7 @@ Image *getImage(
|
|||||||
const QPixmap &pixmap);
|
const QPixmap &pixmap);
|
||||||
Image *getImage(int32 width, int32 height);
|
Image *getImage(int32 width, int32 height);
|
||||||
StorageImage *getImage(const StorageImageLocation &location, int size = 0);
|
StorageImage *getImage(const StorageImageLocation &location, int size = 0);
|
||||||
StorageImage *getImage(
|
StorageImage *getImage( // photoCachedSize
|
||||||
const StorageImageLocation &location,
|
const StorageImageLocation &location,
|
||||||
const QByteArray &bytes);
|
const QByteArray &bytes);
|
||||||
Image *getImage(const MTPWebDocument &location);
|
Image *getImage(const MTPWebDocument &location);
|
||||||
|
@ -250,6 +250,10 @@ if %BuildUWP% neq 0 (
|
|||||||
cd "%DeployPath%"
|
cd "%DeployPath%"
|
||||||
7z a -mx9 %PortableFile% %BinaryName%\
|
7z a -mx9 %PortableFile% %BinaryName%\
|
||||||
if %errorlevel% neq 0 goto error
|
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"
|
set "FinalDeployPath=%FinalReleasePath%\%AppVersionStrMajor%\%AppVersionStrFull%\tsetup"
|
||||||
|
Loading…
Reference in New Issue
Block a user