Merge version 6.2

This commit is contained in:
Giuseppe Marino 2022-08-21 20:16:05 +02:00
commit bcc8c6e60e
No known key found for this signature in database
GPG Key ID: C26F7A532ADEC25E
15 changed files with 360 additions and 175 deletions

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TelegramBotApi VERSION 6.1 LANGUAGES CXX)
project(TelegramBotApi VERSION 6.2 LANGUAGES CXX)
if (POLICY CMP0069)
option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.")

View File

@ -181,7 +181,7 @@
<div class="main">
<div id="osSelectDiv" class="large">
<p>Choose an operating system, on which you want to use the Telegram Bot API server:</p>
<p>Choose an operating system on which you want to use the Telegram Bot API server:</p>
<select id="osSelect" onchange="onOsChanged(false)" autofocus class="large">
<option>Choose an operating system:</option>
<option>Windows</option>
@ -195,7 +195,7 @@
</div>
<div id="linuxSelectDiv" class="hide">
<p>Choose a Linux distro, on which you want to use the Telegram Bot API server:</p>
<p>Choose a Linux distro on which you want to use the Telegram Bot API server:</p>
<select id="linuxSelect" onchange="onOsChanged(false)" class="large">
<option>Choose a Linux distro:</option>
<option>Alpine</option>
@ -207,6 +207,7 @@
<option>Ubuntu 16</option>
<option>Ubuntu 18</option>
<option>Ubuntu 20</option>
<option>Ubuntu 22</option>
<option>Other</option>
</select>
<p></p>
@ -493,6 +494,8 @@ function onOptionsChanged() {
return '-6.0';
case 'Ubuntu 20':
return '-10';
case 'Ubuntu 22':
return '-14';
default:
return ''; // use default version
}
@ -534,6 +537,7 @@ function onOptionsChanged() {
case 'Ubuntu 16':
case 'Ubuntu 18':
case 'Ubuntu 20':
case 'Ubuntu 22':
if (linux_distro.includes('Debian') && !use_root) {
commands.push('su -');
}
@ -550,7 +554,7 @@ function onOptionsChanged() {
}
if (use_clang) {
packages += ' clang' + getClangVersionSuffix() + ' libc++-dev';
if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20') {
if (linux_distro === 'Debian 10+' || linux_distro === 'Ubuntu 18' || linux_distro === 'Ubuntu 20' || linux_distro === 'Ubuntu 22') {
packages += ' libc++abi-dev';
}
} else {

2
td

@ -1 +1 @@
Subproject commit b393215d6671863b6baf2a589d343cff9474f6ba
Subproject commit d9cfcf88fe4ad06dae1716ce8f66bbeb7f9491d9

View File

@ -10,7 +10,7 @@
#include "td/db/TQueue.h"
#include "td/actor/PromiseFuture.h"
#include "td/actor/MultiPromise.h"
#include "td/actor/SleepActor.h"
#include "td/utils/algorithm.h"
@ -22,7 +22,6 @@
#include "td/utils/misc.h"
#include "td/utils/PathView.h"
#include "td/utils/port/path.h"
#include "td/utils/port/Stat.h"
#include "td/utils/Slice.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Span.h"
@ -207,6 +206,12 @@ Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_us
CHECK(is_inited);
}
Client::~Client() {
td::Scheduler::instance()->destroy_on_scheduler(get_file_gc_scheduler_id(), messages_, users_, groups_, supergroups_,
chats_, reply_message_ids_, yet_unsent_reply_message_ids_,
sticker_set_names_);
}
bool Client::init_methods() {
methods_.emplace("getme", &Client::process_get_me_query);
methods_.emplace("getmycommands", &Client::process_get_my_commands_query);
@ -285,6 +290,7 @@ bool Client::init_methods() {
methods_.emplace("approvechatjoinrequest", &Client::process_approve_chat_join_request_query);
methods_.emplace("declinechatjoinrequest", &Client::process_decline_chat_join_request_query);
methods_.emplace("getstickerset", &Client::process_get_sticker_set_query);
methods_.emplace("getcustomemojistickers", &Client::process_get_custom_emoji_stickers_query);
methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query);
methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query);
methods_.emplace("addstickertoset", &Client::process_add_sticker_to_set_query);
@ -526,6 +532,12 @@ class Client::JsonEntity final : public Jsonable {
object("user", JsonUser(entity->user_id_, client_));
break;
}
case td_api::textEntityTypeCustomEmoji::ID: {
auto entity = static_cast<const td_api::textEntityTypeCustomEmoji *>(entity_->type_.get());
object("type", "custom_emoji");
object("custom_emoji_id", td::to_string(entity->custom_emoji_id_));
break;
}
default:
UNREACHABLE();
}
@ -738,6 +750,9 @@ class Client::JsonChat final : public Jsonable {
if (user_info->has_private_forwards) {
object("has_private_forwards", td::JsonTrue());
}
if (user_info->has_restricted_voice_and_video_messages) {
object("has_restricted_voice_and_video_messages", td::JsonTrue());
}
}
photo = user_info->photo.get();
break;
@ -1117,14 +1132,20 @@ class Client::JsonSticker final : public Jsonable {
if (!set_name.empty()) {
object("set_name", set_name);
}
auto type = sticker_->type_->get_id();
object("is_animated", td::JsonBool(type == td_api::stickerTypeAnimated::ID));
object("is_video", td::JsonBool(type == td_api::stickerTypeVideo::ID));
if (type == td_api::stickerTypeMask::ID) {
const auto &mask_position = static_cast<const td_api::stickerTypeMask *>(sticker_->type_.get())->mask_position_;
if (mask_position != nullptr) {
object("mask_position", JsonMaskPosition(mask_position.get()));
}
auto format = sticker_->format_->get_id();
object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID));
object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID));
object("type", Client::get_sticker_type(sticker_->type_));
if (sticker_->custom_emoji_id_ != 0) {
object("custom_emoji_id", td::to_string(sticker_->custom_emoji_id_));
}
const auto &mask_position = sticker_->mask_position_;
if (mask_position != nullptr) {
object("mask_position", JsonMaskPosition(mask_position.get()));
}
if (sticker_->premium_animation_ != nullptr) {
object("premium_animation", JsonFile(sticker_->premium_animation_.get(), client_, false));
@ -2136,6 +2157,8 @@ void Client::JsonMessage::store(JsonValueScope *scope) const {
object("web_app_data", JsonWebAppData(content));
break;
}
case td_api::messageGiftedPremium::ID:
break;
default:
UNREACHABLE();
}
@ -2751,10 +2774,15 @@ class Client::JsonStickerSet final : public Jsonable {
if (sticker_set_->thumbnail_ != nullptr) {
client_->json_store_thumbnail(object, sticker_set_->thumbnail_.get());
}
auto type = sticker_set_->sticker_type_->get_id();
object("is_animated", td::JsonBool(type == td_api::stickerTypeAnimated::ID));
object("is_video", td::JsonBool(type == td_api::stickerTypeVideo::ID));
object("contains_masks", td::JsonBool(type == td_api::stickerTypeMask::ID));
auto format = sticker_set_->sticker_format_->get_id();
object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID));
object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID));
auto type = Client::get_sticker_type(sticker_set_->sticker_type_);
object("sticker_type", type);
object("contains_masks", td::JsonBool(type == "mask"));
object("stickers", JsonStickers(sticker_set_->stickers_, client_));
}
@ -4075,6 +4103,68 @@ class Client::TdOnReturnStickerSetCallback final : public TdQueryCallback {
PromisedQueryPtr query_;
};
class Client::TdOnGetStickerSetPromiseCallback final : public TdQueryCallback {
public:
TdOnGetStickerSetPromiseCallback(Client *client, td::Promise<td::Unit> &&promise)
: client_(client), promise_(std::move(promise)) {
}
void on_result(object_ptr<td_api::Object> result) final {
if (result->get_id() == td_api::error::ID) {
auto error = move_object_as<td_api::error>(result);
return promise_.set_error(Status::Error(error->code_, error->message_));
}
CHECK(result->get_id() == td_api::stickerSet::ID);
auto sticker_set = move_object_as<td_api::stickerSet>(result);
client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_);
promise_.set_value(td::Unit());
}
private:
Client *client_;
td::Promise<td::Unit> promise_;
};
class Client::TdOnGetStickersCallback final : public TdQueryCallback {
public:
TdOnGetStickersCallback(Client *client, PromisedQueryPtr query) : client_(client), query_(std::move(query)) {
}
void on_result(object_ptr<td_api::Object> result) final {
if (result->get_id() == td_api::error::ID) {
return fail_query_with_error(std::move(query_), move_object_as<td_api::error>(result));
}
CHECK(result->get_id() == td_api::stickers::ID);
auto stickers = move_object_as<td_api::stickers>(result);
td::FlatHashSet<int64> sticker_set_ids;
for (const auto &sticker : stickers->stickers_) {
if (sticker->set_id_ != 0 && client_->get_sticker_set_name(sticker->set_id_).empty()) {
sticker_set_ids.insert(sticker->set_id_);
}
}
td::MultiPromiseActorSafe mpas("GetStickerSetsMultiPromiseActor");
mpas.add_promise(td::PromiseCreator::lambda([actor_id = client_->actor_id(client_), stickers = std::move(stickers),
query = std::move(query_)](td::Unit) mutable {
send_closure(actor_id, &Client::return_stickers, std::move(stickers), std::move(query));
}));
mpas.set_ignore_errors(true);
auto lock = mpas.get_promise();
for (auto sticker_set_id : sticker_set_ids) {
client_->send_request(make_object<td_api::getStickerSet>(sticker_set_id),
td::make_unique<TdOnGetStickerSetPromiseCallback>(client_, mpas.get_promise()));
}
lock.set_value(td::Unit());
}
private:
Client *client_;
PromisedQueryPtr query_;
};
class Client::TdOnSendCustomRequestCallback final : public TdQueryCallback {
public:
explicit TdOnSendCustomRequestCallback(PromisedQueryPtr query) : query_(std::move(query)) {
@ -5308,6 +5398,8 @@ void Client::on_update(object_ptr<td_api::Object> result) {
set_user_bio(user_id, std::move(full_info->bio_->text_));
}
set_user_has_private_forwards(user_id, full_info->has_private_forwards_);
set_user_has_restricted_voice_and_video_messages(user_id,
full_info->has_restricted_voice_and_video_note_messages_);
break;
}
case td_api::updateUserStatus::ID: {
@ -5532,30 +5624,13 @@ void Client::on_closed() {
parameters_->shared_data_->webhook_db_->erase(bot_token_with_dc_);
parameters_->shared_data_->user_db_->erase(bot_token_with_dc_);
class RmWorker final : public td::Actor {
public:
RmWorker(td::string dir, td::ActorId<Client> parent) : dir_(std::move(dir)), parent_(std::move(parent)) {
}
private:
td::string dir_;
td::ActorId<Client> parent_;
void start_up() final {
CHECK(dir_.size() >= 24);
CHECK(dir_.back() == TD_DIR_SLASH);
td::rmrf(dir_).ignore();
stop();
}
void tear_down() final {
send_closure(parent_, &Client::finish_closing);
}
};
// NB: the same scheduler as for database in Td
auto current_scheduler_id = td::Scheduler::instance()->sched_id();
auto scheduler_count = td::Scheduler::instance()->sched_count();
auto scheduler_id = td::min(current_scheduler_id + 1, scheduler_count - 1);
td::create_actor_on_scheduler<RmWorker>("RmWorker", scheduler_id, dir_, actor_id(this)).release();
td::Scheduler::instance()->run_on_scheduler(get_file_gc_scheduler_id(),
[actor_id = actor_id(this), dir = dir_](td::Unit) {
CHECK(dir.size() >= 24);
CHECK(dir.back() == TD_DIR_SLASH);
td::rmrf(dir).ignore();
send_closure(actor_id, &Client::finish_closing);
});
return;
}
@ -5575,6 +5650,20 @@ void Client::timeout_expired() {
stop();
}
td::int32 Client::get_database_scheduler_id() {
// the same scheduler as for database in Td
auto current_scheduler_id = td::Scheduler::instance()->sched_id();
auto scheduler_count = td::Scheduler::instance()->sched_count();
return td::min(current_scheduler_id + 1, scheduler_count - 1);
}
td::int32 Client::get_file_gc_scheduler_id() {
// the same scheduler as for file GC in Td
auto current_scheduler_id = td::Scheduler::instance()->sched_id();
auto scheduler_count = td::Scheduler::instance()->sched_count();
return td::min(current_scheduler_id + 2, scheduler_count - 1);
}
void Client::clear_tqueue() {
CHECK(webhook_id_.empty());
auto &tqueue = parameters_->shared_data_->tqueue_;
@ -6818,27 +6907,23 @@ td::Result<td_api::object_ptr<td_api::maskPosition>> Client::get_mask_position(c
return r_mask_position.move_as_ok();
}
td::Result<td::vector<td_api::object_ptr<td_api::inputSticker>>> Client::get_input_stickers(const Query *query,
bool is_masks) const {
td::Result<td::vector<td_api::object_ptr<td_api::inputSticker>>> Client::get_input_stickers(const Query *query) const {
auto emojis = query->arg("emojis");
auto sticker = get_input_file(query, "png_sticker");
object_ptr<td_api::StickerType> sticker_type;
object_ptr<td_api::StickerFormat> sticker_format;
object_ptr<td_api::maskPosition> mask_position;
if (sticker != nullptr) {
if (is_masks) {
TRY_RESULT(mask_position, get_mask_position(query, "mask_position"));
sticker_type = make_object<td_api::stickerTypeMask>(std::move(mask_position));
} else {
sticker_type = make_object<td_api::stickerTypeStatic>();
}
sticker_format = make_object<td_api::stickerFormatWebp>();
TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position"));
} else {
sticker = get_input_file(query, "tgs_sticker", true);
if (sticker != nullptr) {
sticker_type = make_object<td_api::stickerTypeAnimated>();
sticker_format = make_object<td_api::stickerFormatTgs>();
} else {
sticker = get_input_file(query, "webm_sticker", true);
if (sticker != nullptr) {
sticker_type = make_object<td_api::stickerTypeVideo>();
sticker_format = make_object<td_api::stickerFormatWebm>();
} else {
if (!query->arg("tgs_sticker").empty()) {
return Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile");
@ -6852,7 +6937,8 @@ td::Result<td::vector<td_api::object_ptr<td_api::inputSticker>>> Client::get_inp
}
td::vector<object_ptr<td_api::inputSticker>> stickers;
stickers.push_back(make_object<td_api::inputSticker>(std::move(sticker), emojis.str(), std::move(sticker_type)));
stickers.push_back(make_object<td_api::inputSticker>(std::move(sticker), emojis.str(), std::move(sticker_format),
std::move(mask_position)));
return std::move(stickers);
}
@ -7028,6 +7114,10 @@ td::Result<td_api::object_ptr<td_api::TextEntityType>> Client::get_text_entity_t
TRY_RESULT(user_id, get_json_object_long_field(user.get_object(), "id", false));
return make_object<td_api::textEntityTypeMentionName>(user_id);
}
if (type == "custom_emoji") {
TRY_RESULT(custom_emoji_id, get_json_object_long_field(object, "custom_emoji_id", false));
return make_object<td_api::textEntityTypeCustomEmoji>(custom_emoji_id);
}
if (type == "mention" || type == "hashtag" || type == "cashtag" || type == "bot_command" || type == "url" ||
type == "email" || type == "phone_number" || type == "bank_card_number") {
return nullptr;
@ -9111,18 +9201,48 @@ td::Status Client::process_get_sticker_set_query(PromisedQueryPtr &query) {
return Status::OK();
}
td::Status Client::process_get_custom_emoji_stickers_query(PromisedQueryPtr &query) {
TRY_RESULT(custom_emoji_ids_json, get_required_string_arg(query.get(), "custom_emoji_ids"));
LOG(INFO) << "Parsing JSON object: " << custom_emoji_ids_json;
auto r_value = json_decode(custom_emoji_ids_json);
if (r_value.is_error()) {
return Status::Error(400, "Can't parse custom emoji identifiers JSON object");
}
auto value = r_value.move_as_ok();
if (value.type() != JsonValue::Type::Array) {
return Status::Error(400, "Expected an Array of custom emoji identifiers");
}
td::vector<int64> custom_emoji_ids;
for (auto &custom_emoji_id : value.get_array()) {
if (custom_emoji_id.type() != JsonValue::Type::String) {
return Status::Error(400, "Custom emoji identifier must be of type String");
}
auto parsed_id = td::to_integer_safe<int64>(custom_emoji_id.get_string());
if (parsed_id.is_error()) {
return Status::Error(400, "Invalid custom emoji identifier specified");
}
custom_emoji_ids.push_back(parsed_id.ok());
}
send_request(make_object<td_api::getCustomEmojiStickers>(std::move(custom_emoji_ids)),
td::make_unique<TdOnGetStickersCallback>(this, std::move(query)));
return Status::OK();
}
td::Status Client::process_upload_sticker_file_query(PromisedQueryPtr &query) {
CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto png_sticker = get_input_file(query.get(), "png_sticker");
check_user(user_id, std::move(query),
[this, user_id, png_sticker = std::move(png_sticker)](PromisedQueryPtr query) mutable {
send_request(make_object<td_api::uploadStickerFile>(
user_id, make_object<td_api::inputSticker>(std::move(png_sticker), "",
make_object<td_api::stickerTypeStatic>())),
td::make_unique<TdOnReturnFileCallback>(this, std::move(query)));
});
check_user(
user_id, std::move(query), [this, user_id, png_sticker = std::move(png_sticker)](PromisedQueryPtr query) mutable {
send_request(make_object<td_api::uploadStickerFile>(
user_id, make_object<td_api::inputSticker>(std::move(png_sticker), "",
make_object<td_api::stickerFormatWebp>(), nullptr)),
td::make_unique<TdOnReturnFileCallback>(this, std::move(query)));
});
return Status::OK();
}
@ -9131,14 +9251,20 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query)
TRY_RESULT(user_id, get_user_id(query.get()));
auto name = query->arg("name");
auto title = query->arg("title");
auto is_masks = to_bool(query->arg("contains_masks"));
TRY_RESULT(stickers, get_input_stickers(query.get(), is_masks));
TRY_RESULT(stickers, get_input_stickers(query.get()));
TRY_RESULT(sticker_type, get_sticker_type(query->arg("sticker_type")));
if (to_bool(query->arg("contains_masks"))) {
sticker_type = make_object<td_api::stickerTypeMask>();
}
check_user(user_id, std::move(query),
[this, user_id, title, name, stickers = std::move(stickers)](PromisedQueryPtr query) mutable {
send_request(make_object<td_api::createNewStickerSet>(user_id, title.str(), name.str(),
std::move(stickers), PSTRING() << "bot" << my_id_),
td::make_unique<TdOnReturnStickerSetCallback>(this, false, std::move(query)));
[this, user_id, title, name, sticker_type = std::move(sticker_type),
stickers = std::move(stickers)](PromisedQueryPtr query) mutable {
send_request(
make_object<td_api::createNewStickerSet>(user_id, title.str(), name.str(), std::move(sticker_type),
std::move(stickers), PSTRING() << "bot" << my_id_),
td::make_unique<TdOnReturnStickerSetCallback>(this, false, std::move(query)));
});
return Status::OK();
}
@ -9147,7 +9273,7 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) {
CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto name = query->arg("name");
TRY_RESULT(stickers, get_input_stickers(query.get(), true));
TRY_RESULT(stickers, get_input_stickers(query.get()));
CHECK(!stickers.empty());
check_user(user_id, std::move(query),
@ -9818,16 +9944,6 @@ void Client::do_get_file(object_ptr<td_api::file> file, PromisedQueryPtr query)
auto file_id = file->id_;
file_download_listeners_[file_id].push_back(std::move(query));
if (file->local_->is_downloading_completed_) {
Slice relative_path = td::PathView::relative(file->local_->path_, dir_, true);
if (!relative_path.empty()) {
auto r_stat = td::stat(file->local_->path_);
if (r_stat.is_ok() && r_stat.ok().is_reg_ && r_stat.ok().size_ == file->size_) {
return on_file_download(file_id, std::move(file));
}
}
}
send_request(make_object<td_api::downloadFile>(file_id, 1, 0, 0, false),
td::make_unique<TdOnDownloadFileCallback>(this, file_id));
}
@ -9854,6 +9970,10 @@ void Client::on_file_download(int32 file_id, td::Result<object_ptr<td_api::file>
}
}
void Client::return_stickers(object_ptr<td_api::stickers> stickers, PromisedQueryPtr query) {
answer_query(JsonStickers(stickers->stickers_, this), std::move(query));
}
void Client::webhook_verified(td::string cached_ip_address) {
if (get_link_token() != webhook_generation_) {
return;
@ -9916,14 +10036,25 @@ void Client::webhook_error(Status status) {
}
void Client::webhook_closed(Status status) {
if (has_webhook_certificate_) {
td::Scheduler::instance()->run_on_scheduler(get_database_scheduler_id(),
[actor_id = actor_id(this), path = get_webhook_certificate_path(),
status = std::move(status)](td::Unit) mutable {
LOG(INFO) << "Unlink certificate " << path;
td::unlink(path).ignore();
send_closure(actor_id, &Client::on_webhook_closed, std::move(status));
});
return;
}
on_webhook_closed(std::move(status));
}
void Client::on_webhook_closed(Status status) {
LOG(WARNING) << "Webhook closed: " << status
<< ", webhook_query_type = " << (webhook_query_type_ == WebhookQueryType::Verify ? "verify" : "change");
webhook_id_.release();
webhook_url_ = td::string();
if (has_webhook_certificate_) {
td::unlink(get_webhook_certificate_path()).ignore();
has_webhook_certificate_ = false;
}
has_webhook_certificate_ = false;
webhook_max_connections_ = 0;
webhook_ip_address_ = td::string();
webhook_fix_ip_address_ = false;
@ -10216,7 +10347,7 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu
CHECK(total_size >= updates.size());
total_size -= updates.size();
bool need_warning = false;
bool need_warning = total_size > 0 && (query->start_timestamp() - previous_get_updates_finish_time_ > 10.0);
if (total_size <= MIN_PENDING_UPDATES_WARNING / 2) {
if (last_pending_update_count_ > MIN_PENDING_UPDATES_WARNING) {
need_warning = true;
@ -10228,7 +10359,7 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu
last_pending_update_count_ *= 2;
}
}
if (need_warning) {
if (need_warning && previous_get_updates_finish_time_ > 0) {
LOG(WARNING) << "Found " << updates.size() << " updates out of " << (total_size + updates.size())
<< " after last getUpdates call " << (query->start_timestamp() - previous_get_updates_finish_time_)
<< " seconds ago in " << (td::Time::now() - query->start_timestamp()) << " seconds";
@ -10351,6 +10482,11 @@ void Client::set_user_has_private_forwards(int64 user_id, bool has_private_forwa
add_user_info(user_id)->has_private_forwards = has_private_forwards;
}
void Client::set_user_has_restricted_voice_and_video_messages(int64 user_id,
bool has_restricted_voice_and_video_messages) {
add_user_info(user_id)->has_restricted_voice_and_video_messages = has_restricted_voice_and_video_messages;
}
void Client::set_user_status(int64 user_id, object_ptr<td_api::UserStatus> &&status) {
add_user_info(user_id)->status = std::move(status);
}
@ -11113,6 +11249,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr<td_api::me
return true;
case td_api::messageWebAppDataSent::ID:
return true;
case td_api::messageGiftedPremium::ID:
return true;
default:
break;
}
@ -11165,6 +11303,34 @@ void Client::set_message_reply_to_message_id(MessageInfo *message_info, int64 re
message_info->reply_to_message_id = reply_to_message_id;
}
td::Slice Client::get_sticker_type(const object_ptr<td_api::StickerType> &type) {
CHECK(type != nullptr);
switch (type->get_id()) {
case td_api::stickerTypeRegular::ID:
return Slice("regular");
case td_api::stickerTypeMask::ID:
return Slice("mask");
case td_api::stickerTypeCustomEmoji::ID:
return Slice("custom_emoji");
default:
UNREACHABLE();
return Slice();
}
}
td::Result<td_api::object_ptr<td_api::StickerType>> Client::get_sticker_type(Slice type) {
if (type.empty() || type == "regular") {
return make_object<td_api::stickerTypeRegular>();
}
if (type == "mask") {
return make_object<td_api::stickerTypeMask>();
}
if (type == "custom_emoji") {
return make_object<td_api::stickerTypeCustomEmoji>();
}
return Status::Error(400, "Unsupported sticker type specified");
}
td::CSlice Client::get_callback_data(const object_ptr<td_api::InlineKeyboardButtonType> &type) {
CHECK(type != nullptr);
switch (type->get_id()) {

View File

@ -16,7 +16,6 @@
#include "td/net/HttpFile.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/actor/SignalSlot.h"
#include "td/utils/common.h"
@ -24,6 +23,7 @@
#include "td/utils/FlatHashMap.h"
#include "td/utils/FlatHashSet.h"
#include "td/utils/JsonBuilder.h"
#include "td/utils/Promise.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
@ -42,6 +42,11 @@ class Client final : public WebhookActor::Callback {
public:
Client(td::ActorShared<> parent, const td::string &bot_token, bool is_user, bool is_test_dc, td::int64 tqueue_id,
std::shared_ptr<const ClientParameters> parameters, td::ActorId<BotStatActor> stat_actor);
Client(const Client &) = delete;
Client &operator=(const Client &) = delete;
Client(Client &&) = delete;
Client &operator=(Client &&) = delete;
~Client();
void send(PromisedQueryPtr query) final;
@ -212,6 +217,8 @@ class Client final : public WebhookActor::Callback {
class TdOnAnswerWebAppQueryCallback;
class TdOnReturnFileCallback;
class TdOnReturnStickerSetCallback;
class TdOnGetStickerSetPromiseCallback;
class TdOnGetStickersCallback;
class TdOnDownloadFileCallback;
class TdOnCancelDownloadFileCallback;
class TdOnSendCustomRequestCallback;
@ -346,6 +353,10 @@ class Client final : public WebhookActor::Callback {
void on_closed();
void finish_closing();
static int32 get_database_scheduler_id();
static int32 get_file_gc_scheduler_id();
void clear_tqueue();
bool allow_update_before_authorization(const td_api::Object *update) const;
@ -432,7 +443,7 @@ class Client final : public WebhookActor::Callback {
static object_ptr<td_api::MaskPoint> mask_index_to_point(int32 index);
td::Result<td::vector<object_ptr<td_api::inputSticker>>> get_input_stickers(const Query *query, bool is_masks) const;
td::Result<td::vector<object_ptr<td_api::inputSticker>>> get_input_stickers(const Query *query) const;
static td::Result<td::string> get_passport_element_hash(Slice encoded_hash);
@ -599,6 +610,7 @@ class Client final : public WebhookActor::Callback {
Status process_approve_chat_join_request_query(PromisedQueryPtr &query);
Status process_decline_chat_join_request_query(PromisedQueryPtr &query);
Status process_get_sticker_set_query(PromisedQueryPtr &query);
Status process_get_custom_emoji_stickers_query(PromisedQueryPtr &query);
Status process_upload_sticker_file_query(PromisedQueryPtr &query);
Status process_create_new_sticker_set_query(PromisedQueryPtr &query);
Status process_add_sticker_to_set_query(PromisedQueryPtr &query);
@ -663,6 +675,8 @@ class Client final : public WebhookActor::Callback {
void save_webhook() const;
td::string get_webhook_certificate_path() const;
void on_webhook_closed(Status status);
void do_send_message(object_ptr<td_api::InputMessageContent> input_message_content, PromisedQueryPtr query);
int64 get_send_message_query_id(PromisedQueryPtr query, bool is_multisend);
@ -674,6 +688,8 @@ class Client final : public WebhookActor::Callback {
bool is_file_being_downloaded(int32 file_id) const;
void on_file_download(int32 file_id, td::Result<object_ptr<td_api::file>> r_file);
void return_stickers(object_ptr<td_api::stickers> stickers, PromisedQueryPtr query);
void fix_reply_markup_bot_user_ids(object_ptr<td_api::ReplyMarkup> &reply_markup) const;
void fix_inline_query_results_bot_user_ids(td::vector<object_ptr<td_api::InputInlineQueryResult>> &results) const;
@ -726,6 +742,7 @@ class Client final : public WebhookActor::Callback {
bool can_read_all_group_messages = false;
bool is_inline_bot = false;
bool has_private_forwards = false;
bool has_restricted_voice_and_video_messages = false;
bool is_premium = false;
bool added_to_attachment_menu = false;
};
@ -733,7 +750,10 @@ class Client final : public WebhookActor::Callback {
void set_user_photo(int64 user_id, object_ptr<td_api::chatPhoto> &&photo);
void set_user_bio(int64 user_id, td::string &&bio);
void set_user_has_private_forwards(int64 user_id, bool has_private_forwards);
void set_user_has_restricted_voice_and_video_messages(int64 user_id, bool has_restricted_voice_and_video_messages);
void set_user_status(int64 user_id, object_ptr<td_api::UserStatus> &&status);
UserInfo *add_user_info(int64 user_id);
const UserInfo *get_user_info(int64 user_id) const;
@ -851,6 +871,10 @@ class Client final : public WebhookActor::Callback {
void set_message_reply_to_message_id(MessageInfo *message_info, int64 reply_to_message_id);
static Slice get_sticker_type(const object_ptr<td_api::StickerType> &type);
static td::Result<object_ptr<td_api::StickerType>> get_sticker_type(Slice type);
static td::CSlice get_callback_data(const object_ptr<td_api::InlineKeyboardButtonType> &type);
static bool are_equal_inline_keyboard_buttons(const td_api::inlineKeyboardButton *lhs,

View File

@ -99,8 +99,8 @@ void ClientManager::send(PromisedQueryPtr query) {
return;
}
auto tqueue_id = get_tqueue_id(r_user_id.ok(), query->is_test_dc());
if (active_client_count_.find(tqueue_id) != active_client_count_.end()) {
auto tqueue_id = get_tqueue_id(user_id, query->is_test_dc());
if (active_client_count_.count(tqueue_id) != 0) {
// return query->set_retry_after_error(1);
}
@ -163,7 +163,7 @@ void ClientManager::user_login(PromisedQueryPtr query) {
parameters_, std::move(stat_actor));
clients_.get(id)->client_ = std::move(client_id);
auto id_it = token_to_id_.end();
auto id_it = token_to_id_.find(user_token);
std::tie(id_it, std::ignore) = token_to_id_.emplace(user_token, id);
send_closure(client_info->client_, &Client::send, std::move(query)); // will send 429 if the client is already closed
@ -216,7 +216,7 @@ bool ClientManager::check_flood_limits(PromisedQueryPtr &query, bool is_user_log
return true;
}
void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
td::vector<std::pair<td::string, td::string>> args,
bool as_json) {
if (close_flag_) {
@ -544,7 +544,7 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, bool
auto query = td::make_unique<Query>(std::move(containers), token, is_user, is_test_dc, method, std::move(args),
td::vector<std::pair<td::MutableSlice, td::MutableSlice>>(),
td::vector<td::HttpFile>(), std::move(shared_data), td::IPAddress(), true);
return PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor<td::unique_ptr<Query>>()));
return PromisedQueryPtr(query.release(), PromiseDeleter(td::Promise<td::unique_ptr<Query>>()));
}
void ClientManager::raw_event(const td::Event::Raw &event) {

View File

@ -11,13 +11,13 @@
#include "telegram-bot-api/Stats.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"
#include "td/utils/Container.h"
#include "td/utils/FlatHashMap.h"
#include "td/utils/FloodControlFast.h"
#include "td/utils/Promise.h"
#include "td/utils/Slice.h"
#include <memory>
@ -46,7 +46,7 @@ class ClientManager final : public td::Actor {
bool check_flood_limits(PromisedQueryPtr &query, bool is_user_login=false);
void get_stats(td::PromiseActor<td::BufferSlice> promise, td::vector<std::pair<td::string, td::string>> args, bool as_json);
void get_stats(td::Promise<td::BufferSlice> promise, td::vector<std::pair<td::string, td::string>> args, bool as_json);
void close(td::Promise<td::Unit> &&promise);

View File

@ -14,6 +14,7 @@
#include "td/utils/JsonBuilder.h"
#include "td/utils/logging.h"
#include "td/utils/Parser.h"
#include "td/utils/Promise.h"
#include "td/utils/SliceBuilder.h"
namespace telegram_bot_api {
@ -63,26 +64,21 @@ void HttpConnection::handle(td::unique_ptr<td::HttpQuery> http_query,
std::move(http_query->args_), std::move(http_query->headers_),
std::move(http_query->files_), shared_data_, http_query->peer_address_, false);
td::PromiseActor<td::unique_ptr<Query>> promise;
td::FutureActor<td::unique_ptr<Query>> future;
td::init_promise_future(&promise, &future);
future.set_event(td::EventCreator::yield(actor_id()));
auto promise = td::PromiseCreator::lambda([actor_id = actor_id(this)](td::Result<td::unique_ptr<Query>> r_query) {
send_closure(actor_id, &HttpConnection::on_query_finished, std::move(r_query));
});
auto promised_query = PromisedQueryPtr(query.release(), PromiseDeleter(std::move(promise)));
if (is_login) {
send_closure(client_manager_, &ClientManager::user_login, std::move(promised_query));
} else {
send_closure(client_manager_, &ClientManager::send, std::move(promised_query));
}
result_ = std::move(future);
}
void HttpConnection::wakeup() {
if (result_.empty()) {
return;
}
LOG_CHECK(result_.is_ok()) << result_.move_as_error();
void HttpConnection::on_query_finished(td::Result<td::unique_ptr<Query>> r_query) {
LOG_CHECK(r_query.is_ok()) << r_query.error();
auto query = result_.move_as_ok();
auto query = r_query.move_as_ok();
send_response(query->http_status_code(), std::move(query->answer()), query->retry_after());
}

View File

@ -13,10 +13,10 @@
#include "td/net/HttpQuery.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <memory>
@ -32,10 +32,7 @@ class HttpConnection final : public td::HttpInboundConnection::Callback {
void handle(td::unique_ptr<td::HttpQuery> http_query, td::ActorOwn<td::HttpInboundConnection> connection) final;
void wakeup() final;
private:
td::FutureActor<td::unique_ptr<Query>> result_;
td::ActorId<ClientManager> client_manager_;
td::ActorOwn<td::HttpInboundConnection> connection_;
std::shared_ptr<SharedData> shared_data_;
@ -45,6 +42,8 @@ class HttpConnection final : public td::HttpInboundConnection::Callback {
stop();
}
void on_query_finished(td::Result<td::unique_ptr<Query>> r_query);
void send_response(int http_status_code, td::BufferSlice &&content, int retry_after);
void send_http_error(int http_status_code, td::Slice description);

View File

@ -9,7 +9,7 @@
#include "td/net/HttpHeaderCreator.h"
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/Promise.h"
namespace telegram_bot_api {
@ -17,25 +17,23 @@ void HttpStatConnection::handle(td::unique_ptr<td::HttpQuery> http_query,
td::ActorOwn<td::HttpInboundConnection> connection) {
CHECK(connection_->empty());
connection_ = std::move(connection);
td::PromiseActor<td::BufferSlice> promise;
td::FutureActor<td::BufferSlice> future;
init_promise_future(&promise, &future);
future.set_event(td::EventCreator::yield(actor_id()));
LOG(DEBUG) << "SEND";
td::Parser url_path_parser(http_query->url_path_);
as_json_ = url_path_parser.try_skip("/json");
auto promise = td::PromiseCreator::lambda([actor_id = actor_id(this)](td::Result<td::BufferSlice> result) {
send_closure(actor_id, &HttpStatConnection::on_result, std::move(result));
});
send_closure(client_manager_, &ClientManager::get_stats, std::move(promise), http_query->get_args(), as_json_);
result_ = std::move(future);
}
void HttpStatConnection::wakeup() {
if (result_.empty()) {
void HttpStatConnection::on_result(td::Result<td::BufferSlice> result) {
if (result.is_error()) {
send_closure(connection_.release(), &td::HttpInboundConnection::write_error,
td::Status::Error(500, "Internal Server Error: closing"));
return;
}
LOG_CHECK(result_.is_ok()) << result_.move_as_error();
auto content = result_.move_as_ok();
auto content = result.move_as_ok();
td::HttpHeaderCreator hc;
hc.init_status_line(200);
hc.set_keep_alive();

View File

@ -12,9 +12,9 @@
#include "td/net/HttpQuery.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h"
#include "td/utils/Status.h"
namespace telegram_bot_api {
@ -22,16 +22,16 @@ class HttpStatConnection final : public td::HttpInboundConnection::Callback {
public:
explicit HttpStatConnection(td::ActorId<ClientManager> client_manager) : client_manager_(client_manager) {
}
void handle(td::unique_ptr<td::HttpQuery> http_query, td::ActorOwn<td::HttpInboundConnection> connection) final;
void wakeup() final;
void handle(td::unique_ptr<td::HttpQuery> http_query, td::ActorOwn<td::HttpInboundConnection> connection) final;
private:
bool as_json_;
td::FutureActor<td::BufferSlice> result_;
td::ActorId<ClientManager> client_manager_;
td::ActorOwn<td::HttpInboundConnection> connection_;
void on_result(td::Result<td::BufferSlice> result);
void hangup() final {
connection_.release();
stop();

View File

@ -11,7 +11,6 @@
#include "td/net/HttpFile.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h"
#include "td/utils/common.h"
@ -19,6 +18,7 @@
#include "td/utils/JsonBuilder.h"
#include "td/utils/List.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/Promise.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
@ -231,7 +231,7 @@ class JsonQueryError final : public td::Jsonable {
class PromiseDeleter {
public:
explicit PromiseDeleter(td::PromiseActor<td::unique_ptr<Query>> &&promise) : promise_(std::move(promise)) {
explicit PromiseDeleter(td::Promise<td::unique_ptr<Query>> &&promise) : promise_(std::move(promise)) {
}
PromiseDeleter() = default;
PromiseDeleter(const PromiseDeleter &) = delete;
@ -240,7 +240,7 @@ class PromiseDeleter {
PromiseDeleter &operator=(PromiseDeleter &&) = default;
void operator()(Query *raw_ptr) {
td::unique_ptr<Query> query(raw_ptr); // now I cannot forget to delete this pointer
if (!promise_.empty_promise()) {
if (promise_) {
if (!query->is_ready()) {
query->set_retry_after_error(5);
}
@ -249,11 +249,11 @@ class PromiseDeleter {
}
}
~PromiseDeleter() {
CHECK(promise_.empty());
CHECK(!promise_);
}
private:
td::PromiseActor<td::unique_ptr<Query>> promise_;
td::Promise<td::unique_ptr<Query>> promise_;
};
using PromisedQueryPtr = std::unique_ptr<Query, PromiseDeleter>;

View File

@ -15,7 +15,6 @@
#include "td/net/TransparentProxy.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/base64.h"
#include "td/utils/buffer.h"
@ -26,6 +25,7 @@
#include "td/utils/misc.h"
#include "td/utils/port/IPAddress.h"
#include "td/utils/port/SocketFd.h"
#include "td/utils/Promise.h"
#include "td/utils/Random.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/SliceBuilder.h"
@ -82,7 +82,7 @@ void WebhookActor::relax_wakeup_at(double wakeup_at, const char *source) {
}
void WebhookActor::resolve_ip_address() {
if (fix_ip_address_) {
if (fix_ip_address_ || is_ip_address_being_resolved_) {
return;
}
if (td::Time::now() < next_ip_address_resolve_time_) {
@ -90,43 +90,42 @@ void WebhookActor::resolve_ip_address() {
return;
}
bool future_created = false;
if (future_ip_address_.empty()) {
td::PromiseActor<td::IPAddress> promise;
init_promise_future(&promise, &future_ip_address_);
future_created = true;
send_closure(parameters_->get_host_by_name_actor_id_, &td::GetHostByNameActor::run, url_.host_, url_.port_, false,
td::PromiseCreator::from_promise_actor(std::move(promise)));
is_ip_address_being_resolved_ = true;
auto promise = td::PromiseCreator::lambda([actor_id = actor_id(this)](td::Result<td::IPAddress> r_ip_address) {
send_closure(actor_id, &WebhookActor::on_resolved_ip_address, std::move(r_ip_address));
});
send_closure(parameters_->get_host_by_name_actor_id_, &td::GetHostByNameActor::run, url_.host_, url_.port_, false,
std::move(promise));
}
void WebhookActor::on_resolved_ip_address(td::Result<td::IPAddress> r_ip_address) {
CHECK(is_ip_address_being_resolved_);
is_ip_address_being_resolved_ = false;
next_ip_address_resolve_time_ =
td::Time::now() + IP_ADDRESS_CACHE_TIME + td::Random::fast(0, IP_ADDRESS_CACHE_TIME / 10);
relax_wakeup_at(next_ip_address_resolve_time_, "on_resolved_ip_address");
SCOPE_EXIT {
loop();
};
if (r_ip_address.is_error()) {
return on_error(r_ip_address.move_as_error());
}
if (future_ip_address_.is_ready()) {
next_ip_address_resolve_time_ =
td::Time::now() + IP_ADDRESS_CACHE_TIME + td::Random::fast(0, IP_ADDRESS_CACHE_TIME / 10);
relax_wakeup_at(next_ip_address_resolve_time_, "resolve_ip_address");
auto r_ip_address = future_ip_address_.move_as_result();
if (r_ip_address.is_error()) {
CHECK(!(r_ip_address.error() == td::Status::Error<td::FutureActor<td::IPAddress>::HANGUP_ERROR_CODE>()));
return on_error(r_ip_address.move_as_error());
}
auto new_ip_address = r_ip_address.move_as_ok();
if (!check_ip_address(new_ip_address)) {
return on_error(td::Status::Error(PSLICE() << "IP address " << new_ip_address.get_ip_str() << " is reserved"));
}
if (!(ip_address_ == new_ip_address)) {
VLOG(webhook) << "IP address has changed: " << ip_address_ << " --> " << new_ip_address;
ip_address_ = new_ip_address;
ip_generation_++;
if (was_checked_) {
on_webhook_verified();
}
}
VLOG(webhook) << "IP address was verified";
} else {
if (future_created) {
future_ip_address_.set_event(td::EventCreator::yield(actor_id()));
auto new_ip_address = r_ip_address.move_as_ok();
if (!check_ip_address(new_ip_address)) {
return on_error(td::Status::Error(PSLICE() << "IP address " << new_ip_address.get_ip_str() << " is reserved"));
}
if (!(ip_address_ == new_ip_address)) {
VLOG(webhook) << "IP address has changed: " << ip_address_ << " --> " << new_ip_address;
ip_address_ = new_ip_address;
ip_generation_++;
if (was_checked_) {
on_webhook_verified();
}
}
VLOG(webhook) << "IP address was verified";
}
td::Status WebhookActor::create_connection() {
@ -602,11 +601,10 @@ void WebhookActor::handle(td::unique_ptr<td::HttpQuery> response) {
method != "logout" && !td::begins_with(method, "get")) {
VLOG(webhook) << "Receive request " << method << " in response to webhook";
auto query = td::make_unique<Query>(std::move(response->container_), td::MutableSlice(), false, false,
td::MutableSlice(), std::move(response->args_),
std::move(response->headers_), std::move(response->files_),
parameters_->shared_data_, response->peer_address_, false);
auto promised_query =
PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor<td::unique_ptr<Query>>()));
td::MutableSlice(), std::move(response->args_),
std::move(response->headers_), std::move(response->files_),
parameters_->shared_data_, response->peer_address_, false);
auto promised_query = PromisedQueryPtr(query.release(), PromiseDeleter(td::Promise<td::unique_ptr<Query>>()));
send_closure(callback_, &Callback::send, std::move(promised_query));
}
first_error_410_time_ = 0;

View File

@ -15,7 +15,6 @@
#include "td/net/SslStream.h"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/common.h"
@ -137,7 +136,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback {
td::IPAddress ip_address_;
td::int32 ip_generation_ = 0;
double next_ip_address_resolve_time_ = 0;
td::FutureActor<td::IPAddress> future_ip_address_;
bool is_ip_address_being_resolved_ = false;
class Connection final : public td::ListNode {
public:
@ -175,6 +174,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback {
void relax_wakeup_at(double wakeup_at, const char *source);
void resolve_ip_address();
void on_resolved_ip_address(td::Result<td::IPAddress> r_ip_address);
td::Result<td::SslStream> create_ssl_stream();
td::Status create_connection() TD_WARN_UNUSED_RESULT;

View File

@ -22,7 +22,6 @@
#include "td/actor/actor.h"
#include "td/actor/ConcurrentScheduler.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h"
#include "td/utils/CombinedLog.h"
@ -45,6 +44,7 @@
#include "td/utils/port/stacktrace.h"
#include "td/utils/port/Stat.h"
#include "td/utils/port/user.h"
#include "td/utils/Promise.h"
#include "td/utils/Slice.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/Status.h"
@ -200,7 +200,7 @@ int main(int argc, char *argv[]) {
auto start_time = td::Time::now();
auto shared_data = std::make_shared<SharedData>();
auto parameters = std::make_unique<ClientParameters>();
parameters->version_ = "6.1";
parameters->version_ = "6.2";
parameters->shared_data_ = shared_data;
parameters->start_time_ = start_time;
auto net_query_stats = td::create_net_query_stats();