From 97bab388ea920e4173c4783d5be593d7df3130d7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 10 Apr 2020 15:17:10 +0400 Subject: [PATCH] Use rpl for file download progress notifications. --- .../SourceFiles/chat_helpers/stickers.cpp | 21 +--- Telegram/SourceFiles/chat_helpers/stickers.h | 7 -- Telegram/SourceFiles/data/data_document.cpp | 103 +++++++++++------- Telegram/SourceFiles/data/data_document.h | 2 + Telegram/SourceFiles/data/data_session.cpp | 19 ++++ Telegram/SourceFiles/data/data_session.h | 4 + Telegram/SourceFiles/mainwidget.cpp | 47 -------- Telegram/SourceFiles/mainwidget.h | 4 - .../passport/passport_form_controller.cpp | 16 ++- .../passport/passport_form_controller.h | 2 +- .../SourceFiles/storage/file_download.cpp | 23 ++-- Telegram/SourceFiles/storage/file_download.h | 12 +- .../storage/file_download_mtproto.cpp | 4 +- Telegram/SourceFiles/ui/image/image_source.h | 3 + 14 files changed, 125 insertions(+), 142 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index 06ef194d6..a057763f5 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -1282,11 +1282,12 @@ ThumbnailSource::ThumbnailSource( } QImage ThumbnailSource::takeLoaded() { + const auto loader = currentLoader(); if (_bytesForAnimated.isEmpty() - && _loader - && _loader->finished() - && !_loader->cancelled()) { - _bytesForAnimated = _loader->bytes(); + && loader + && loader->finished() + && !loader->cancelled()) { + _bytesForAnimated = loader->bytes(); } auto result = StorageSource::takeLoaded(); if (!_bytesForAnimated.isEmpty() @@ -1301,16 +1302,4 @@ QByteArray ThumbnailSource::bytesForCache() { return _bytesForAnimated; } -std::unique_ptr ThumbnailSource::createLoader( - Data::FileOrigin origin, - LoadFromCloudSetting fromCloud, - bool autoLoading) { - auto result = StorageSource::createLoader( - origin, - fromCloud, - autoLoading); - _loader = result.get(); - return result; -} - } // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers.h b/Telegram/SourceFiles/chat_helpers/stickers.h index d0b8fd03b..608b7dcdd 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.h +++ b/Telegram/SourceFiles/chat_helpers/stickers.h @@ -178,14 +178,7 @@ public: QByteArray bytesForCache() override; -protected: - std::unique_ptr createLoader( - Data::FileOrigin origin, - LoadFromCloudSetting fromCloud, - bool autoLoading) override; - private: - QPointer _loader; QByteArray _bytesForAnimated; }; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 787d4593c..327a6c889 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -795,34 +795,32 @@ void DocumentData::automaticLoadSettingsChanged() { } bool DocumentData::loaded(bool check) const { - if (loading() && _loader->finished()) { - if (_loader->cancelled()) { - _flags |= Flag::DownloadCancelled; - destroyLoader(); - } else { - auto that = const_cast(this); - that->setLocation(FileLocation(_loader->fileName())); - ActiveCache().decrement(that->_data.size()); - that->_data = _loader->bytes(); - ActiveCache().increment(that->_data.size()); - - that->setGoodThumbnailDataReady(); - - if (const auto media = activeMediaView()) { - media->setBytes(_loader->bytes()); - media->checkStickerLarge(_loader.get()); - } - destroyLoader(); - - if (!that->_data.isEmpty()) { - ActiveCache().up(that); - } - } - _owner->notifyDocumentLayoutChanged(this); - } return !rawBytes().isEmpty() || !filepath(check).isEmpty(); } +void DocumentData::finishLoad() { + const auto guard = gsl::finally([&] { + destroyLoader(); + }); + if (_loader->cancelled()) { + _flags |= Flag::DownloadCancelled; + return; + } + setLocation(FileLocation(_loader->fileName())); + ActiveCache().decrement(_data.size()); + _data = _loader->bytes(); + ActiveCache().increment(_data.size()); + + setGoodThumbnailDataReady(); + if (const auto media = activeMediaView()) { + media->setBytes(_loader->bytes()); + media->checkStickerLarge(_loader.get()); + } + if (!_data.isEmpty()) { + ActiveCache().up(this); + } +} + void DocumentData::destroyLoader() const { if (!_loader) { return; @@ -996,17 +994,7 @@ void DocumentData::save( autoLoading, cacheTag()); } - - QObject::connect( - _loader.get(), - &FileLoader::progress, - App::main(), - [=](FileLoader *l) { App::main()->documentLoadProgress(l); }); - QObject::connect( - _loader.get(), - &FileLoader::failed, - App::main(), - &MainWidget::documentLoadFailed); + handleLoaderUpdates(); } if (loading()) { _loader->start(); @@ -1014,6 +1002,46 @@ void DocumentData::save( _owner->notifyDocumentLayoutChanged(this); } +void DocumentData::handleLoaderUpdates() { + _loader->updates( + ) | rpl::start_with_next_error_done([=] { + _owner->documentLoadProgress(this); + }, [=](bool started) { + if (started) { + const auto origin = _loader->fileOrigin(); + const auto failedFileName = _loader->fileName(); + const auto retry = [=] { + Ui::hideLayer(); + save(origin, failedFileName); + }; + Ui::show(Box( + tr::lng_download_finish_failed(tr::now), + crl::guard(&session(), retry))); + } else { + // Sometimes we have LOCATION_INVALID error in documents / stickers. + // Sometimes FILE_REFERENCE_EXPIRED could not be handled. + // + //const auto openSettings = [=] { + // Global::SetDownloadPath(QString()); + // Global::SetDownloadPathBookmark(QByteArray()); + // Ui::show(Box()); + // Global::RefDownloadPathChanged().notify(); + //}; + //Ui::show(Box( + // tr::lng_download_path_failed(tr::now), + // tr::lng_download_path_settings(tr::now), + // crl::guard(&session(), openSettings))); + } + finishLoad(); + status = FileDownloadFailed; + _owner->documentLoadFail(this, started); + }, [=] { + finishLoad(); + _owner->documentLoadDone(this); + }) | rpl::release(); + +} + void DocumentData::cancel() { if (!loading()) { return; @@ -1021,8 +1049,7 @@ void DocumentData::cancel() { _flags |= Flag::DownloadCancelled; destroyLoader(); - _owner->notifyDocumentLayoutChanged(this); - App::main()->documentLoadProgress(this); + _owner->documentLoadDone(this); } bool DocumentData::cancelled() const { diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index b41c248d9..2ea9848a5 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -287,6 +287,8 @@ private: void setMaybeSupportsStreaming(bool supports); void setLoadedInMediaCacheLocation(); + void finishLoad(); + void handleLoaderUpdates(); void destroyLoader() const; [[nodiscard]] bool useStreamingLoader() const; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 6d2e3fd37..f9895844f 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1114,6 +1114,25 @@ void Session::requestPollViewRepaint(not_null poll) { } } +void Session::documentLoadProgress(not_null document) { + requestDocumentViewRepaint(document); + session().documentUpdated.notify(document, true); + + if (document->isAudioFile()) { + ::Media::Player::instance()->documentLoadProgress(document); + } +} + +void Session::documentLoadDone(not_null document) { + notifyDocumentLayoutChanged(document); +} + +void Session::documentLoadFail( + not_null document, + bool started) { + notifyDocumentLayoutChanged(document); +} + void Session::markMediaRead(not_null document) { const auto i = _documentItems.find(document); if (i != end(_documentItems)) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 41670f668..b3c9ec4cb 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -433,6 +433,10 @@ public: void markMediaRead(not_null document); void requestPollViewRepaint(not_null poll); + void documentLoadProgress(not_null document); + void documentLoadDone(not_null document); + void documentLoadFail(not_null document, bool started); + HistoryItem *addNewMessage( const MTPMessage &data, MTPDmessage_ClientFlags flags, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 4255eed31..93596718a 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1252,53 +1252,6 @@ void MainWidget::exportTopBarHeightUpdated() { } } -void MainWidget::documentLoadProgress(FileLoader *loader) { - if (const auto documentId = loader ? loader->objId() : 0) { - documentLoadProgress(session().data().document(documentId)); - } -} - -void MainWidget::documentLoadProgress(DocumentData *document) { - session().data().requestDocumentViewRepaint(document); - session().documentUpdated.notify(document, true); - - if (!document->loaded() && document->isAudioFile()) { - Media::Player::instance()->documentLoadProgress(document); - } -} - -void MainWidget::documentLoadFailed(FileLoader *loader, bool started) { - const auto documentId = loader ? loader->objId() : 0; - if (!documentId) return; - - const auto document = session().data().document(documentId); - if (started) { - const auto origin = loader->fileOrigin(); - const auto failedFileName = loader->fileName(); - Ui::show(Box(tr::lng_download_finish_failed(tr::now), crl::guard(this, [=] { - Ui::hideLayer(); - if (document) { - document->save(origin, failedFileName); - } - }))); - } else { - // Sometimes we have LOCATION_INVALID error in documents / stickers. - // Sometimes FILE_REFERENCE_EXPIRED could not be handled. - // - //Ui::show(Box(tr::lng_download_path_failed(tr::now), tr::lng_download_path_settings(tr::now), crl::guard(this, [=] { - // Global::SetDownloadPath(QString()); - // Global::SetDownloadPathBookmark(QByteArray()); - // Ui::show(Box()); - // Global::RefDownloadPathChanged().notify(); - //}))); - } - - if (document) { - if (document->loading()) document->cancel(); - document->status = FileDownloadFailed; - } -} - void MainWidget::inlineResultLoadProgress(FileLoader *loader) { //InlineBots::Result *result = InlineBots::resultFromLoader(loader); //if (!result) return; diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 6afd699dd..c82ff75f0 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -266,8 +266,6 @@ public: bool ptsUpdateAndApply(int32 pts, int32 ptsCount, const MTPUpdate &update); bool ptsUpdateAndApply(int32 pts, int32 ptsCount); - void documentLoadProgress(DocumentData *document); - void searchInChat(Dialogs::Key chat); void app_sendBotCallback( @@ -299,8 +297,6 @@ signals: void dialogsUpdated(); public slots: - void documentLoadProgress(FileLoader *loader); - void documentLoadFailed(FileLoader *loader, bool started); void inlineResultLoadProgress(FileLoader *loader); void inlineResultLoadFailed(FileLoader *loader, bool started); diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index f7f794c82..bbb94e8cb 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -1738,16 +1738,14 @@ void FormController::loadFile(File &file) { false, Data::kImageCacheTag)); const auto loader = j->second.get(); - loader->connect(loader, &mtpFileLoader::progress, [=] { - if (loader->finished()) { - fileLoadDone(key, loader->bytes()); - } else { - fileLoadProgress(key, loader->currentOffset()); - } - }); - loader->connect(loader, &mtpFileLoader::failed, [=] { + loader->updates( + ) | rpl::start_with_next_error_done([=] { + fileLoadProgress(key, loader->currentOffset()); + }, [=](bool started) { fileLoadFail(key); - }); + }, [=] { + fileLoadDone(key, loader->bytes()); + }) | rpl::release(); loader->start(); } diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h index 4ae25ac65..b6a531c76 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_controller.h @@ -529,7 +529,7 @@ private: Form _form; bool _cancelled = false; mtpRequestId _recoverRequestId = 0; - std::map> _fileLoaders; + base::flat_map> _fileLoaders; rpl::event_stream> _scanUpdated; rpl::event_stream> _valueSaveFinished; diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 72ddd262d..7a32d5670 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -72,7 +72,8 @@ void FileLoader::finishWithBytes(const QByteArray &data) { Platform::File::PostprocessDownloaded( QFileInfo(_file).absoluteFilePath()); } - Auth().downloaderTaskFinished().notify(); + _session->downloaderTaskFinished().notify(); + _updates.fire_done(); } QByteArray FileLoader::imageFormat(const QSize &shrinkBox) const { @@ -130,7 +131,7 @@ void FileLoader::permitLoadFromCloud() { } void FileLoader::notifyAboutProgress() { - emit progress(this); + _updates.fire({}); } void FileLoader::localLoaded( @@ -148,7 +149,6 @@ void FileLoader::localLoaded( _imageData = imageData; } finishWithBytes(result.data); - notifyAboutProgress(); } void FileLoader::start() { @@ -186,7 +186,7 @@ void FileLoader::loadLocal(const Storage::Cache::Key &key) { std::move(image)); }); }; - session().data().cache().get(key, [=, callback = std::move(done)]( + _session->data().cache().get(key, [=, callback = std::move(done)]( QByteArray &&value) mutable { if (readImage) { crl::async([ @@ -218,10 +218,10 @@ bool FileLoader::tryLoadLocal() { return true; } - const auto weak = QPointer(this); + const auto weak = base::make_weak(this); if (_toCache == LoadToCacheAsWell) { loadLocal(cacheKey()); - emit progress(this); + notifyAboutProgress(); } if (!weak) { return false; @@ -253,11 +253,11 @@ void FileLoader::cancel(bool fail) { } _data = QByteArray(); - const auto weak = QPointer(this); + const auto weak = base::make_weak(this); if (fail) { - emit failed(this, started); + _updates.fire_error_copy(started); } else { - emit progress(this); + _updates.fire_done(); } if (weak) { _filename = QString(); @@ -361,13 +361,14 @@ bool FileLoader::finalizeResult() { } if ((_toCache == LoadToCacheAsWell) && (_data.size() <= Storage::kMaxFileInMemory)) { - session().data().cache().put( + _session->data().cache().put( cacheKey(), Storage::Cache::Database::TaggedValue( base::duplicate(_data), _cacheTag)); } } - Auth().downloaderTaskFinished().notify(); + _session->downloaderTaskFinished().notify(); + _updates.fire_done(); return true; } diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index b97505507..d8d0a667b 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/observer.h" #include "base/timer.h" #include "base/binary_guard.h" +#include "base/weak_ptr.h" #include @@ -51,9 +52,7 @@ struct StorageImageSaved { }; -class FileLoader : public QObject { - Q_OBJECT - +class FileLoader : public base::has_weak_ptr { public: FileLoader( const QString &toFile, @@ -109,9 +108,9 @@ public: const QByteArray &imageFormat, const QImage &imageData); -signals: - void progress(FileLoader *loader); - void failed(FileLoader *loader, bool started); + [[nodiscard]] rpl::producer updates() const { + return _updates.events(); + } protected: enum class LocalStatus { @@ -139,6 +138,7 @@ protected: [[nodiscard]] QByteArray readLoadedPartBack(int offset, int size); const not_null _session; + rpl::event_stream _updates; bool _autoLoading = false; uint8 _cacheTag = 0; diff --git a/Telegram/SourceFiles/storage/file_download_mtproto.cpp b/Telegram/SourceFiles/storage/file_download_mtproto.cpp index bf14e8bfe..118792cf6 100644 --- a/Telegram/SourceFiles/storage/file_download_mtproto.cpp +++ b/Telegram/SourceFiles/storage/file_download_mtproto.cpp @@ -109,7 +109,6 @@ bool mtpFileLoader::feedPart(int offset, const QByteArray &bytes) { if (buffer.empty() || (buffer.size() % 1024)) { // bad next offset _lastComplete = true; } - const auto weak = QPointer(this); const auto finished = !haveSentRequests() && (_lastComplete || (_size && _nextRequestOffset >= _size)); if (finished) { @@ -117,8 +116,7 @@ bool mtpFileLoader::feedPart(int offset, const QByteArray &bytes) { if (!finalizeResult()) { return false; } - } - if (weak) { + } else { notifyAboutProgress(); } return true; diff --git a/Telegram/SourceFiles/ui/image/image_source.h b/Telegram/SourceFiles/ui/image/image_source.h index ec7731e92..0da22b1e5 100644 --- a/Telegram/SourceFiles/ui/image/image_source.h +++ b/Telegram/SourceFiles/ui/image/image_source.h @@ -148,6 +148,9 @@ protected: bool autoLoading) = 0; void loadLocal(); + FileLoader *currentLoader() const { + return _loader.get(); + } private: bool cancelled() const;