195 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
	
		
			4.4 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
 | 
						|
*/
 | 
						|
#include "storage/file_download_mtproto.h"
 | 
						|
 | 
						|
#include "data/data_document.h"
 | 
						|
#include "data/data_file_origin.h"
 | 
						|
#include "storage/cache/storage_cache_types.h"
 | 
						|
#include "main/main_session.h"
 | 
						|
#include "apiwrap.h"
 | 
						|
#include "mtproto/mtp_instance.h"
 | 
						|
#include "mtproto/mtproto_config.h"
 | 
						|
#include "mtproto/mtproto_auth_key.h"
 | 
						|
 | 
						|
mtpFileLoader::mtpFileLoader(
 | 
						|
	not_null<Main::Session*> session,
 | 
						|
	const StorageFileLocation &location,
 | 
						|
	Data::FileOrigin origin,
 | 
						|
	LocationType type,
 | 
						|
	const QString &to,
 | 
						|
	int64 loadSize,
 | 
						|
	int64 fullSize,
 | 
						|
	LoadToCacheSetting toCache,
 | 
						|
	LoadFromCloudSetting fromCloud,
 | 
						|
	bool autoLoading,
 | 
						|
	uint8 cacheTag)
 | 
						|
: FileLoader(
 | 
						|
	session,
 | 
						|
	to,
 | 
						|
	loadSize,
 | 
						|
	fullSize,
 | 
						|
	type,
 | 
						|
	toCache,
 | 
						|
	fromCloud,
 | 
						|
	autoLoading,
 | 
						|
	cacheTag)
 | 
						|
, DownloadMtprotoTask(&session->downloader(), location, origin) {
 | 
						|
}
 | 
						|
 | 
						|
mtpFileLoader::mtpFileLoader(
 | 
						|
	not_null<Main::Session*> session,
 | 
						|
	const WebFileLocation &location,
 | 
						|
	int64 loadSize,
 | 
						|
	int64 fullSize,
 | 
						|
	LoadFromCloudSetting fromCloud,
 | 
						|
	bool autoLoading,
 | 
						|
	uint8 cacheTag)
 | 
						|
: FileLoader(
 | 
						|
	session,
 | 
						|
	QString(),
 | 
						|
	loadSize,
 | 
						|
	fullSize,
 | 
						|
	UnknownFileLocation,
 | 
						|
	LoadToCacheAsWell,
 | 
						|
	fromCloud,
 | 
						|
	autoLoading,
 | 
						|
	cacheTag)
 | 
						|
, DownloadMtprotoTask(
 | 
						|
	&session->downloader(),
 | 
						|
	session->serverConfig().webFileDcId,
 | 
						|
	{ location }) {
 | 
						|
}
 | 
						|
 | 
						|
mtpFileLoader::mtpFileLoader(
 | 
						|
	not_null<Main::Session*> session,
 | 
						|
	const GeoPointLocation &location,
 | 
						|
	int64 loadSize,
 | 
						|
	int64 fullSize,
 | 
						|
	LoadFromCloudSetting fromCloud,
 | 
						|
	bool autoLoading,
 | 
						|
	uint8 cacheTag)
 | 
						|
: FileLoader(
 | 
						|
	session,
 | 
						|
	QString(),
 | 
						|
	loadSize,
 | 
						|
	fullSize,
 | 
						|
	UnknownFileLocation,
 | 
						|
	LoadToCacheAsWell,
 | 
						|
	fromCloud,
 | 
						|
	autoLoading,
 | 
						|
	cacheTag)
 | 
						|
, DownloadMtprotoTask(
 | 
						|
	&session->downloader(),
 | 
						|
	session->serverConfig().webFileDcId,
 | 
						|
	{ location }) {
 | 
						|
}
 | 
						|
 | 
						|
