2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 06:26:18 +00:00

Add downloaded files cache in export.

Also write downloaded photo paths.
This commit is contained in:
John Preston
2018-06-17 13:47:47 +01:00
parent 07ff7c6cb0
commit 2dc3ec955a
6 changed files with 137 additions and 19 deletions

View File

@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "export/data/export_data_types.h"
#include "export/output/export_output_file.h"
#include "mtproto/rpc_sender.h"
#include "base/value_ordering.h"
#include "base/bytes.h"
#include <deque>
@@ -25,13 +26,61 @@ constexpr auto kFileNextRequestDelay = TimeMs(20);
constexpr auto kChatsSliceLimit = 100;
constexpr auto kMessagesSliceLimit = 100;
constexpr auto kFileMaxSize = 1500 * 1024 * 1024;
constexpr auto kLocationCacheSize = 100'000;
bool FileIsAvailable(const Data::File &file) {
return file.relativePath.isEmpty() && (file.location.dcId != 0);
struct LocationKey {
uint64 type;
uint64 id;
inline bool operator<(const LocationKey &other) const {
return std::tie(type, id) < std::tie(other.type, other.id);
}
};
std::tuple<const uint64 &, const uint64 &> value_ordering_helper(const LocationKey &value) {
return std::tie(
value.type,
value.id);
}
LocationKey ComputeLocationKey(const Data::FileLocation &value) {
auto result = LocationKey();
result.type = value.dcId;
value.data.match([&](const MTPDinputFileLocation &data) {
result.type |= (1ULL << 24);
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
result.id = data.vvolume_id.v;
}, [&](const MTPDinputDocumentFileLocation &data) {
result.type |= (2ULL << 24);
result.id = data.vid.v;
}, [&](const MTPDinputSecureFileLocation &data) {
result.type |= (3ULL << 24);
result.id = data.vid.v;
}, [&](const MTPDinputEncryptedFileLocation &data) {
result.type |= (4ULL << 24);
result.id = data.vid.v;
});
return result;
}
} // namespace
class ApiWrap::LoadedFileCache {
public:
using Location = Data::FileLocation;
LoadedFileCache(int limit);
void save(const Location &location, const QString &relativePath);
base::optional<QString> find(const Location &location) const;
private:
int _limit = 0;
std::map<LocationKey, QString> _map;
std::deque<LocationKey> _list;
};
struct ApiWrap::UserpicsProcess {
FnMut<void(Data::UserpicsInfo&&)> start;
Fn<void(Data::UserpicsSlice&&)> handleSlice;
@@ -94,6 +143,32 @@ struct ApiWrap::DialogsProcess::Single {
};
ApiWrap::LoadedFileCache::LoadedFileCache(int limit) : _limit(limit) {
Expects(limit >= 0);
}
void ApiWrap::LoadedFileCache::save(
const Location &location,
const QString &relativePath) {
const auto key = ComputeLocationKey(location);
_map[key] = relativePath;
_list.push_back(key);
if (_list.size() > _limit) {
const auto key = _list.front();
_list.pop_front();
_map.erase(key);
}
}
base::optional<QString> ApiWrap::LoadedFileCache::find(
const Location &location) const {
const auto key = ComputeLocationKey(location);
if (const auto i = _map.find(key); i != end(_map)) {
return i->second;
}
return base::none;
}
ApiWrap::FileProcess::FileProcess(const QString &path) : file(path) {
}
@@ -129,7 +204,8 @@ auto ApiWrap::fileRequest(const Data::FileLocation &location, int offset) {
}
ApiWrap::ApiWrap(Fn<void(FnMut<void()>)> runner)
: _mtp(std::move(runner)) {
: _mtp(std::move(runner))
, _fileCache(std::make_unique<LoadedFileCache>(kLocationCacheSize)) {
}
rpl::producer<RPCError> ApiWrap::errors() const {
@@ -613,11 +689,11 @@ bool ApiWrap::processFileLoad(
if (!file.relativePath.isEmpty()) {
return true;
} else if (writePreloadedFile(file)) {
return true;
} else if (!FileIsAvailable(file)) {
} else if (!file.location) {
file.skipReason = SkipReason::Unavailable;
return true;
} else if (writePreloadedFile(file)) {
return true;
}
using Type = MediaSettings::Type;
@@ -656,11 +732,15 @@ bool ApiWrap::writePreloadedFile(Data::File &file) {
using namespace Output;
if (!file.content.isEmpty()) {
if (const auto path = _fileCache->find(file.location)) {
file.relativePath = *path;
return true;
} else if (!file.content.isEmpty()) {
const auto process = prepareFileProcess(file);
auto &output = _fileProcess->file;
if (output.writeBlock(file.content) == File::Result::Success) {
file.relativePath = process->relativePath;
_fileCache->save(file.location, file.relativePath);
return true;
}
error(QString("Could not write '%1'.").arg(process->relativePath));
@@ -670,7 +750,7 @@ bool ApiWrap::writePreloadedFile(Data::File &file) {
void ApiWrap::loadFile(const Data::File &file, FnMut<void(QString)> done) {
Expects(_fileProcess == nullptr);
Expects(FileIsAvailable(file));
Expects(file.location.dcId != 0);
_fileProcess = prepareFileProcess(file);
_fileProcess->done = std::move(done);
@@ -767,7 +847,10 @@ void ApiWrap::filePartDone(int offset, const MTPupload_File &result) {
return;
}
}
auto process = base::take(_fileProcess);
const auto relativePath = process->relativePath;
_fileCache->save(process->location, relativePath);
process->done(process->relativePath);
}