Add td_api::getMapThumbnailFile.

GitOrigin-RevId: f02f154cc8a3ce62f888bdaf9c159cebcb4a350a
This commit is contained in:
levlam 2018-08-13 23:18:27 +03:00
parent e27e4f405e
commit c6bc8f7c3f
10 changed files with 217 additions and 4 deletions

View File

@ -3277,6 +3277,10 @@ setStickerPositionInSet sticker:InputFile position:int32 = Ok;
removeStickerFromSet sticker:InputFile = Ok;
//@description Returns information about a file with a map thumbnail @location Location of the map center @zoom Map zoom level; 13-20 @width Map width in pixels before applying scale; 16-1024 @height Map height in pixels before applying scale; 16-1024 @scale Map scale; 1-3 @chat_id Identifier of a chat, in which the thumbnail will be shown. Use 0 if unknown
getMapThumbnailFile location:location zoom:int32 width:int32 height:int32 scale:int32 chat_id:int53 = File;
//@description Accepts Telegram terms of services @terms_of_service_id Terms of service identifier
acceptTermsOfService terms_of_service_id:string = Ok;

Binary file not shown.

View File

@ -64,6 +64,11 @@ bool Location::empty() const {
return is_empty_;
}
bool Location::is_valid_map_point() const {
const double MAX_VALID_MAP_LATITUDE = 85.05112877;
return !empty() && std::abs(latitude_) <= MAX_VALID_MAP_LATITUDE;
}
tl_object_ptr<td_api::location> Location::get_location_object() const {
if (empty()) {
return nullptr;

View File

@ -45,6 +45,8 @@ class Location {
bool empty() const;
bool is_valid_map_point() const;
tl_object_ptr<td_api::location> get_location_object() const;
tl_object_ptr<telegram_api::InputGeoPoint> get_input_geo_point() const;

View File

@ -5988,6 +5988,21 @@ void Td::on_request(uint64 id, const td_api::resetAllNotificationSettings &reque
send_closure(actor_id(this), &Td::send_result, id, make_tl_object<td_api::ok>());
}
void Td::on_request(uint64 id, const td_api::getMapThumbnailFile &request) {
DialogId dialog_id(request.chat_id_);
if (!messages_manager_->have_dialog_force(dialog_id)) {
dialog_id = DialogId();
}
auto r_file_id = file_manager_->get_map_thumbnail_file_id(Location(request.location_), request.zoom_, request.width_,
request.height_, request.scale_, dialog_id);
if (r_file_id.is_error()) {
send_closure(actor_id(this), &Td::send_error, id, r_file_id.move_as_error());
} else {
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(r_file_id.ok()));
}
}
void Td::on_request(uint64 id, const td_api::getLanguagePackInfo &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();

View File

@ -755,6 +755,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::reportChat &request);
void on_request(uint64 id, const td_api::getMapThumbnailFile &request);
void on_request(uint64 id, const td_api::getLanguagePackInfo &request);
void on_request(uint64 id, td_api::getLanguagePackStrings &request);

View File

@ -2195,6 +2195,24 @@ class CliClient final : public Actor {
send_request(make_tl_object<td_api::getFile>(as_file_id(args)));
} else if (op == "grf") {
send_request(make_tl_object<td_api::getRemoteFile>(args, nullptr));
} else if (op == "gmtf") {
string latitude;
string longitude;
string zoom;
string width;
string height;
string scale;
string chat_id;
std::tie(latitude, args) = split(args);
std::tie(longitude, args) = split(args);
std::tie(zoom, args) = split(args);
std::tie(width, args) = split(args);
std::tie(height, args) = split(args);
std::tie(scale, chat_id) = split(args);
send_request(make_tl_object<td_api::getMapThumbnailFile>(
as_location(latitude, longitude), to_integer<int32>(zoom), to_integer<int32>(width),
to_integer<int32>(height), to_integer<int32>(scale), as_chat_id(chat_id)));
} else if (op == "df" || op == "DownloadFile") {
string file_id_str;
string priority;

View File

@ -12,6 +12,8 @@
#include "td/telegram/files/FileLoaderUtils.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/Td.h"
#include "td/utils/common.h"
@ -20,6 +22,7 @@
#include "td/utils/port/path.h"
#include "td/utils/Slice.h"
#include <cmath>
#include <utility>
namespace td {
@ -56,7 +59,7 @@ class FileDownloadGenerateActor : public FileGenerateActor {
ActorShared<> parent_;
void start_up() override {
LOG(INFO) << "DOWNLOAD " << file_id_;
LOG(INFO) << "Generate by downloading " << file_id_;
class Callback : public FileManager::DownloadCallback {
public:
explicit Callback(ActorId<FileDownloadGenerateActor> parent) : parent_(std::move(parent)) {
@ -91,7 +94,7 @@ class FileDownloadGenerateActor : public FileGenerateActor {
callback->on_ok(location);
} else {
LOG(ERROR) << "Expected to have local location";
callback->on_error(Status::Error("Unknown"));
callback->on_error(Status::Error(500, "Unknown"));
}
});
stop();
@ -102,6 +105,129 @@ class FileDownloadGenerateActor : public FileGenerateActor {
}
};
class MapDownloadGenerateActor : public FileGenerateActor {
public:
MapDownloadGenerateActor(string conversion, std::unique_ptr<FileGenerateCallback> callback, ActorShared<> parent)
: conversion_(std::move(conversion)), callback_(std::move(callback)), parent_(std::move(parent)) {
}
void file_generate_progress(int32 expected_size, int32 local_prefix_size, Promise<> promise) override {
UNREACHABLE();
}
void file_generate_finish(Status status, Promise<> promise) override {
UNREACHABLE();
}
private:
string conversion_;
std::unique_ptr<FileGenerateCallback> callback_;
ActorShared<> parent_;
string file_name_;
class Callback : public NetQueryCallback {
ActorId<MapDownloadGenerateActor> parent_;
public:
explicit Callback(ActorId<MapDownloadGenerateActor> parent) : parent_(parent) {
}
void on_result(NetQueryPtr query) override {
send_closure(parent_, &MapDownloadGenerateActor::on_result, std::move(query));
}
void hangup_shared() override {
send_closure(parent_, &MapDownloadGenerateActor::hangup_shared);
}
};
ActorOwn<NetQueryCallback> net_callback_;
Result<tl_object_ptr<telegram_api::inputWebFileGeoPointLocation>> parse_conversion() {
auto parts = full_split(Slice(conversion_), '#');
if (parts.size() != 8 || !parts[0].empty() || parts[1] != "map") {
return Status::Error("Wrong conversion");
}
TRY_RESULT(zoom, to_integer_safe<int32>(parts[2]));
TRY_RESULT(x, to_integer_safe<int32>(parts[3]));
TRY_RESULT(y, to_integer_safe<int32>(parts[4]));
TRY_RESULT(width, to_integer_safe<int32>(parts[5]));
TRY_RESULT(height, to_integer_safe<int32>(parts[6]));
TRY_RESULT(scale, to_integer_safe<int32>(parts[7]));
int64 access_hash = 0;
if (zoom < 13 || zoom > 20) {
return Status::Error("Wrong zoom");
}
auto size = 256 * (1 << zoom);
if (x < 0 || x >= size) {
return Status::Error("Wrong x");
}
if (y < 0 || y >= size) {
return Status::Error("Wrong y");
}
if (width < 16 || height < 16 || width > 1024 || height > 1024) {
return Status::Error("Wrong dimensions");
}
if (scale < 1 || scale > 3) {
return Status::Error("Wrong scale");
}
file_name_ = PSTRING() << "map_" << zoom << "_" << x << "_" << y << ".jpg";
const double PI = 3.14159265358979323846;
double longitude = (x + 0.1) * 360.0 / size - 180;
double latitude = 90 - 360 * std::atan(std::exp(((y + 0.1) / size - 0.5) * 2 * PI)) / PI;
return make_tl_object<telegram_api::inputWebFileGeoPointLocation>(
make_tl_object<telegram_api::inputGeoPoint>(latitude, longitude), access_hash, width, height, zoom, scale);
}
void start_up() override {
auto r_input_web_file = parse_conversion();
if (r_input_web_file.is_error()) {
LOG(ERROR) << "Can't parse " << conversion_ << ": " << r_input_web_file.error();
return on_error(r_input_web_file.move_as_error());
}
net_callback_ = create_actor<Callback>("MapDownloadGenerateCallback", actor_id(this));
LOG(INFO) << "Download " << conversion_;
auto query = G()->net_query_creator().create(
create_storer(telegram_api::upload_getWebFile(r_input_web_file.move_as_ok(), 0, 1 << 20)),
G()->get_webfile_dc_id(), NetQuery::Type::DownloadSmall);
G()->net_query_dispatcher().dispatch_with_callback(std::move(query), {net_callback_.get(), 0});
}
void on_result(NetQueryPtr query) {
auto r_result = process_result(std::move(query));
if (r_result.is_error()) {
return on_error(r_result.move_as_error());
}
callback_->on_ok(r_result.ok());
stop();
}
Result<FullLocalFileLocation> process_result(NetQueryPtr query) {
TRY_RESULT(web_file, fetch_result<telegram_api::upload_getWebFile>(std::move(query)));
if (static_cast<size_t>(web_file->size_) != web_file->bytes_.size()) {
LOG(ERROR) << "Failed to download map of size " << web_file->size_;
return Status::Error("File is too big");
}
return save_file_bytes(FileType::Thumbnail, std::move(web_file->bytes_), file_name_);
}
void on_error(Status error) {
callback_->on_error(std::move(error));
stop();
}
void hangup_shared() {
on_error(Status::Error(1, "Cancelled"));
}
};
class FileExternalGenerateActor : public FileGenerateActor {
public:
FileExternalGenerateActor(uint64 query_id, const FullGenerateFileLocation &generate_location,
@ -226,6 +352,9 @@ void FileGenerateManager::generate_file(uint64 query_id, const FullGenerateFileL
auto file_id = FileId(to_integer<int32>(conversion.substr(file_id_query.size())), 0);
query.worker_ = create_actor<FileDownloadGenerateActor>("FileDownloadGenerateActor", generate_location.file_type_,
file_id, std::move(callback), std::move(parent));
} else if (begins_with(conversion, "#map#") && generate_location.original_path_.empty()) {
query.worker_ = create_actor<MapDownloadGenerateActor>(
"MapDownloadGenerateActor", std::move(generate_location.conversion_), std::move(callback), std::move(parent));
} else {
query.worker_ = create_actor<FileExternalGenerateActor>("FileExternalGenerationActor", query_id, generate_location,
local_location, std::move(name), std::move(callback),

View File

@ -28,6 +28,7 @@
#include "td/utils/tl_helpers.h"
#include <algorithm>
#include <cmath>
#include <limits>
#include <tuple>
#include <utility>
@ -168,7 +169,8 @@ void FileNode::set_upload_priority(int8 priority) {
}
void FileNode::set_generate_priority(int8 download_priority, int8 upload_priority) {
if ((download_priority_ == 0) != (download_priority == 0) || (upload_priority_ == 0) != (upload_priority == 0)) {
if ((generate_download_priority_ == 0) != (download_priority == 0) ||
(generate_upload_priority_ == 0) != (upload_priority == 0)) {
VLOG(update_file) << "File " << main_file_id_ << " has changed generate priority to " << download_priority << "/"
<< upload_priority;
on_info_changed();
@ -561,7 +563,7 @@ Status FileManager::check_local_location(FullLocalFileLocation &location, int64
return Status::Error(PSLICE() << "File \"" << location.path_ << "\" was modified");
}
if ((location.file_type_ == FileType::Thumbnail || location.file_type_ == FileType::EncryptedThumbnail) &&
size >= MAX_THUMBNAIL_SIZE) {
size >= MAX_THUMBNAIL_SIZE && !begins_with(PathView(location.path_).file_name(), "map")) {
return Status::Error(PSLICE() << "File \"" << location.path_ << "\" is too big for thumbnail "
<< tag("size", format::as_size(size)));
}
@ -2058,6 +2060,38 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
return check_input_file_id(type, std::move(r_file_id), is_encrypted, allow_zero, is_secure);
}
Result<FileId> FileManager::get_map_thumbnail_file_id(Location location, int32 zoom, int32 width, int32 height,
int32 scale, DialogId owner_dialog_id) {
if (!location.is_valid_map_point()) {
return Status::Error(6, "Invalid location specified");
}
if (zoom < 13 || zoom > 20) {
return Status::Error(6, "Wrong zoom");
}
if (width < 16 || width > 1024) {
return Status::Error(6, "Wrong width");
}
if (height < 16 || height > 1024) {
return Status::Error(6, "Wrong height");
}
if (scale < 1 || scale > 3) {
return Status::Error(6, "Wrong scale");
}
const double PI = 3.14159265358979323846;
double sin_latitude = std::sin(location.get_latitude() * PI / 180);
int32 size = 256 * (1 << zoom);
int32 x = static_cast<int32>((location.get_longitude() + 180) / 360 * size);
int32 y = static_cast<int32>((0.5 - std::log((1 + sin_latitude) / (1 - sin_latitude)) / (4 * PI)) * size);
x = clamp(x, 0, size - 1); // just in case
y = clamp(y, 0, size - 1); // just in case
string conversion = PSTRING() << "#map#" << zoom << "#" << x << "#" << y << "#" << width << "#" << height << "#"
<< scale << "#";
return register_generate(FileType::Thumbnail, FileLocationSource::FromUser, string(), std::move(conversion),
owner_dialog_id, 0);
}
vector<tl_object_ptr<telegram_api::InputDocument>> FileManager::get_input_documents(const vector<FileId> &file_ids) {
vector<tl_object_ptr<telegram_api::InputDocument>> result;
result.reserve(file_ids.size());

View File

@ -16,6 +16,7 @@
#include "td/telegram/files/FileLoadManager.h"
#include "td/telegram/files/FileLocation.h"
#include "td/telegram/files/FileStats.h"
#include "td/telegram/Location.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
@ -350,6 +351,9 @@ class FileManager : public FileLoadManager::Callback {
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
bool get_by_hash = false, bool is_secure = false) TD_WARN_UNUSED_RESULT;
Result<FileId> get_map_thumbnail_file_id(Location location, int32 zoom, int32 width, int32 height, int32 scale,
DialogId owner_dialog_id) TD_WARN_UNUSED_RESULT;
vector<tl_object_ptr<telegram_api::InputDocument>> get_input_documents(const vector<FileId> &file_ids);
template <class T>