From 8ca0b614d7dc63a9986940646dc598f7f076fbfa Mon Sep 17 00:00:00 2001
From: 23rd <23rd@vivaldi.net>
Date: Wed, 5 Feb 2020 17:13:12 +0300
Subject: [PATCH] Moved loader of emoji sets and dictionaries to CloudBlob.

---
 .../boxes/dictionaries_manager.cpp            | 109 ++++-------------
 .../chat_helpers/emoji_sets_manager.cpp       | 111 ++++--------------
 .../storage/storage_cloud_blob.cpp            |  59 ++++++++++
 .../SourceFiles/storage/storage_cloud_blob.h  |  43 +++++++
 4 files changed, 153 insertions(+), 169 deletions(-)

diff --git a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp
index 4beab9046..46f809fe1 100644
--- a/Telegram/SourceFiles/boxes/dictionaries_manager.cpp
+++ b/Telegram/SourceFiles/boxes/dictionaries_manager.cpp
@@ -41,34 +41,19 @@ using Dictionaries = std::vector<int>;
 using namespace Storage::CloudBlob;
 
 using Loading = MTP::DedicatedLoader::Progress;
-using DictState = base::variant<
-	Available,
-	Ready,
-	Active,
-	Failed,
-	Loading>;
+using DictState = BlobState;
 
-class Loader : public QObject {
+class Loader : public BlobLoader {
 public:
-	Loader(QObject *parent, int id);
+	Loader(
+		QObject *parent,
+		int id,
+		MTP::DedicatedLoader::Location location,
+		const QString &folder,
+		int size);
 
-	int id() const;
-
-	rpl::producer<DictState> state() const;
-	void destroy();
-
-private:
-	void setImplementation(std::unique_ptr<MTP::DedicatedLoader> loader);
-	void unpack(const QString &path);
-	void finalize(const QString &path);
-	void fail();
-
-	int _id = 0;
-	int _size = 0;
-	rpl::variable<DictState> _state;
-
-	MTP::WeakInstance _mtproto;
-	std::unique_ptr<MTP::DedicatedLoader> _implementation;
+	void destroy() override;
+	void unpack(const QString &path) override;
 
 };
 
@@ -109,10 +94,10 @@ int GetDownloadSize(int id) {
 }
 
 MTP::DedicatedLoader::Location GetDownloadLocation(int id) {
-	constexpr auto kUsername = "tdhbcfiles";
+	const auto username = kCloudLocationUsername.utf16();
 	const auto sets = Spellchecker::Dictionaries();
 	const auto i = ranges::find(sets, id, &Spellchecker::Dict::id);
-	return MTP::DedicatedLoader::Location{ kUsername, i->postId };
+	return MTP::DedicatedLoader::Location{ username, i->postId };
 }
 
 DictState ComputeState(int id) {
@@ -147,60 +132,18 @@ QString StateDescription(const DictState &state) {
 	});
 }
 
