Merge remote-tracking branch 'upstream/master' into merge-upstream

This commit is contained in:
Giuseppe Marino 2021-11-05 13:50:44 +01:00
commit 188fa9d8b0
No known key found for this signature in database
GPG Key ID: 2BC70C5463357449
11 changed files with 264 additions and 99 deletions

View File

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

View File

@ -250,7 +250,7 @@ function onOptionsChanged() {
pre_text.push('Download and install <a href="https://git-scm.com/download/win">Git</a>.');
}
if (os_linux && linux_distro === 'Other') {
var compiler = use_clang ? 'clang >= 3.4' : 'g++ >= 4.9.2';
var compiler = use_clang ? 'clang >= 3.4, libc++' : 'g++ >= 4.9.2';
pre_text.push('Install Git, ' + compiler + ', make, CMake >= 3.0.2, OpenSSL-dev, zlib-dev, gperf using your package manager.');
}
if (os_freebsd) {

2
td

@ -1 +1 @@
Subproject commit 0126cec2686e3b95cc1b6dfb5676d364da0e091b
Subproject commit eb346f5573040803d4424049dd2ba8aaa039fa56

View File

@ -75,8 +75,8 @@ void Client::fail_query_with_error(PromisedQueryPtr query, int32 error_code, Sli
}
int32 real_error_code = error_code;
Slice real_error_message = error_message;
if (error_code < 300 || error_code == 404) {
if (error_code <= 0) {
if (error_code < 400 || error_code == 404) {
if (error_code < 200) {
LOG(ERROR) << "Receive error \"" << real_error_message << "\" with code " << error_code << " from " << *query;
}
@ -278,6 +278,8 @@ bool Client::init_methods() {
methods_.emplace("kickchatmember", &Client::process_ban_chat_member_query);
methods_.emplace("restrictchatmember", &Client::process_restrict_chat_member_query);
methods_.emplace("unbanchatmember", &Client::process_unban_chat_member_query);
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("uploadstickerfile", &Client::process_upload_sticker_file_query);
methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query);
@ -624,6 +626,9 @@ class Client::JsonChatInviteLink : public Jsonable {
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("invite_link", chat_invite_link_->invite_link_);
if (!chat_invite_link_->name_.empty()) {
object("name", chat_invite_link_->name_);
}
object("creator", JsonUser(chat_invite_link_->creator_user_id_, client_));
if (chat_invite_link_->expire_date_ != 0) {
object("expire_date", chat_invite_link_->expire_date_);
@ -631,6 +636,10 @@ class Client::JsonChatInviteLink : public Jsonable {
if (chat_invite_link_->member_limit_ != 0) {
object("member_limit", chat_invite_link_->member_limit_);
}
if (chat_invite_link_->pending_join_request_count_ != 0) {
object("pending_join_request_count", chat_invite_link_->pending_join_request_count_);
}
object("creates_join_request", td::JsonBool(chat_invite_link_->creates_join_request_));
object("is_primary", td::JsonBool(chat_invite_link_->is_primary_));
object("is_revoked", td::JsonBool(chat_invite_link_->is_revoked_));
}
@ -1519,54 +1528,54 @@ class Client::JsonProximityAlertTriggered : public Jsonable {
const Client *client_;
};
class Client::JsonVoiceChatScheduled : public Jsonable {
class Client::JsonVideoChatScheduled : public Jsonable {
public:
explicit JsonVoiceChatScheduled(const td_api::messageVoiceChatScheduled *voice_chat_scheduled)
: voice_chat_scheduled_(voice_chat_scheduled) {
explicit JsonVideoChatScheduled(const td_api::messageVideoChatScheduled *video_chat_scheduled)
: video_chat_scheduled_(video_chat_scheduled) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("start_date", voice_chat_scheduled_->start_date_);
object("start_date", video_chat_scheduled_->start_date_);
}
private:
const td_api::messageVoiceChatScheduled *voice_chat_scheduled_;
const td_api::messageVideoChatScheduled *video_chat_scheduled_;
};
class Client::JsonVoiceChatStarted : public Jsonable {
class Client::JsonVideoChatStarted : public Jsonable {
public:
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
}
};
class Client::JsonVoiceChatEnded : public Jsonable {
class Client::JsonVideoChatEnded : public Jsonable {
public:
explicit JsonVoiceChatEnded(const td_api::messageVoiceChatEnded *voice_chat_ended)
: voice_chat_ended_(voice_chat_ended) {
explicit JsonVideoChatEnded(const td_api::messageVideoChatEnded *video_chat_ended)
: video_chat_ended_(video_chat_ended) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("duration", voice_chat_ended_->duration_);
object("duration", video_chat_ended_->duration_);
}
private:
const td_api::messageVoiceChatEnded *voice_chat_ended_;
const td_api::messageVideoChatEnded *video_chat_ended_;
};
class Client::JsonInviteVoiceChatParticipants : public Jsonable {
class Client::JsonInviteVideoChatParticipants : public Jsonable {
public:
JsonInviteVoiceChatParticipants(const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants,
JsonInviteVideoChatParticipants(const td_api::messageInviteVideoChatParticipants *invite_video_chat_participants,
const Client *client)
: invite_voice_chat_participants_(invite_voice_chat_participants), client_(client) {
: invite_video_chat_participants_(invite_video_chat_participants), client_(client) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("users", JsonUsers(invite_voice_chat_participants_->user_ids_, client_));
object("users", JsonUsers(invite_video_chat_participants_->user_ids_, client_));
}
private:
const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants_;
const td_api::messageInviteVideoChatParticipants *invite_video_chat_participants_;
const Client *client_;
};
@ -1862,6 +1871,14 @@ void Client::JsonMessage::store(JsonValueScope *scope) const {
}
break;
}
case td_api::messageChatJoinByRequest::ID: {
if (message_->sender_user_id > 0) {
object("new_chat_participant", JsonUser(message_->sender_user_id, client_));
object("new_chat_member", JsonUser(message_->sender_user_id, client_));
object("new_chat_members", JsonUsers({message_->sender_user_id}, client_));
}
break;
}
case td_api::messageChatDeleteMember::ID: {
auto message_delete_member = static_cast<const td_api::messageChatDeleteMember *>(message_->content.get());
int64 user_id = message_delete_member->user_id_;
@ -1959,6 +1976,9 @@ void Client::JsonMessage::store(JsonValueScope *scope) const {
break;
case td_api::messageChatSetTheme::ID:
break;
case td_api::messageAnimatedEmoji::ID:
UNREACHABLE();
break;
case td_api::messageWebsiteConnected::ID: {
auto chat = client_->get_chat(message_->chat_id);
if (chat->type != ChatInfo::Type::Private) {
@ -1984,22 +2004,22 @@ void Client::JsonMessage::store(JsonValueScope *scope) const {
object("proximity_alert_triggered", JsonProximityAlertTriggered(content, client_));
break;
}
case td_api::messageVoiceChatScheduled::ID: {
auto content = static_cast<const td_api::messageVoiceChatScheduled *>(message_->content.get());
object("voice_chat_scheduled", JsonVoiceChatScheduled(content));
case td_api::messageVideoChatScheduled::ID: {
auto content = static_cast<const td_api::messageVideoChatScheduled *>(message_->content.get());
object("voice_chat_scheduled", JsonVideoChatScheduled(content));
break;
}
case td_api::messageVoiceChatStarted::ID:
object("voice_chat_started", JsonVoiceChatStarted());
case td_api::messageVideoChatStarted::ID:
object("voice_chat_started", JsonVideoChatStarted());
break;
case td_api::messageVoiceChatEnded::ID: {
auto content = static_cast<const td_api::messageVoiceChatEnded *>(message_->content.get());
object("voice_chat_ended", JsonVoiceChatEnded(content));
case td_api::messageVideoChatEnded::ID: {
auto content = static_cast<const td_api::messageVideoChatEnded *>(message_->content.get());
object("voice_chat_ended", JsonVideoChatEnded(content));
break;
}
case td_api::messageInviteVoiceChatParticipants::ID: {
auto content = static_cast<const td_api::messageInviteVoiceChatParticipants *>(message_->content.get());
object("voice_chat_participants_invited", JsonInviteVoiceChatParticipants(content, client_));
case td_api::messageInviteVideoChatParticipants::ID: {
auto content = static_cast<const td_api::messageInviteVideoChatParticipants *>(message_->content.get());
object("voice_chat_participants_invited", JsonInviteVideoChatParticipants(content, client_));
break;
}
default:
@ -2370,7 +2390,7 @@ class Client::JsonChatMember : public Jsonable {
object("can_pin_messages", td::JsonBool(administrator->can_pin_messages_));
}
object("can_promote_members", td::JsonBool(administrator->can_promote_members_));
object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_voice_chats_));
object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_video_chats_));
if (!administrator->custom_title_.empty()) {
object("custom_title", administrator->custom_title_);
}
@ -2474,6 +2494,29 @@ class Client::JsonChatMemberUpdated : public Jsonable {
const Client *client_;
};
class Client::JsonChatJoinRequest : public Jsonable {
public:
JsonChatJoinRequest(const td_api::updateNewChatJoinRequest *update, const Client *client)
: update_(update), client_(client) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("chat", JsonChat(update_->chat_id_, false, client_));
object("from", JsonUser(update_->request_->user_id_, client_));
object("date", update_->request_->date_);
if (!update_->request_->bio_.empty()) {
object("bio", update_->request_->bio_);
}
if (update_->invite_link_ != nullptr) {
object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_));
}
}
private:
const td_api::updateNewChatJoinRequest *update_;
const Client *client_;
};
class Client::JsonGameHighScore : public Jsonable {
public:
JsonGameHighScore(const td_api::gameHighScore *score, const Client *client) : score_(score), client_(client) {
@ -4116,7 +4159,7 @@ void Client::raw_event(const td::Event::Raw &event) {
}
void Client::loop() {
if (logging_out_ || closing_ || was_authorized_ || waiting_for_auth_input_) {
if (was_authorized_ || logging_out_ || closing_ || waiting_for_auth_input_) {
while (!cmd_queue_.empty()) {
auto query = std::move(cmd_queue_.front());
cmd_queue_.pop();
@ -4741,6 +4784,7 @@ void Client::on_update_authorization_state() {
if (!was_authorized_) {
LOG(WARNING) << "Logged in as @" << user_info->username;
was_authorized_ = true;
td::send_event(parent_, td::Event::raw(static_cast<void *>(this)));
update_shared_unix_time_difference();
if (!pending_updates_.empty()) {
LOG(INFO) << "Process " << pending_updates_.size() << " pending updates";
@ -4757,15 +4801,21 @@ void Client::on_update_authorization_state() {
if (!logging_out_) {
LOG(WARNING) << "Logging out";
logging_out_ = true;
if (was_authorized_ && !closing_) {
td::send_event(parent_, td::Event::raw(nullptr));
}
}
break;
return loop();
case td_api::authorizationStateClosing::ID:
waiting_for_auth_input_ = false;
if (!closing_) {
LOG(WARNING) << "Closing";
closing_ = true;
if (was_authorized_ && !logging_out_) {
td::send_event(parent_, td::Event::raw(nullptr));
}
}
break;
return loop();
case td_api::authorizationStateClosed::ID:
return on_closed();
default:
@ -5064,6 +5114,9 @@ void Client::on_update(object_ptr<td_api::Object> result) {
case td_api::updateChatMember::ID:
add_update_chat_member(move_object_as<td_api::updateChatMember>(result));
break;
case td_api::updateNewChatJoinRequest::ID:
add_update_chat_join_request(move_object_as<td_api::updateNewChatJoinRequest>(result));
break;
default:
// we are not interested in this update
break;
@ -5121,6 +5174,7 @@ void Client::on_closed() {
}
on_message_send_failed(chat_id, message_id, 0, Status::Error(http_status_code, description));
}
CHECK(yet_unsent_message_count_.empty());
while (!pending_bot_resolve_queries_.empty()) {
auto it = pending_bot_resolve_queries_.begin();
@ -5615,6 +5669,9 @@ td_api::object_ptr<td_api::ChatAction> Client::get_chat_action(const Query *quer
if (action == "upload_document") {
return make_object<td_api::chatActionUploadingDocument>();
}
if (action == "choose_sticker") {
return make_object<td_api::chatActionChoosingSticker>();
}
if (action == "pick_up_location" || action == "find_location") {
return make_object<td_api::chatActionChoosingLocation>();
}
@ -6869,6 +6926,13 @@ td::int64 Client::extract_yet_unsent_message_query_id(int64 chat_id, int64 messa
yet_unsent_messages_.erase(yet_unsent_message_it);
auto count_it = yet_unsent_message_count_.find(chat_id);
CHECK(count_it != yet_unsent_message_count_.end());
CHECK(count_it->second > 0);
if (--count_it->second == 0) {
yet_unsent_message_count_.erase(count_it);
}
if (reply_to_message_id > 0) {
auto it = yet_unsent_reply_message_ids_.find({chat_id, reply_to_message_id});
CHECK(it != yet_unsent_reply_message_ids_.end());
@ -7536,6 +7600,10 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) {
auto on_success = [this, disable_notification, input_message_contents = std::move(input_message_contents),
reply_markup = std::move(reply_markup), send_at = std::move(send_at)](
int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable {
auto it = yet_unsent_message_count_.find(chat_id);
if (it != yet_unsent_message_count_.end() && it->second > MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) {
return query->set_retry_after_error(60);
}
send_request(make_object<td_api::sendMessageAlbum>(chat_id, 0, reply_to_message_id,
get_message_send_options(disable_notification, std::move(send_at)),
std::move(input_message_contents)),
@ -7906,12 +7974,16 @@ td::Status Client::process_export_chat_invite_link_query(PromisedQueryPtr &query
td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto name = query->arg("name");
auto expire_date = get_integer_arg(query.get(), "expire_date", 0, 0);
auto member_limit = get_integer_arg(query.get(), "member_limit", 0, 0, 100000);
auto creates_join_request = to_bool(query->arg("creates_join_request"));
check_chat(chat_id, AccessRights::Write, std::move(query),
[this, expire_date, member_limit](int64 chat_id, PromisedQueryPtr query) {
send_request(make_object<td_api::createChatInviteLink>(chat_id, expire_date, member_limit),
[this, name = name.str(), expire_date, member_limit, creates_join_request](int64 chat_id,
PromisedQueryPtr query) {
send_request(make_object<td_api::createChatInviteLink>(chat_id, name, expire_date, member_limit,
creates_join_request),
std::make_unique<TdOnGetChatInviteLinkCallback>(this, std::move(query)));
});
return Status::OK();
@ -7920,12 +7992,16 @@ td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query
td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto invite_link = query->arg("invite_link");
auto name = query->arg("name");
auto expire_date = get_integer_arg(query.get(), "expire_date", 0, 0);
auto member_limit = get_integer_arg(query.get(), "member_limit", 0, 0, 100000);
auto creates_join_request = to_bool(query->arg("creates_join_request"));
check_chat(chat_id, AccessRights::Write, std::move(query),
[this, invite_link = invite_link.str(), expire_date, member_limit](int64 chat_id, PromisedQueryPtr query) {
send_request(make_object<td_api::editChatInviteLink>(chat_id, invite_link, expire_date, member_limit),
[this, invite_link = invite_link.str(), name = name.str(), expire_date, member_limit,
creates_join_request](int64 chat_id, PromisedQueryPtr query) {
send_request(make_object<td_api::editChatInviteLink>(chat_id, invite_link, name, expire_date,
member_limit, creates_join_request),
std::make_unique<TdOnGetChatInviteLinkCallback>(this, std::move(query)));
});
return Status::OK();
@ -8231,11 +8307,11 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) {
auto can_restrict_members = to_bool(query->arg("can_restrict_members"));
auto can_pin_messages = to_bool(query->arg("can_pin_messages"));
auto can_promote_members = to_bool(query->arg("can_promote_members"));
auto can_manage_voice_chats = to_bool(query->arg("can_manage_voice_chats"));
auto can_manage_video_chats = to_bool(query->arg("can_manage_voice_chats"));
auto is_anonymous = to_bool(query->arg("is_anonymous"));
auto status = make_object<td_api::chatMemberStatusAdministrator>(
td::string(), true, can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages,
can_invite_users, can_restrict_members, can_pin_messages, can_promote_members, can_manage_voice_chats,
can_invite_users, can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats,
is_anonymous);
check_chat(chat_id, AccessRights::Write, std::move(query),
[this, user_id, status = std::move(status)](int64 chat_id, PromisedQueryPtr query) mutable {
@ -8394,6 +8470,32 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) {
return Status::OK();
}
td::Status Client::process_approve_chat_join_request_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
TRY_RESULT(user_id, get_user_id(query.get()));
check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) {
check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) {
send_request(make_object<td_api::approveChatJoinRequest>(chat_id, user_id),
std::make_unique<TdOnOkQueryCallback>(std::move(query)));
});
});
return Status::OK();
}
td::Status Client::process_decline_chat_join_request_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
TRY_RESULT(user_id, get_user_id(query.get()));
check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) {
check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) {
send_request(make_object<td_api::declineChatJoinRequest>(chat_id, user_id),
std::make_unique<TdOnOkQueryCallback>(std::move(query)));
});
});
return Status::OK();
}
td::Status Client::process_get_sticker_set_query(PromisedQueryPtr &query) {
auto name = query->arg("name");
if (td::trim(to_lower(name)) == to_lower(GREAT_MINDS_SET_NAME)) {
@ -9335,6 +9437,10 @@ void Client::do_send_message(object_ptr<td_api::InputMessageContent> input_messa
auto on_success = [this, disable_notification, input_message_content = std::move(input_message_content),
reply_markup = std::move(reply_markup), send_at = std::move(send_at)](
int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable {
auto it = yet_unsent_message_count_.find(chat_id);
if (it != yet_unsent_message_count_.end() && it->second > MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) {
return query->set_retry_after_error(60);
}
send_request(make_object<td_api::sendMessage>(chat_id, 0, reply_to_message_id,
get_message_send_options(disable_notification, std::move(send_at)),
std::move(reply_markup), std::move(input_message_content)),
@ -9370,6 +9476,7 @@ void Client::on_sent_message(object_ptr<td_api::message> &&message, int64 query_
yet_unsent_message.send_message_query_id = query_id;
auto emplace_result = yet_unsent_messages_.emplace(yet_unsent_message_id, yet_unsent_message);
CHECK(emplace_result.second);
yet_unsent_message_count_[chat_id]++;
pending_send_message_queries_[query_id].awaited_message_count++;
}
@ -9848,6 +9955,8 @@ Client::Slice Client::get_update_type_name(UpdateType update_type) {
return Slice("my_chat_member");
case UpdateType::ChatMember:
return Slice("chat_member");
case UpdateType::ChatJoinRequest:
return Slice("chat_join_request");
default:
UNREACHABLE();
return Slice();
@ -10136,6 +10245,16 @@ void Client::add_update_chat_member(object_ptr<td_api::updateChatMember> &&updat
}
}
void Client::add_update_chat_join_request(object_ptr<td_api::updateNewChatJoinRequest> &&update) {
CHECK(update != nullptr);
CHECK(update->request_ != nullptr);
auto left_time = update->request_->date_ + 86400 - get_unix_time();
if (left_time > 0) {
auto webhook_queue_id = update->chat_id_ + (static_cast<int64>(6) << 33);
add_update(UpdateType::ChatJoinRequest, JsonChatJoinRequest(update.get(), this), left_time, webhook_queue_id);
}
}
td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const {
CHECK(message_add_members != nullptr);
for (auto &member_user_id : message_add_members->member_user_ids_) {
@ -10158,12 +10277,13 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr<td_api::me
case td_api::messageChatChangePhoto::ID:
case td_api::messageChatDeletePhoto::ID:
case td_api::messageChatDeleteMember::ID:
case td_api::messageChatSetTheme::ID:
case td_api::messagePinMessage::ID:
case td_api::messageProximityAlertTriggered::ID:
case td_api::messageVoiceChatScheduled::ID:
case td_api::messageVoiceChatStarted::ID:
case td_api::messageVoiceChatEnded::ID:
case td_api::messageInviteVoiceChatParticipants::ID:
case td_api::messageVideoChatScheduled::ID:
case td_api::messageVideoChatStarted::ID:
case td_api::messageVideoChatEnded::ID:
case td_api::messageInviteVideoChatParticipants::ID:
// don't skip
break;
default:

View File

@ -63,6 +63,8 @@ class Client : public WebhookActor::Callback {
static constexpr int32 MAX_CERTIFICATE_FILE_SIZE = 3 << 20;
static constexpr int32 MAX_DOWNLOAD_FILE_SIZE = 20 << 20;
static constexpr int32 MAX_CONCURRENTLY_SENT_CHAT_MESSAGES = 1000; // some unreasonably big value
static constexpr int32 MESSAGES_CACHE_TIME = 3600;
static constexpr std::size_t MIN_PENDING_UPDATES_WARNING = 200;
@ -143,6 +145,7 @@ class Client : public WebhookActor::Callback {
class JsonChatMember;
class JsonChatMembers;
class JsonChatMemberUpdated;
class JsonChatJoinRequest;
class JsonGameHighScore;
class JsonAddress;
class JsonOrderInfo;
@ -151,10 +154,10 @@ class Client : public WebhookActor::Callback {
class JsonEncryptedCredentials;
class JsonPassportData;
class JsonProximityAlertTriggered;
class JsonVoiceChatScheduled;
class JsonVoiceChatStarted;
class JsonVoiceChatEnded;
class JsonInviteVoiceChatParticipants;
class JsonVideoChatScheduled;
class JsonVideoChatStarted;
class JsonVideoChatEnded;
class JsonInviteVideoChatParticipants;
class JsonChatSetTtl;
class JsonUpdateTypes;
class JsonWebhookInfo;
@ -557,6 +560,8 @@ class Client : public WebhookActor::Callback {
Status process_ban_chat_member_query(PromisedQueryPtr &query);
Status process_restrict_chat_member_query(PromisedQueryPtr &query);
Status process_unban_chat_member_query(PromisedQueryPtr &query);
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_upload_sticker_file_query(PromisedQueryPtr &query);
Status process_create_new_sticker_set_query(PromisedQueryPtr &query);
@ -900,6 +905,8 @@ class Client : public WebhookActor::Callback {
void add_update_chat_member(object_ptr<td_api::updateChatMember> &&update);
void add_update_chat_join_request(object_ptr<td_api::updateNewChatJoinRequest> &&update);
// append only before Size
enum class UpdateType : int32 {
Message,
@ -917,6 +924,7 @@ class Client : public WebhookActor::Callback {
PollAnswer,
MyChatMember,
ChatMember,
ChatJoinRequest,
Size
};
@ -998,6 +1006,8 @@ class Client : public WebhookActor::Callback {
};
std::unordered_map<FullMessageId, YetUnsentMessage, FullMessageIdHash> yet_unsent_messages_;
std::unordered_map<int64, int32> yet_unsent_message_count_;
struct PendingSendMessageQuery {
PromisedQueryPtr query;
bool is_multisend = false;

View File

@ -93,12 +93,18 @@ void ClientManager::send(PromisedQueryPtr query) {
if (!check_flood_limits(query)) {
return;
}
auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), token, td::ActorOwn<Client>()});
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()) {
// return query->set_retry_after_error(1);
}
auto id =
clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), token, tqueue_id, td::ActorOwn<Client>()});
auto *client_info = clients_.get(id);
client_info->client_ =
td::create_actor<Client>(PSLICE() << "Client/" << token, actor_shared(this, id), query->token().str(), query->is_user(),
query->is_test_dc(), get_tqueue_id(r_user_id.ok(), query->is_test_dc()), parameters_,
client_info->stat_.actor_id(&client_info->stat_));
client_info->client_ = td::create_actor<Client>(PSLICE() << "Client/" << token, actor_shared(this, id),
query->token().str(), query->is_user(), query->is_test_dc(),
tqueue_id, parameters_, client_info->stat_.actor_id(&client_info->stat_));
auto method = query->method();
if (method != "deletewebhook" && method != "setwebhook") {
@ -139,7 +145,12 @@ void ClientManager::user_login(PromisedQueryPtr query) {
long token_hash = std::hash<td::string>{}(user_token);
auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), user_token, td::ActorOwn<Client>()});
auto tqueue_id = get_tqueue_id(token_hash, query->is_test_dc());
if (active_client_count_.find(tqueue_id) != active_client_count_.end()) {
// return query->set_retry_after_error(1);
}
auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), user_token, tqueue_id, td::ActorOwn<Client>()});
auto *client_info = clients_.get(id);
auto stat_actor = client_info->stat_.actor_id(&client_info->stat_);
auto client_id = td::create_actor<Client>(PSLICE() << "Client/" << user_token, actor_shared(this, id), user_token,
@ -270,23 +281,23 @@ void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
}
if(!as_json) {
sb << stat_.get_description() << "\n";
sb << stat_.get_description() << '\n';
}
if (id_filter.empty()) {
if(as_json) {
jb_root("uptime", td::JsonFloat(now - parameters_->start_time_));
} else {
sb << "uptime\t" << now - parameters_->start_time_ << "\n";
sb << "uptime\t" << now - parameters_->start_time_ << '\n';
}
if(as_json) {
jb_root("bot_count", td::JsonLong(clients_.size()));
} else {
sb << "bot_count\t" << clients_.size() << "\n";
sb << "bot_count\t" << clients_.size() << '\n';
}
if(as_json) {
jb_root("active_bot_count", td::JsonInt(active_bot_count));
} else {
sb << "active_bot_count\t" << active_bot_count << "\n";
sb << "active_bot_count\t" << active_bot_count << '\n';
}
auto r_mem_stat = td::mem_stat();
if (r_mem_stat.is_ok()) {
@ -294,10 +305,10 @@ void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
if(as_json) {
jb_root("memory", JsonStatsMem(mem_stat));
} else {
sb << "rss\t" << td::format::as_size(mem_stat.resident_size_) << "\n";
sb << "vm\t" << td::format::as_size(mem_stat.virtual_size_) << "\n";
sb << "rss_peak\t" << td::format::as_size(mem_stat.resident_size_peak_) << "\n";
sb << "vm_peak\t" << td::format::as_size(mem_stat.virtual_size_peak_) << "\n";
sb << "rss\t" << td::format::as_size(mem_stat.resident_size_) << '\n';
sb << "vm\t" << td::format::as_size(mem_stat.virtual_size_) << '\n';
sb << "rss_peak\t" << td::format::as_size(mem_stat.resident_size_peak_) << '\n';
sb << "vm_peak\t" << td::format::as_size(mem_stat.virtual_size_peak_) << '\n';
}
} else {
if(as_json) {
@ -314,7 +325,7 @@ void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
} else {
auto cpu_stats = ServerCpuStat::instance().as_vector(td::Time::now());
for (auto &stat : cpu_stats) {
sb << stat.key_ << "\t" << stat.value_ << "\n";
sb << stat.key_ << "\t" << stat.value_ << '\n';
}
}
@ -324,16 +335,16 @@ void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
jb_root("active_requests", td::JsonLong(parameters_->shared_data_->query_count_.load()));
jb_root("active_network_queries", td::JsonLong(td::get_pending_network_query_count(*parameters_->net_query_stats_)));
} else {
sb << "buffer_memory\t" << td::format::as_size(td::BufferAllocator::get_buffer_mem()) << "\n";
sb << "active_webhook_connections\t" << WebhookActor::get_total_connections_count() << "\n";
sb << "active_requests\t" << parameters_->shared_data_->query_count_.load() << "\n";
sb << "active_network_queries\t" << td::get_pending_network_query_count(*parameters_->net_query_stats_) << "\n";
sb << "buffer_memory\t" << td::format::as_size(td::BufferAllocator::get_buffer_mem()) << '\n';
sb << "active_webhook_connections\t" << WebhookActor::get_total_connections_count() << '\n';
sb << "active_requests\t" << parameters_->shared_data_->query_count_.load() << '\n';
sb << "active_network_queries\t" << td::get_pending_network_query_count(*parameters_->net_query_stats_) << '\n';
}
if(as_json) {
} else {
auto stats = stat_.as_vector(now);
for (auto &stat : stats) {
sb << stat.key_ << "\t" << stat.value_ << "\n";
sb << stat.key_ << "\t" << stat.value_ << '\n';
}
}
}
@ -358,30 +369,30 @@ void ClientManager::get_stats(td::PromiseActor<td::BufferSlice> promise,
CHECK(client_info);
auto bot_info = client_info->client_->get_actor_unsafe()->get_bot_info();
sb << "\n";
sb << "id\t" << bot_info.id_ << "\n";
sb << "uptime\t" << now - bot_info.start_time_ << "\n";
sb << '\n';
sb << "id\t" << bot_info.id_ << '\n';
sb << "uptime\t" << now - bot_info.start_time_ << '\n';
if (!parameters_->stats_hide_sensible_data_) {
sb << "token\t" << bot_info.token_ << "\n";
sb << "token\t" << bot_info.token_ << '\n';
}
sb << "username\t" << bot_info.username_ << "\n";
sb << "username\t" << bot_info.username_ << '\n';
if (!parameters_->stats_hide_sensible_data_) {
sb << "webhook\t" << bot_info.webhook_ << "\n";
sb << "webhook\t" << bot_info.webhook_ << '\n';
} else if (bot_info.webhook_.empty()) {
sb << "webhook disabled" << "\n";
sb << "webhook disabled" << '\n';
} else {
sb << "webhook enabled" << "\n";
sb << "webhook enabled" << '\n';
}
sb << "has_custom_certificate\t" << bot_info.has_webhook_certificate_ << "\n";
sb << "head_update_id\t" << bot_info.head_update_id_ << "\n";
sb << "tail_update_id\t" << bot_info.tail_update_id_ << "\n";
sb << "pending_update_count\t" << bot_info.pending_update_count_ << "\n";
sb << "webhook_max_connections\t" << bot_info.webhook_max_connections_ << "\n";
sb << "has_custom_certificate\t" << bot_info.has_webhook_certificate_ << '\n';
sb << "head_update_id\t" << bot_info.head_update_id_ << '\n';
sb << "tail_update_id\t" << bot_info.tail_update_id_ << '\n';
sb << "pending_update_count\t" << bot_info.pending_update_count_ << '\n';
sb << "webhook_max_connections\t" << bot_info.webhook_max_connections_ << '\n';
auto stats = client_info->stat_.as_vector(now);
for (auto &stat : stats) {
if (stat.key_ == "update_count" || stat.key_ == "request_count") {
sb << stat.key_ << "/sec\t" << stat.value_ << "\n";
sb << stat.key_ << "/sec\t" << stat.value_ << '\n';
}
}
if (sb.is_error()) {
@ -526,6 +537,21 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, bool
return PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor<td::unique_ptr<Query>>()));
}
void ClientManager::raw_event(const td::Event::Raw &event) {
auto id = get_link_token();
auto *info = clients_.get(id);
CHECK(info != nullptr);
auto &value = active_client_count_[info->tqueue_id_];
if (event.ptr != nullptr) {
value++;
} else {
CHECK(value > 0);
if (--value == 0) {
active_client_count_.erase(info->tqueue_id_);
}
}
}
void ClientManager::hangup_shared() {
auto id = get_link_token();
auto *info = clients_.get(id);
@ -535,19 +561,23 @@ void ClientManager::hangup_shared() {
clients_.erase(id);
if (close_flag_ && clients_.empty()) {
CHECK(active_client_count_.empty());
close_db();
}
}
void ClientManager::close_db() {
LOG(WARNING) << "Closing databases";
td::MultiPromiseActorSafe mpromise("close binlogs");
mpromise.add_promise(td::PromiseCreator::lambda(
td::MultiPromiseActorSafe mpas("close binlogs");
mpas.add_promise(td::PromiseCreator::lambda(
[actor_id = actor_id(this)](td::Unit) { send_closure(actor_id, &ClientManager::finish_close); }));
mpas.set_ignore_errors(true);
parameters_->shared_data_->tqueue_->close(mpromise.get_promise());
parameters_->shared_data_->webhook_db_->close(mpromise.get_promise());
parameters_->shared_data_->user_db_->close(mpromise.get_promise());
auto lock = mpas.get_promise();
parameters_->shared_data_->tqueue_->close(mpas.get_promise());
parameters_->shared_data_->webhook_db_->close(mpas.get_promise());
parameters_->shared_data_->user_db_->close(mpas.get_promise());
lock.set_value(td::Unit());
}
void ClientManager::finish_close() {

View File

@ -55,6 +55,7 @@ class ClientManager final : public td::Actor {
public:
BotStatActor stat_;
td::string token_;
td::int64 tqueue_id_;
td::ActorOwn<Client> client_;
};
td::Container<ClientInfo> clients_;
@ -65,6 +66,7 @@ class ClientManager final : public td::Actor {
std::unordered_map<td::string, td::uint64> token_to_id_;
std::unordered_map<td::string, td::FloodControlFast> flood_controls_;
std::unordered_map<td::int64, td::uint64> active_client_count_;
bool close_flag_ = false;
td::vector<td::Promise<td::Unit>> close_promises_;
@ -75,6 +77,7 @@ class ClientManager final : public td::Actor {
std::shared_ptr<SharedData> shared_data);
void start_up() override;
void raw_event(const td::Event::Raw &event) override;
void hangup_shared() override;
void close_db();
void finish_close();

View File

@ -11,6 +11,7 @@
#include "td/net/HttpInboundConnection.h"
#include "td/net/TcpListener.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/FloodControlFast.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
@ -64,8 +65,8 @@ class HttpServer : public td::TcpListener::Callback {
if (scheduler_id > 0) {
scheduler_id--;
}
td::create_actor<td::HttpInboundConnection>("HttpInboundConnection", std::move(fd), 0, 20, 500, creator_(),
scheduler_id)
td::create_actor<td::HttpInboundConnection>("HttpInboundConnection", td::BufferedFd<td::SocketFd>(std::move(fd)), 0,
20, 500, creator_(), scheduler_id)
.release();
}

View File

@ -156,7 +156,7 @@ td::Status WebhookActor::create_connection() {
public:
Callback(td::ActorId<WebhookActor> actor, td::int64 id) : actor_(actor), id_(id) {
}
void set_result(td::Result<td::SocketFd> result) override {
void set_result(td::Result<td::BufferedFd<td::SocketFd>> result) override {
send_closure(std::move(actor_), &WebhookActor::on_socket_ready_async, std::move(result), id_);
CHECK(actor_.empty());
}
@ -195,7 +195,7 @@ td::Status WebhookActor::create_connection() {
on_error(r_fd.move_as_error());
return error;
}
return create_connection(r_fd.move_as_ok());
return create_connection(td::BufferedFd<td::SocketFd>(r_fd.move_as_ok()));
}
td::Result<td::SslStream> WebhookActor::create_ssl_stream() {
@ -215,7 +215,7 @@ td::Result<td::SslStream> WebhookActor::create_ssl_stream() {
return r_ssl_stream.move_as_ok();
}
td::Status WebhookActor::create_connection(td::SocketFd fd) {
td::Status WebhookActor::create_connection(td::BufferedFd<td::SocketFd> fd) {
TRY_RESULT(ssl_stream, create_ssl_stream());
auto id = connections_.create(Connection());
@ -237,7 +237,7 @@ td::Status WebhookActor::create_connection(td::SocketFd fd) {
return td::Status::OK();
}
void WebhookActor::on_socket_ready_async(td::Result<td::SocketFd> r_fd, td::int64 id) {
void WebhookActor::on_socket_ready_async(td::Result<td::BufferedFd<td::SocketFd>> r_fd, td::int64 id) {
pending_sockets_.erase(id);
if (r_fd.is_ok()) {
VLOG(webhook) << "Socket " << id << " is ready";

View File

@ -17,6 +17,7 @@
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
#include "td/utils/BufferedFd.h"
#include "td/utils/common.h"
#include "td/utils/Container.h"
#include "td/utils/FloodControlFast.h"
@ -159,7 +160,7 @@ class WebhookActor : public td::HttpOutboundConnection::Callback {
}
};
td::Container<td::ActorOwn<>> pending_sockets_;
td::vector<td::SocketFd> ready_sockets_;
td::vector<td::BufferedFd<td::SocketFd>> ready_sockets_;
td::int32 max_connections_ = 0;
td::Container<Connection> connections_;
@ -176,8 +177,8 @@ class WebhookActor : public td::HttpOutboundConnection::Callback {
td::Result<td::SslStream> create_ssl_stream();
td::Status create_connection() TD_WARN_UNUSED_RESULT;
td::Status create_connection(td::SocketFd fd) TD_WARN_UNUSED_RESULT;
void on_socket_ready_async(td::Result<td::SocketFd> r_fd, td::int64 id);
td::Status create_connection(td::BufferedFd<td::SocketFd> fd) TD_WARN_UNUSED_RESULT;
void on_socket_ready_async(td::Result<td::BufferedFd<td::SocketFd>> r_fd, td::int64 id);
void create_new_connections();

View File

@ -198,7 +198,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_ = "5.3.3";
parameters->version_ = "5.4";
parameters->shared_data_ = shared_data;
parameters->start_time_ = start_time;
auto net_query_stats = td::create_net_query_stats();