mtpFileLoader::~mtpFileLoader() {
 | 
						|
	if (!_finished) {
 | 
						|
		cancel();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
Data::FileOrigin mtpFileLoader::fileOrigin() const {
 | 
						|
	return DownloadMtprotoTask::fileOrigin();
 | 
						|
}
 | 
						|
 | 
						|
uint64 mtpFileLoader::objId() const {
 | 
						|
	return DownloadMtprotoTask::objectId();
 | 
						|
}
 | 
						|
 | 
						|
bool mtpFileLoader::readyToRequest() const {
 | 
						|
	return !_finished
 | 
						|
		&& !_lastComplete
 | 
						|
		&& (_fullSize != 0 || !haveSentRequests())
 | 
						|
		&& (!_fullSize || _nextRequestOffset < _loadSize);
 | 
						|
}
 | 
						|
 | 
						|
int64 mtpFileLoader::takeNextRequestOffset() {
 | 
						|
	Expects(readyToRequest());
 | 
						|
 | 
						|
	const auto result = _nextRequestOffset;
 | 
						|
	_nextRequestOffset += Storage::kDownloadPartSize;
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
bool mtpFileLoader::feedPart(int64 offset, const QByteArray &bytes) {
 | 
						|
	const auto buffer = bytes::make_span(bytes);
 | 
						|
	if (!writeResultPart(offset, buffer)) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	if (buffer.empty() || (buffer.size() % 1024)) { // bad next offset
 | 
						|
		_lastComplete = true;
 | 
						|
	}
 | 
						|
	const auto finished = !haveSentRequests()
 | 
						|
		&& (_lastComplete || (_fullSize && _nextRequestOffset >= _loadSize));
 | 
						|
	if (finished) {
 | 
						|
		removeFromQueue();
 | 
						|
		if (!finalizeResult()) {
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		notifyAboutProgress();
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
void mtpFileLoader::cancelOnFail() {
 | 
						|
	cancel(true);
 | 
						|
}
 | 
						|
 | 
						|
bool mtpFileLoader::setWebFileSizeHook(int64 size) {
 | 
						|
	if (!_fullSize || _fullSize == size) {
 | 
						|
		_fullSize = _loadSize = size;
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	LOG(("MTP Error: "
 | 
						|
		"Bad size provided by bot for webDocument: %1, real: %2"
 | 
						|
		).arg(_fullSize
 | 
						|
		).arg(size));
 | 
						|
	cancel(true);
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
void mtpFileLoader::startLoading() {
 | 
						|
	addToQueue();
 | 
						|
}
 | 
						|
 | 
						|
void mtpFileLoader::startLoadingWithPartial(const QByteArray &data) {
 | 
						|
	Expects(data.startsWith("partial:"));
 | 
						|
 | 
						|
	constexpr auto kPrefix = 8;
 | 
						|
	const auto parts = (data.size() - kPrefix) / Storage::kDownloadPartSize;
 | 
						|
	const auto use = parts * int64(Storage::kDownloadPartSize);
 | 
						|
	if (use > 0) {
 | 
						|
		_nextRequestOffset = use;
 | 
						|
		feedPart(0, QByteArray::fromRawData(data.data() + kPrefix, use));
 | 
						|
	}
 | 
						|
	startLoading();
 | 
						|
}
 | 
						|
 | 
						|
void mtpFileLoader::cancelHook() {
 | 
						|
	cancelAllRequests();
 | 
						|
}
 | 
						|
 | 
						|
Storage::Cache::Key mtpFileLoader::cacheKey() const {
 | 
						|
	return v::match(location().data, [&](const WebFileLocation &location) {
 | 
						|
		return Data::WebDocumentCacheKey(location);
 | 
						|
	}, [&](const GeoPointLocation &location) {
 | 
						|
		return Data::GeoPointCacheKey(location);
 | 
						|
	}, [&](const StorageFileLocation &location) {
 | 
						|
		return location.cacheKey();
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
std::optional<MediaKey> mtpFileLoader::fileLocationKey() const {
 | 
						|
	if (_locationType != UnknownFileLocation) {
 | 
						|
		return mediaKey(_locationType, dcId(), objId());
 | 
						|
	}
 | 
						|
	return std::nullopt;
 | 
						|
}
 |