tdesktop/Telegram/SourceFiles/data/data_download_manager.h

210 lines
5.8 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/timer.h"
namespace Ui {
struct DownloadBarProgress;
struct DownloadBarContent;
} // namespace Ui
namespace Main {
class Session;
} // namespace Main
namespace Data {
// Used in serialization!
enum class DownloadType {
Document,
Photo,
};
// unixtime * 1000.
using DownloadDate = int64;
[[nodiscard]] inline TimeId DateFromDownloadDate(DownloadDate date) {
return date / 1000;
}
struct DownloadId {
uint64 objectId = 0;
DownloadType type = DownloadType::Document;
};
struct DownloadProgress {
int64 ready = 0;
int64 total = 0;
};
inline constexpr bool operator==(
const DownloadProgress &a,
const DownloadProgress &b) {
return (a.ready == b.ready) && (a.total == b.total);
}
struct DownloadObject {
not_null<HistoryItem*> item;
DocumentData *document = nullptr;
PhotoData *photo = nullptr;
};
struct DownloadedId {
DownloadId download;
DownloadDate started = 0;
QString path;
int32 size = 0;
FullMsgId itemId;
uint64 peerAccessHash = 0;
std::unique_ptr<DownloadObject> object;
};
struct DownloadingId {
DownloadObject object;
DownloadDate started = 0;
QString path;
int ready = 0;
int total = 0;
bool hiddenByView = false;
bool done = false;
};
class DownloadManager final {
public:
DownloadManager();
~DownloadManager();
void trackSession(not_null<Main::Session*> session);
void itemVisibilitiesUpdated(not_null<Main::Session*> session);
[[nodiscard]] DownloadDate computeNextStartDate();
void addLoading(DownloadObject object);
void addLoaded(
DownloadObject object,
const QString &path,
DownloadDate started);
void clearIfFinished();
void deleteFiles(const std::vector<GlobalMsgId> &ids);
void deleteAll();
[[nodiscard]] bool loadedHasNonCloudFile() const;
[[nodiscard]] auto loadingList() const
-> ranges::any_view<const DownloadingId*, ranges::category::input>;
[[nodiscard]] DownloadProgress loadingProgress() const;
[[nodiscard]] rpl::producer<> loadingListChanges() const;
[[nodiscard]] auto loadingProgressValue() const
-> rpl::producer<DownloadProgress>;
[[nodiscard]] bool loadingInProgress(
Main::Session *onlyInSession = nullptr) const;
void loadingStopWithConfirmation(
Fn<void()> callback,
Main::Session *onlyInSession = nullptr);
[[nodiscard]] auto loadedList()
-> ranges::any_view<const DownloadedId*, ranges::category::input>;
[[nodiscard]] auto loadedAdded() const
-> rpl::producer<not_null<const DownloadedId*>>;
[[nodiscard]] auto loadedRemoved() const
-> rpl::producer<not_null<const HistoryItem*>>;
[[nodiscard]] rpl::producer<> loadedResolveDone() const;
private:
struct DeleteFilesDescriptor;
struct SessionData {
std::vector<DownloadedId> downloaded;
std::vector<DownloadingId> downloading;
int resolveNeeded = 0;
int resolveSentRequests = 0;
int resolveSentTotal = 0;
rpl::lifetime lifetime;
};
void check(not_null<const HistoryItem*> item);
void check(not_null<DocumentData*> document);
void check(
SessionData &data,
std::vector<DownloadingId>::iterator i);
void changed(not_null<const HistoryItem*> item);
void removed(not_null<const HistoryItem*> item);
void detach(DownloadedId &id);
void untrack(not_null<Main::Session*> session);
void remove(
SessionData &data,
std::vector<DownloadingId>::iterator i);
void cancel(
SessionData &data,
std::vector<DownloadingId>::iterator i);
void clearLoading();
[[nodiscard]] SessionData &sessionData(not_null<Main::Session*> session);
[[nodiscard]] const SessionData &sessionData(
not_null<Main::Session*> session) const;
[[nodiscard]] SessionData &sessionData(
not_null<const HistoryItem*> item);
[[nodiscard]] SessionData &sessionData(not_null<DocumentData*> document);
void resolve(not_null<Main::Session*> session, SessionData &data);
void resolveRequestsFinished(
not_null<Main::Session*> session,
SessionData &data);
void checkFullResolveDone();
[[nodiscard]] not_null<HistoryItem*> regenerateItem(
const DownloadObject &previous);
[[nodiscard]] not_null<HistoryItem*> generateFakeItem(
not_null<DocumentData*> document);
[[nodiscard]] not_null<HistoryItem*> generateItem(
HistoryItem *previousItem,
DocumentData *document,
PhotoData *photo);
void generateEntry(not_null<Main::Session*> session, DownloadedId &id);
[[nodiscard]] HistoryItem *lookupLoadingItem(
Main::Session *onlyInSession) const;
void loadingStop(Main::Session *onlyInSession);
void finishFilesDelete(DeleteFilesDescriptor &&descriptor);
void writePostponed(not_null<Main::Session*> session);
[[nodiscard]] Fn<std::optional<QByteArray>()> serializator(
not_null<Main::Session*> session) const;
[[nodiscard]] std::vector<DownloadedId> deserialize(
not_null<Main::Session*> session) const;
base::flat_map<not_null<Main::Session*>, SessionData> _sessions;
base::flat_set<not_null<const HistoryItem*>> _loading;
base::flat_set<not_null<DocumentData*>> _loadingDocuments;
base::flat_set<not_null<const HistoryItem*>> _loadingDone;
base::flat_set<not_null<const HistoryItem*>> _loaded;
base::flat_set<not_null<HistoryItem*>> _generated;
base::flat_set<not_null<DocumentData*>> _generatedDocuments;
TimeId _lastStartedBase = 0;
int _lastStartedAdded = 0;
rpl::event_stream<> _loadingListChanges;
rpl::variable<DownloadProgress> _loadingProgress;
rpl::event_stream<not_null<const DownloadedId*>> _loadedAdded;
rpl::event_stream<not_null<const HistoryItem*>> _loadedRemoved;
rpl::variable<bool> _loadedResolveDone;
base::Timer _clearLoadingTimer;
};
[[nodiscard]] auto MakeDownloadBarProgress()
-> rpl::producer<Ui::DownloadBarProgress>;
[[nodiscard]] rpl::producer<Ui::DownloadBarContent> MakeDownloadBarContent();
} // namespace Data