199 lines
5.5 KiB
C++
199 lines
5.5 KiB
C++
|
//
|
||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||
|
//
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
//
|
||
|
#include "DownloadManager.h"
|
||
|
#include "td/utils/algorithm.h"
|
||
|
#include "td/utils/FlatHashMap.h"
|
||
|
namespace td {
|
||
|
class DownloadManagerImpl final : public DownloadManager {
|
||
|
public:
|
||
|
void set_callback(unique_ptr<Callback> callback) final {
|
||
|
callback_ = std::move(callback);
|
||
|
loop();
|
||
|
}
|
||
|
|
||
|
Status toggle_is_paused(FileId file_id, bool is_paused) final {
|
||
|
if (!callback_) {
|
||
|
return Status::OK();
|
||
|
}
|
||
|
auto it = active_files_.find(file_id);
|
||
|
if (it == active_files_.end()) {
|
||
|
return Status::Error(400, "Can't find file");
|
||
|
}
|
||
|
|
||
|
auto &file_info = it->second;
|
||
|
if (is_paused != file_info.is_paused) {
|
||
|
file_info.is_paused = is_paused;
|
||
|
if (is_paused) {
|
||
|
callback_->pause_file(file_info.internal_file_id);
|
||
|
} else {
|
||
|
callback_->start_file(file_info.internal_file_id, file_info.priority);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO: update db
|
||
|
|
||
|
return Status::OK();
|
||
|
}
|
||
|
|
||
|
void toggle_all_is_paused(bool is_paused) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
for (auto &it : active_files_) {
|
||
|
toggle_is_paused(it.key(), is_paused);
|
||
|
}
|
||
|
|
||
|
// TODO: update db
|
||
|
}
|
||
|
|
||
|
void remove_file(FileId file_id, FileSourceId file_source_id, bool delete_from_cache) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
auto it = active_files_.find(file_id);
|
||
|
if (it != active_files_.end() && (!file_source_id.is_valid() || file_source_id == it->second.file_source_id)) {
|
||
|
auto &file_info = it->second;
|
||
|
if (!file_info.is_paused) {
|
||
|
callback_->pause_file(file_info.internal_file_id);
|
||
|
}
|
||
|
if (delete_from_cache) {
|
||
|
callback_->delete_file(file_info.internal_file_id);
|
||
|
}
|
||
|
by_internal_file_id_.erase(file_info.internal_file_id);
|
||
|
|
||
|
active_files_.erase(it);
|
||
|
}
|
||
|
// TODO: remove from db
|
||
|
}
|
||
|
|
||
|
void remove_all_files(bool only_active, bool only_completed, bool delete_from_cache) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
if (!only_completed) {
|
||
|
td::table_remove_if(active_files_, [&](auto &it) {
|
||
|
FileInfo &file_info = it.second;
|
||
|
if (!file_info.is_paused) {
|
||
|
callback_->pause_file(file_info.internal_file_id);
|
||
|
}
|
||
|
if (delete_from_cache) {
|
||
|
callback_->delete_file(file_info.internal_file_id);
|
||
|
}
|
||
|
return true;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// TODO: remove from db. should respect only_active
|
||
|
// TODO: if delete_from_cache, should iterate all files in db
|
||
|
}
|
||
|
|
||
|
void add_file(FileId file_id, FileSourceId file_source_id, std::string search_by, int8 priority) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
FileInfo file_info;
|
||
|
file_info.internal_file_id = callback_->dup_file_id(file_id);
|
||
|
file_info.file_source_id = file_source_id;
|
||
|
file_info.is_paused = false;
|
||
|
file_info.priority = priority;
|
||
|
by_internal_file_id_[file_info.internal_file_id] = file_id;
|
||
|
|
||
|
if (active_files_.count(file_id) == 0) {
|
||
|
counters_.total_count++;
|
||
|
callback_->update_counters(counters_);
|
||
|
}
|
||
|
active_files_[file_id] = file_info;
|
||
|
callback_->start_file(file_info.internal_file_id, file_info.priority);
|
||
|
|
||
|
// TODO: add file to db
|
||
|
}
|
||
|
|
||
|
FoundFileDownloads search(std::string query, bool only_active, bool only_completed, std::string offset,
|
||
|
int32 limit) final {
|
||
|
if (!callback_) {
|
||
|
return {};
|
||
|
}
|
||
|
// TODO: query to database
|
||
|
return FoundFileDownloads();
|
||
|
}
|
||
|
|
||
|
void update_file_download_state(FileId internal_file_id, int64 download_size, int64 size, bool is_paused) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto by_internal_file_id_it = by_internal_file_id_.find(internal_file_id);
|
||
|
if (by_internal_file_id_it == by_internal_file_id_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
auto it = active_files_.find(by_internal_file_id_it->second);
|
||
|
CHECK(it != active_files_.end());
|
||
|
auto &file_info = it->second;
|
||
|
counters_.downloaded_size -= file_info.downloaded_size;
|
||
|
counters_.total_count -= file_info.size;
|
||
|
file_info.size = size;
|
||
|
file_info.downloaded_size = download_size;
|
||
|
counters_.downloaded_size += file_info.downloaded_size;
|
||
|
counters_.total_count += file_info.size;
|
||
|
file_info.is_paused = is_paused;
|
||
|
|
||
|
if (download_size == size) {
|
||
|
active_files_.erase(it);
|
||
|
by_internal_file_id_.erase(by_internal_file_id_it);
|
||
|
|
||
|
if (active_files_.empty()) {
|
||
|
counters_ = {};
|
||
|
}
|
||
|
}
|
||
|
callback_->update_counters(counters_);
|
||
|
}
|
||
|
|
||
|
void update_file_deleted(FileId internal_file_id) final {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto it = by_internal_file_id_.find(internal_file_id);
|
||
|
if (it == by_internal_file_id_.end()) {
|
||
|
return;
|
||
|
}
|
||
|
remove_file(it->second, {}, false);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
unique_ptr<Callback> callback_;
|
||
|
struct FileInfo {
|
||
|
int8 priority;
|
||
|
bool is_paused{};
|
||
|
FileId internal_file_id{};
|
||
|
FileSourceId file_source_id{};
|
||
|
|
||
|
int64 size{};
|
||
|
int64 downloaded_size{};
|
||
|
};
|
||
|
FlatHashMap<FileId, FileInfo, FileIdHash> active_files_;
|
||
|
FlatHashMap<FileId, FileId, FileIdHash> by_internal_file_id_;
|
||
|
|
||
|
Counters counters_;
|
||
|
|
||
|
void loop() override {
|
||
|
if (!callback_) {
|
||
|
return;
|
||
|
}
|
||
|
// TODO: ???
|
||
|
// TODO: load active files from db
|
||
|
}
|
||
|
void tear_down() override {
|
||
|
callback_.reset();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
unique_ptr<DownloadManager> DownloadManager::create() {
|
||
|
return make_unique<DownloadManagerImpl>();
|
||
|
}
|
||
|
} // namespace td
|