-Loader::Loader(QObject *parent, int id)
-: QObject(parent)
-, _id(id)
-, _size(GetDownloadSize(_id))
-, _state(Loading{ 0, _size })
-, _mtproto(Core::App().activeAccount().mtp()) {
-	const auto ready = [=](std::unique_ptr<MTP::DedicatedLoader> loader) {
-		if (loader) {
-			setImplementation(std::move(loader));
-		} else {
-			fail();
-		}
-	};
-	const auto location = GetDownloadLocation(id);
-	const auto folder = Spellchecker::DictPathByLangId(id);
-	MTP::StartDedicatedLoader(&_mtproto, location, folder, ready);
-}
-
-int Loader::id() const {
-	return _id;
-}
-
-rpl::producer<DictState> Loader::state() const {
-	return _state.value();
-}
-
-void Loader::setImplementation(
-		std::unique_ptr<MTP::DedicatedLoader> loader) {
-	_implementation = std::move(loader);
-	auto convert = [](auto value) {
-		return DictState(value);
-	};
-	_state = _implementation->progress(
-	) | rpl::map([](const Loading &state) {
-		return DictState(state);
-	});
-	_implementation->failed(
-	) | rpl::start_with_next([=] {
-		fail();
-	}, _implementation->lifetime());
-
-	_implementation->ready(
-	) | rpl::start_with_next([=](const QString &filepath) {
-		unpack(filepath);
-	}, _implementation->lifetime());
-
-	QDir(Spellchecker::DictPathByLangId(_id)).removeRecursively();
-	_implementation->start();
+Loader::Loader(
+	QObject *parent,
+	int id,
+	MTP::DedicatedLoader::Location location,
+	const QString &folder,
+	int size) : BlobLoader(parent, id, location, folder, size) {
 }
 
 void Loader::unpack(const QString &path) {
 	const auto weak = Ui::MakeWeak(this);
 	crl::async([=] {
-		if (Spellchecker::UnpackDictionary(path, _id)) {
+		if (Spellchecker::UnpackDictionary(path, id())) {
 			QFile(path).remove();
 			crl::on_main(weak, [=] {
 				destroy();
@@ -213,13 +156,6 @@ void Loader::unpack(const QString &path) {
 	});
 }
 
-void Loader::finalize(const QString &path) {
-}
-
-void Loader::fail() {
-	_state = Failed();
-}
-
 void Loader::destroy() {
 	Expects(GlobalLoader == this);
 
@@ -329,7 +265,12 @@ auto AddButtonWithLoader(
 	) | rpl::start_with_next([=](bool toggled) {
 		const auto &state = buttonState->current();
 		if (toggled && (state.is<Available>() || state.is<Failed>())) {
-			SetGlobalLoader(base::make_unique_q<Loader>(App::main(), id));
+			SetGlobalLoader(base::make_unique_q<Loader>(
+				App::main(),
+				id,
+				GetDownloadLocation(id),
+				Spellchecker::DictPathByLangId(id),
+				GetDownloadSize(id)));
 		} else if (!toggled && state.is<Loading>()) {
 			if (GlobalLoader && GlobalLoader->id() == id) {
 				GlobalLoader->destroy();
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp
index 190c7fbc4..c41fac066 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp
+++ b/Telegram/SourceFiles/chat_helpers/emoji_sets_manager.cpp
@@ -53,34 +53,19 @@ auto Sets() {
 }
 
 using Loading = MTP::DedicatedLoader::Progress;
-using SetState = base::variant<
-	Available,
-	Ready,
-	Active,
-	Loading,
-	Failed>;
+using SetState = BlobState;
 
-class Loader : public QObject {
+class Loader : public BlobLoader {
 public:
-	Loader(QObject *parent, int id);
+	Loader(
+		QObject *parent,
+		int id,
+		MTP::DedicatedLoader::Location location,
+		const QString &folder,
+		int size);
 
-	int id() const;
-
-	rpl::producer<SetState> state() const;
-	void destroy();
-
-private:
-	void setImplementation(std::unique_ptr<MTP::DedicatedLoader> loader);
-	void unpack(const QString &path);
-	void finalize(const QString &path);
-	void fail();
-
-	int _id = 0;
-	int _size = 0;
-	rpl::variable<SetState> _state;
-
-	MTP::WeakInstance _mtproto;
-	std::unique_ptr<MTP::DedicatedLoader> _implementation;
+	void destroy() override;
+	void unpack(const QString &path) override;
 
 };
 
@@ -148,10 +133,10 @@ int GetDownloadSize(int id) {
 }
 
 MTP::DedicatedLoader::Location GetDownloadLocation(int id) {
-	constexpr auto kUsername = "tdhbcfiles";
+	const auto username = kCloudLocationUsername.utf16();
 	const auto sets = Sets();
 	const auto i = ranges::find(sets, id, &Set::id);
-	return MTP::DedicatedLoader::Location{ kUsername, i->postId };
+	return MTP::DedicatedLoader::Location{ username, i->postId };
 }
 
 SetState ComputeState(int id) {
@@ -195,63 +180,21 @@ bool UnpackSet(const QString &path, const QString &folder) {
 	return UnpackBlob(path, folder, GoodSetPartName);
 }
 
-Loader::Loader(QObject *parent, int id)
-: QObject(parent)
-, _id(id)
-, _size(GetDownloadSize(_id))
-, _state(Loading{ 0, _size })
-, _mtproto(Core::App().activeAccount().mtp()) {
-	const auto ready = [=](std::unique_ptr<MTP::DedicatedLoader> loader) {
-		if (loader) {
-			setImplementation(std::move(loader));
-		} else {
-			fail();
-		}
-	};
-	const auto location = GetDownloadLocation(id);
-	const auto folder = internal::SetDataPath(id);
-	MTP::StartDedicatedLoader(&_mtproto, location, folder, ready);
-}
-
-int Loader::id() const {
-	return _id;
-}
-
-rpl::producer<SetState> Loader::state() const {
-	return _state.value();
-}
-
-void Loader::setImplementation(
-		std::unique_ptr<MTP::DedicatedLoader> loader) {
-	_implementation = std::move(loader);
-	auto convert = [](auto value) {
-		return SetState(value);
-	};
-	_state = _implementation->progress(
-	) | rpl::map([](const Loading &state) {
-		return SetState(state);
-	});
-	_implementation->failed(
-	) | rpl::start_with_next([=] {
-		fail();
-	}, _implementation->lifetime());
-
-	_implementation->ready(
-	) | rpl::start_with_next([=](const QString &filepath) {
-		unpack(filepath);
-	}, _implementation->lifetime());
-
-	QDir(internal::SetDataPath(_id)).removeRecursively();
-	_implementation->start();
+Loader::Loader(
+	QObject *parent,
+	int id,
+	MTP::DedicatedLoader::Location location,
+	const QString &folder,
+	int size) : BlobLoader(parent, id, location, folder, size) {
 }
 
 void Loader::unpack(const QString &path) {
-	const auto folder = internal::SetDataPath(_id);
+	const auto folder = internal::SetDataPath(id());
 	const auto weak = Ui::MakeWeak(this);
 	crl::async([=] {
 		if (UnpackSet(path, folder)) {
 			QFile(path).remove();
-			SwitchToSet(_id, crl::guard(weak, [=](bool success) {
+			SwitchToSet(id(), crl::guard(weak, [=](bool success) {
 				if (success) {
 					destroy();
 				} else {
@@ -266,13 +209,6 @@ void Loader::unpack(const QString &path) {
 	});
 }
 
-void Loader::finalize(const QString &path) {
-}
-
-void Loader::fail() {
-	_state = Failed();
-}
-
 void Loader::destroy() {
 	Expects(GlobalLoader == this);
 
@@ -491,7 +427,12 @@ void Row::setupHandler() {
 }
 
 void Row::load() {
-	SetGlobalLoader(base::make_unique_q<Loader>(App::main(), _id));
+	SetGlobalLoader(base::make_unique_q<Loader>(
+		App::main(),
+		_id,
+		GetDownloadLocation(_id),
+		internal::SetDataPath(_id),
+		GetDownloadSize(_id)));
 }
 
 void Row::setupLabels(const Set &set) {
diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp
index a90635462..3707cc8cb 100644
--- a/Telegram/SourceFiles/storage/storage_cloud_blob.cpp
+++ b/Telegram/SourceFiles/storage/storage_cloud_blob.cpp
@@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "storage/storage_cloud_blob.h"
 
 #include "base/zlib_help.h"
+#include "core/application.h"
+#include "main/main_account.h"
 
 namespace Storage::CloudBlob {
 
@@ -64,4 +66,61 @@ bool UnpackBlob(
 	return true;
 }
 
+BlobLoader::BlobLoader(
+	QObject *parent,
+	int id,
+	MTP::DedicatedLoader::Location location,
+	const QString &folder,
+	int size)
+: QObject(parent)
+, _folder(folder)
+, _id(id)
+, _state(Loading{ 0, size })
+, _mtproto(Core::App().activeAccount().mtp()) {
+	const auto ready = [=](std::unique_ptr<MTP::DedicatedLoader> loader) {
+		if (loader) {
+			setImplementation(std::move(loader));
+		} else {
+			fail();
+		}
+	};
+	MTP::StartDedicatedLoader(&_mtproto, location, _folder, ready);
+}
+
+int BlobLoader::id() const {
+	return _id;
+}
+
+rpl::producer<BlobState> BlobLoader::state() const {
+	return _state.value();
+}
+
+void BlobLoader::setImplementation(
+		std::unique_ptr<MTP::DedicatedLoader> loader) {
+	_implementation = std::move(loader);
+	auto convert = [](auto value) {
+		return BlobState(value);
+	};
+	_state = _implementation->progress(
+	) | rpl::map([](const Loading &state) {
+		return BlobState(state);
+	});
+	_implementation->failed(
+	) | rpl::start_with_next([=] {
+		fail();
+	}, _implementation->lifetime());
+
+	_implementation->ready(
+	) | rpl::start_with_next([=](const QString &filepath) {
+		unpack(filepath);
+	}, _implementation->lifetime());
+
+	QDir(_folder).removeRecursively();
+	_implementation->start();
+}
+
+void BlobLoader::fail() {
+	_state = Failed();
+}
+
 } // namespace Storage::CloudBlob
diff --git a/Telegram/SourceFiles/storage/storage_cloud_blob.h b/Telegram/SourceFiles/storage/storage_cloud_blob.h
index e34705f2c..a0533eee7 100644
--- a/Telegram/SourceFiles/storage/storage_cloud_blob.h
+++ b/Telegram/SourceFiles/storage/storage_cloud_blob.h
@@ -7,8 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "mtproto/dedicated_file_loader.h"
+
 namespace Storage::CloudBlob {
 
+constexpr auto kCloudLocationUsername = "tdhbcfiles"_cs;
+
 struct Blob {
 	int id = 0;
 	int postId = 0;
@@ -51,9 +55,48 @@ struct Failed {
 	}
 };
 
+using Loading = MTP::DedicatedLoader::Progress;
+using BlobState = base::variant<
+	Available,
+	Ready,
+	Active,
+	Failed,
+	Loading>;
+
 bool UnpackBlob(
 	const QString &path,
 	const QString &folder,
 	Fn<bool(const QString &)> checkNameCallback);
 
+class BlobLoader : public QObject {
+public:
+	BlobLoader(
+		QObject *parent,
+		int id,
+		MTP::DedicatedLoader::Location location,
+		const QString &folder,
+		int size);
+
+	int id() const;
+
+	rpl::producer<BlobState> state() const;
+	virtual void destroy() = 0;
+	virtual void unpack(const QString &path) = 0;
+
+protected:
+	void fail();
+
+	const QString _folder;
+
+private:
+	void setImplementation(std::unique_ptr<MTP::DedicatedLoader> loader);
+
+	int _id = 0;
+	rpl::variable<BlobState> _state;
+
+	MTP::WeakInstance _mtproto;
+	std::unique_ptr<MTP::DedicatedLoader> _implementation;
+
+};
+
 } // namespace Storage::CloudBlob