Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Giuseppe Marino 2023-02-04 15:31:24 +01:00
commit 85763a1591
No known key found for this signature in database
GPG Key ID: C26F7A532ADEC25E
23 changed files with 298 additions and 95 deletions

View File

@ -69,10 +69,10 @@ jobs:
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2
- name: Cache Docker layers
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ env.SAFE_ARCH }}-${{ github.sha }}

View File

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

2
td

@ -1 +1 @@
Subproject commit 5ee9c7365b9533d207887e32a9d71645e5d30fd8
Subproject commit 3179d35694a28267a0b6273fc9b5bdce3b6b1235

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -819,10 +819,12 @@ class Client::JsonChat final : public Jsonable {
}
object("permissions", JsonChatPermissions(permissions));
}
auto everyone_is_administrator = permissions->can_send_messages_ && permissions->can_send_media_messages_ &&
permissions->can_send_polls_ && permissions->can_send_other_messages_ &&
permissions->can_add_web_page_previews_ && permissions->can_change_info_ &&
permissions->can_invite_users_ && permissions->can_pin_messages_;
auto everyone_is_administrator =
permissions->can_send_messages_ && permissions->can_send_audios_ && permissions->can_send_documents_ &&
permissions->can_send_photos_ && permissions->can_send_videos_ && permissions->can_send_video_notes_ &&
permissions->can_send_voice_notes_ && permissions->can_send_polls_ &&
permissions->can_send_other_messages_ && permissions->can_add_web_page_previews_ &&
permissions->can_change_info_ && permissions->can_invite_users_ && permissions->can_pin_messages_;
object("all_members_are_administrators", td::JsonBool(everyone_is_administrator));
photo = group_info->photo.get();
break;
@ -1825,6 +1827,34 @@ class Client::JsonChatSetMessageAutoDeleteTime final : public Jsonable {
const td_api::messageChatSetMessageAutoDeleteTime *chat_set_message_auto_delete_time_;
};
class Client::JsonUserShared final : public Jsonable {
public:
explicit JsonUserShared(const td_api::messageUserShared *user_shared) : user_shared_(user_shared) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("user_id", user_shared_->user_id_);
object("request_id", user_shared_->button_id_);
}
private:
const td_api::messageUserShared *user_shared_;
};
class Client::JsonChatShared final : public Jsonable {
public:
explicit JsonChatShared(const td_api::messageChatShared *chat_shared) : chat_shared_(chat_shared) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
object("chat_id", chat_shared_->chat_id_);
object("request_id", chat_shared_->button_id_);
}
private:
const td_api::messageChatShared *chat_shared_;
};
class Client::JsonWebAppInfo final : public Jsonable {
public:
explicit JsonWebAppInfo(const td::string &url) : url_(url) {
@ -2315,6 +2345,16 @@ void Client::JsonMessage::store(JsonValueScope *scope) const {
case td_api::messageBotWriteAccessAllowed::ID:
object("write_access_allowed", JsonEmptyObject());
break;
case td_api::messageUserShared::ID: {
auto content = static_cast<const td_api::messageUserShared *>(message_->content.get());
object("user_shared", JsonUserShared(content));
break;
}
case td_api::messageChatShared::ID: {
auto content = static_cast<const td_api::messageChatShared *>(message_->content.get());
object("chat_shared", JsonChatShared(content));
break;
}
default:
UNREACHABLE();
}
@ -2825,6 +2865,7 @@ class Client::JsonChatJoinRequest final : public Jsonable {
auto object = scope->enter_object();
object("chat", JsonChat(update_->chat_id_, false, client_));
object("from", JsonUser(update_->request_->user_id_, client_));
object("user_chat_id", update_->user_chat_id_);
object("date", update_->request_->date_);
if (!update_->request_->bio_.empty()) {
object("bio", update_->request_->bio_);
@ -4718,7 +4759,11 @@ ServerBotInfo Client::get_bot_info() const {
if (user_info != nullptr) {
res.username_ = user_info->editable_username;
} else if (!was_authorized_) {
res.username_ = "<unauthorized>";
if (logging_out_) {
res.username_ = "<failed to authorize>";
} else {
res.username_ = "<unauthorized>";
}
} else {
res.username_ = "<unknown>";
}
@ -6000,7 +6045,8 @@ void Client::timeout_expired() {
void Client::clear_tqueue() {
CHECK(webhook_id_.empty());
auto &tqueue = parameters_->shared_data_->tqueue_;
tqueue->clear(tqueue_id_, 0);
auto deleted_events = tqueue->clear(tqueue_id_, 0);
td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), deleted_events);
}
bool Client::to_bool(td::MutableSlice value) {
@ -6050,6 +6096,47 @@ td::Result<td_api::object_ptr<td_api::keyboardButton>> Client::get_keyboard_butt
return make_object<td_api::keyboardButton>(text, make_object<td_api::keyboardButtonTypeWebApp>(url));
}
if (has_json_object_field(object, "request_user")) {
TRY_RESULT(request_user, get_json_object_field(object, "request_user", JsonValue::Type::Object, false));
auto &request_user_object = request_user.get_object();
TRY_RESULT(id, get_json_object_int_field(request_user_object, "request_id", false));
auto restrict_user_is_bot = has_json_object_field(request_user_object, "user_is_bot");
TRY_RESULT(user_is_bot, get_json_object_bool_field(request_user_object, "user_is_bot"));
auto restrict_user_is_premium = has_json_object_field(request_user_object, "user_is_premium");
TRY_RESULT(user_is_premium, get_json_object_bool_field(request_user_object, "user_is_premium"));
return make_object<td_api::keyboardButton>(
text, make_object<td_api::keyboardButtonTypeRequestUser>(id, restrict_user_is_bot, user_is_bot,
restrict_user_is_premium, user_is_premium));
}
if (has_json_object_field(object, "request_chat")) {
TRY_RESULT(request_chat, get_json_object_field(object, "request_chat", JsonValue::Type::Object, false));
auto &request_chat_object = request_chat.get_object();
TRY_RESULT(id, get_json_object_int_field(request_chat_object, "request_id", false));
TRY_RESULT(chat_is_channel, get_json_object_bool_field(request_chat_object, "chat_is_channel"));
auto restrict_chat_is_forum = has_json_object_field(request_chat_object, "chat_is_forum");
TRY_RESULT(chat_is_forum, get_json_object_bool_field(request_chat_object, "chat_is_forum"));
auto restrict_chat_has_username = has_json_object_field(request_chat_object, "chat_has_username");
TRY_RESULT(chat_has_username, get_json_object_bool_field(request_chat_object, "chat_has_username"));
TRY_RESULT(chat_is_created, get_json_object_bool_field(request_chat_object, "chat_is_created"));
td_api::object_ptr<td_api::chatAdministratorRights> user_administrator_rights;
if (has_json_object_field(request_chat_object, "user_administrator_rights")) {
TRY_RESULT_ASSIGN(user_administrator_rights, get_chat_administrator_rights(get_json_object_field_force(
request_chat_object, "user_administrator_rights")));
}
td_api::object_ptr<td_api::chatAdministratorRights> bot_administrator_rights;
if (has_json_object_field(request_chat_object, "bot_administrator_rights")) {
TRY_RESULT_ASSIGN(bot_administrator_rights, get_chat_administrator_rights(get_json_object_field_force(
request_chat_object, "bot_administrator_rights")));
}
TRY_RESULT(bot_is_member, get_json_object_bool_field(request_chat_object, "bot_is_member"));
return make_object<td_api::keyboardButton>(
text, make_object<td_api::keyboardButtonTypeRequestChat>(
id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username,
chat_has_username, chat_is_created, std::move(user_administrator_rights),
std::move(bot_administrator_rights), bot_is_member));
}
return make_object<td_api::keyboardButton>(text, nullptr);
}
if (button.type() == JsonValue::Type::String) {
@ -7551,10 +7638,15 @@ td::Result<td_api::object_ptr<td_api::location>> Client::get_location(const Quer
td::to_double(horizontal_accuracy));
}
td::Result<td_api::object_ptr<td_api::chatPermissions>> Client::get_chat_permissions(const Query *query,
bool &allow_legacy) {
td::Result<td_api::object_ptr<td_api::chatPermissions>> Client::get_chat_permissions(
const Query *query, bool &allow_legacy, bool use_independent_chat_permissions) {
auto can_send_messages = false;
auto can_send_media_messages = false;
auto can_send_audios = false;
auto can_send_documents = false;
auto can_send_photos = false;
auto can_send_videos = false;
auto can_send_video_notes = false;
auto can_send_voice_notes = false;
auto can_send_polls = false;
auto can_send_other_messages = false;
auto can_add_web_page_previews = false;
@ -7580,7 +7672,6 @@ td::Result<td_api::object_ptr<td_api::chatPermissions>> Client::get_chat_permiss
auto status = [&] {
TRY_RESULT_ASSIGN(can_send_messages, get_json_object_bool_field(object, "can_send_messages"));
TRY_RESULT_ASSIGN(can_send_media_messages, get_json_object_bool_field(object, "can_send_media_messages"));
TRY_RESULT_ASSIGN(can_send_polls, get_json_object_bool_field(object, "can_send_polls"));
TRY_RESULT_ASSIGN(can_send_other_messages, get_json_object_bool_field(object, "can_send_other_messages"));
TRY_RESULT_ASSIGN(can_add_web_page_previews, get_json_object_bool_field(object, "can_add_web_page_previews"));
@ -7592,19 +7683,60 @@ td::Result<td_api::object_ptr<td_api::chatPermissions>> Client::get_chat_permiss
} else {
can_manage_topics = can_pin_messages;
}
if (has_json_object_field(object, "can_send_audios") || has_json_object_field(object, "can_send_documents") ||
has_json_object_field(object, "can_send_photos") || has_json_object_field(object, "can_send_videos") ||
has_json_object_field(object, "can_send_video_notes") ||
has_json_object_field(object, "can_send_voice_notes")) {
TRY_RESULT_ASSIGN(can_send_audios, get_json_object_bool_field(object, "can_send_audios"));
TRY_RESULT_ASSIGN(can_send_documents, get_json_object_bool_field(object, "can_send_documents"));
TRY_RESULT_ASSIGN(can_send_photos, get_json_object_bool_field(object, "can_send_photos"));
TRY_RESULT_ASSIGN(can_send_videos, get_json_object_bool_field(object, "can_send_videos"));
TRY_RESULT_ASSIGN(can_send_video_notes, get_json_object_bool_field(object, "can_send_video_notes"));
TRY_RESULT_ASSIGN(can_send_voice_notes, get_json_object_bool_field(object, "can_send_voice_notes"));
} else {
TRY_RESULT(can_send_media_messages, get_json_object_bool_field(object, "can_send_media_messages"));
can_send_audios = can_send_media_messages;
can_send_documents = can_send_media_messages;
can_send_photos = can_send_media_messages;
can_send_videos = can_send_media_messages;
can_send_video_notes = can_send_media_messages;
can_send_voice_notes = can_send_media_messages;
if (can_send_media_messages && !use_independent_chat_permissions) {
can_send_messages = true;
}
}
return Status::OK();
}();
if (status.is_error()) {
return Status::Error(400, PSLICE() << "Can't parse chat permissions: " << status.message());
}
if ((can_send_other_messages || can_add_web_page_previews) && !use_independent_chat_permissions) {
can_send_audios = true;
can_send_documents = true;
can_send_photos = true;
can_send_videos = true;
can_send_video_notes = true;
can_send_voice_notes = true;
can_send_messages = true;
}
if (can_send_polls && !use_independent_chat_permissions) {
can_send_messages = true;
}
} else if (allow_legacy) {
allow_legacy = false;
can_send_messages = to_bool(query->arg("can_send_messages"));
can_send_media_messages = to_bool(query->arg("can_send_media_messages"));
bool can_send_media_messages = to_bool(query->arg("can_send_media_messages"));
can_send_other_messages = to_bool(query->arg("can_send_other_messages"));
can_add_web_page_previews = to_bool(query->arg("can_add_web_page_previews"));
if ((can_send_other_messages || can_add_web_page_previews) && !use_independent_chat_permissions) {
can_send_media_messages = true;
}
if (can_send_media_messages && !use_independent_chat_permissions) {
can_send_messages = true;
}
if (can_send_messages && can_send_media_messages && can_send_other_messages && can_add_web_page_previews) {
// legacy unrestrict
@ -7617,14 +7749,19 @@ td::Result<td_api::object_ptr<td_api::chatPermissions>> Client::get_chat_permiss
query->has_arg("can_send_other_messages") || query->has_arg("can_add_web_page_previews")) {
allow_legacy = true;
}
can_send_audios = can_send_media_messages;
can_send_documents = can_send_media_messages;
can_send_photos = can_send_media_messages;
can_send_videos = can_send_media_messages;
can_send_video_notes = can_send_media_messages;
can_send_voice_notes = can_send_media_messages;
}
if (can_send_other_messages || can_add_web_page_previews) {
can_send_media_messages = true;
}
return make_object<td_api::chatPermissions>(can_send_messages, can_send_media_messages, can_send_polls,
can_send_other_messages, can_add_web_page_previews, can_change_info,
can_invite_users, can_pin_messages, can_manage_topics);
return make_object<td_api::chatPermissions>(can_send_messages, can_send_audios, can_send_documents, can_send_photos,
can_send_videos, can_send_video_notes, can_send_voice_notes,
can_send_polls, can_send_other_messages, can_add_web_page_previews,
can_change_info, can_invite_users, can_pin_messages, can_manage_topics);
}
td::Result<td_api::object_ptr<td_api::InputMessageContent>> Client::get_input_media(const Query *query,
@ -9123,7 +9260,8 @@ td::Status Client::process_set_chat_title_query(PromisedQueryPtr &query) {
td::Status Client::process_set_chat_permissions_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
bool allow_legacy = false;
TRY_RESULT(permissions, get_chat_permissions(query.get(), allow_legacy));
auto use_independent_chat_permissions = to_bool(query->arg("use_independent_chat_permissions"));
TRY_RESULT(permissions, get_chat_permissions(query.get(), allow_legacy, use_independent_chat_permissions));
CHECK(!allow_legacy);
check_chat(chat_id, AccessRights::Write, std::move(query),
@ -9575,7 +9713,8 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) {
TRY_RESULT(user_id, get_user_id(query.get()));
int32 until_date = get_integer_arg(query.get(), "until_date", 0);
bool allow_legacy = true;
TRY_RESULT(permissions, get_chat_permissions(query.get(), allow_legacy));
auto use_independent_chat_permissions = to_bool(query->arg("use_independent_chat_permissions"));
TRY_RESULT(permissions, get_chat_permissions(query.get(), allow_legacy, use_independent_chat_permissions));
check_chat(chat_id, AccessRights::Write, std::move(query),
[this, user_id, until_date, is_legacy = allow_legacy, permissions = std::move(permissions)](
@ -10303,10 +10442,10 @@ td::Status Client::process_create_chat_query(PromisedQueryPtr &query) {
auto description = query->arg("description");
auto message_auto_delete_time = get_integer_arg(query.get(), "message_auto_delete_time", 0);
if (chat_type == "supergroup") {
send_request(make_object<td_api::createNewSupergroupChat>(title.str(), false, description.str(), nullptr, message_auto_delete_time, false),
send_request(make_object<td_api::createNewSupergroupChat>(title.str(), false, false, description.str(), nullptr, message_auto_delete_time, false),
td::make_unique<TdOnReturnChatCallback>(this, std::move(query)));
} else if (chat_type == "channel") {
send_request(make_object<td_api::createNewSupergroupChat>(title.str(), true, description.str(), nullptr, message_auto_delete_time, false),
send_request(make_object<td_api::createNewSupergroupChat>(title.str(), false, true, description.str(), nullptr, message_auto_delete_time, false),
td::make_unique<TdOnReturnChatCallback>(this, std::move(query)));
} else if (chat_type == "group") {
TRY_RESULT(initial_members, get_int_array_arg<td::int64>(query.get(), "user_ids"))
@ -10920,7 +11059,8 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu
LOG(DEBUG) << "Queue head = " << tqueue->get_head(tqueue_id_) << ", queue tail = " << tqueue->get_tail(tqueue_id_);
if (offset < 0) {
tqueue->clear(tqueue_id_, -offset);
auto deleted_events = tqueue->clear(tqueue_id_, -offset);
td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), deleted_events);
}
if (offset <= 0) {
offset = tqueue->get_head(tqueue_id_).value();
@ -11375,8 +11515,17 @@ void Client::json_store_administrator_rights(td::JsonObjectScope &object, const
}
void Client::json_store_permissions(td::JsonObjectScope &object, const td_api::chatPermissions *permissions) {
bool can_send_media_messages = permissions->can_send_audios_ || permissions->can_send_documents_ ||
permissions->can_send_photos_ || permissions->can_send_videos_ ||
permissions->can_send_video_notes_ || permissions->can_send_voice_notes_;
object("can_send_messages", td::JsonBool(permissions->can_send_messages_));
object("can_send_media_messages", td::JsonBool(permissions->can_send_media_messages_));
object("can_send_media_messages", td::JsonBool(can_send_media_messages));
object("can_send_audios", td::JsonBool(permissions->can_send_audios_));
object("can_send_documents", td::JsonBool(permissions->can_send_documents_));
object("can_send_photos", td::JsonBool(permissions->can_send_photos_));
object("can_send_videos", td::JsonBool(permissions->can_send_videos_));
object("can_send_video_notes", td::JsonBool(permissions->can_send_video_notes_));
object("can_send_voice_notes", td::JsonBool(permissions->can_send_voice_notes_));
object("can_send_polls", td::JsonBool(permissions->can_send_polls_));
object("can_send_other_messages", td::JsonBool(permissions->can_send_other_messages_));
object("can_add_web_page_previews", td::JsonBool(permissions->can_add_web_page_previews_));

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -173,6 +173,8 @@ class Client final : public WebhookActor::Callback {
class JsonVideoChatEnded;
class JsonInviteVideoChatParticipants;
class JsonChatSetMessageAutoDeleteTime;
class JsonUserShared;
class JsonChatShared;
class JsonUpdateTypes;
class JsonWebhookInfo;
class JsonStickerSet;
@ -484,7 +486,8 @@ class Client final : public WebhookActor::Callback {
static td::Result<object_ptr<td_api::location>> get_location(const Query *query);
static td::Result<object_ptr<td_api::chatPermissions>> get_chat_permissions(const Query *query, bool &allow_legacy);
static td::Result<object_ptr<td_api::chatPermissions>> get_chat_permissions(const Query *query, bool &allow_legacy,
bool use_independent_chat_permissions);
td::Result<object_ptr<td_api::InputMessageContent>> get_input_media(const Query *query, td::JsonValue &&input_media,
bool for_album) const;

View File

@ -221,6 +221,39 @@ bool ClientManager::check_flood_limits(PromisedQueryPtr &query, bool is_user_log
return true;
}
ClientManager::TopClients ClientManager::get_top_clients(std::size_t max_count, td::Slice token_filter) {
auto now = td::Time::now();
TopClients result;
td::vector<std::pair<td::int64, td::uint64>> top_client_ids;
for (auto id : clients_.ids()) {
auto *client_info = clients_.get(id);
CHECK(client_info);
if (client_info->stat_.is_active(now)) {
result.active_count++;
}
if (!td::begins_with(client_info->token_, token_filter)) {
continue;
}
auto score = static_cast<td::int64>(client_info->stat_.get_score(now) * -1e9);
if (score == 0 && top_client_ids.size() >= max_count) {
continue;
}
top_client_ids.emplace_back(score, id);
}
if (top_client_ids.size() < max_count) {
max_count = top_client_ids.size();
}
std::partial_sort(top_client_ids.begin(), top_client_ids.begin() + max_count, top_client_ids.end());
result.top_client_ids.reserve(max_count);
for (std::size_t i = 0; i < max_count; i++) {
result.top_client_ids.push_back(top_client_ids[i].second);
}
return result;
}
void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
td::vector<std::pair<td::string, td::string>> args,
bool as_json) {
@ -266,32 +299,7 @@ void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
}
auto now = td::Time::now();
td::int32 active_bot_count = 0;
td::vector<std::pair<td::int64, td::uint64>> top_bot_ids;
size_t max_bots = 50;
for (auto id : clients_.ids()) {
auto *client_info = clients_.get(id);
CHECK(client_info);
if (client_info->stat_.is_active(now)) {
active_bot_count++;
}
if (!td::begins_with(client_info->token_, id_filter)) {
continue;
}
auto score = static_cast<td::int64>(client_info->stat_.get_score(now) * -1e9);
if (score == 0 && top_bot_ids.size() >= max_bots) {
continue;
}
top_bot_ids.emplace_back(score, id);
}
if (top_bot_ids.size() < max_bots) {
max_bots = top_bot_ids.size();
}
std::partial_sort(top_bot_ids.begin(), top_bot_ids.begin() + max_bots, top_bot_ids.end());
top_bot_ids.resize(max_bots);
auto top_clients = get_top_clients(50, id_filter);
if(!as_json) {
sb << stat_.get_description() << '\n';
@ -308,9 +316,9 @@ void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
sb << "bot_count\t" << clients_.size() << '\n';
}
if(as_json) {
jb_root("active_bot_count", td::JsonInt(active_bot_count));
jb_root("active_bot_count", td::JsonInt(top_clients.active_count));
} else {
sb << "active_bot_count\t" << active_bot_count << '\n';
sb << "active_bot_count\t" << top_clients.active_count << '\n';
}
auto r_mem_stat = td::mem_stat();
if (r_mem_stat.is_ok()) {
@ -364,8 +372,8 @@ void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
if(as_json) {
td::vector<JsonStatsBotAdvanced> bots;
for (std::pair<td::int64, td::uint64> top_bot_id : top_bot_ids) {
auto client_info = clients_.get(top_bot_id.second);
for (auto top_client_id : top_clients.top_client_ids) {
auto client_info = clients_.get(top_client_id);
CHECK(client_info);
ServerBotInfo bot_info = client_info->client_.get_actor_unsafe()->get_bot_info();
auto active_request_count = client_info->stat_.get_active_request_count();
@ -373,15 +381,15 @@ void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
auto active_file_upload_count = client_info->stat_.get_active_file_upload_count();
auto stats = client_info->stat_.as_json_ready_vector(now);
JsonStatsBotAdvanced bot(
std::move(top_bot_id), std::move(bot_info), active_request_count, active_file_upload_bytes, active_file_upload_count, std::move(stats), parameters_->stats_hide_sensible_data_, now
std::move(top_client_id), std::move(bot_info), active_request_count, active_file_upload_bytes, active_file_upload_count, std::move(stats), parameters_->stats_hide_sensible_data_, now
);
bots.push_back(bot);
}
auto bot_count = bots.size();
jb_root("bots", JsonStatsBots(std::move(bots), bot_count > 100));
} else {
for (auto top_bot_id : top_bot_ids) {
auto *client_info = clients_.get(top_bot_id.second);
for (auto top_client_id : top_clients.top_client_ids) {
auto *client_info = clients_.get(top_client_id);
CHECK(client_info);
auto bot_info = client_info->client_.get_actor_unsafe()->get_bot_info();
auto active_request_count = client_info->stat_.get_active_request_count();
@ -525,7 +533,7 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, bool
td::vector<td::BufferSlice> containers;
auto add_string = [&containers](td::Slice str) {
containers.emplace_back(str);
return containers.back().as_slice();
return containers.back().as_mutable_slice();
};
token = add_string(token);
@ -631,6 +639,37 @@ void ClientManager::dump_statistics() {
}
td::dump_pending_network_queries(*parameters_->net_query_stats_);
auto now = td::Time::now();
auto top_clients = get_top_clients(10, {});
for (auto top_client_id : top_clients.top_client_ids) {
auto *client_info = clients_.get(top_client_id);
CHECK(client_info);
auto bot_info = client_info->client_.get_actor_unsafe()->get_bot_info();
td::string update_count;
td::string request_count;
auto replace_tabs = [](td::string &str) {
for (auto &c : str) {
if (c == '\t') {
c = ' ';
}
}
};
auto stats = client_info->stat_.as_vector(now);
for (auto &stat : stats) {
if (stat.key_ == "update_count") {
replace_tabs(stat.value_);
update_count = std::move(stat.value_);
}
if (stat.key_ == "request_count") {
replace_tabs(stat.value_);
request_count = std::move(stat.value_);
}
}
LOG(WARNING) << td::tag("id", bot_info.id_) << td::tag("update_count", update_count)
<< td::tag("request_count", request_count);
}
}
void ClientManager::raw_event(const td::Event::Raw &event) {

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -79,13 +79,19 @@ class ClientManager final : public td::Actor {
td::int64 tqueue_deleted_events_ = 0;
td::int64 last_tqueue_deleted_events_ = 0;
static constexpr double WATCHDOG_TIMEOUT = 0.5;
static constexpr double WATCHDOG_TIMEOUT = 0.25;
static td::int64 get_tqueue_id(td::int64 user_id, bool is_test_dc);
static PromisedQueryPtr get_webhook_restore_query(td::Slice token, bool is_user, td::Slice webhook_info,
std::shared_ptr<SharedData> shared_data);
struct TopClients {
td::int32 active_count = 0;
td::vector<td::uint64> top_client_ids;
};
TopClients get_top_clients(std::size_t max_count, td::Slice token_filter);
void start_up() final;
void raw_event(const td::Event::Raw &event) final;
void timeout_expired() final;

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -117,6 +117,8 @@ class Query final : public td::ListNode {
if (!empty()) {
shared_data_->query_list_size_.fetch_sub(1, std::memory_order_relaxed);
}
td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), container_, args_,
headers_, files_, answer_);
}
}

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -123,16 +123,15 @@ class JsonStatsCpu : public td::Jsonable {
class JsonStatsBot : public td::Jsonable {
public:
explicit JsonStatsBot(std::pair<td::int64, td::uint64> score_id_pair) : score_id_pair_(std::move(score_id_pair)) {
explicit JsonStatsBot(td::uint64 client_id) : client_id_(client_id) {
}
void store(td::JsonValueScope *scope) const {
auto object = scope->enter_object();
object("score", td::JsonLong(score_id_pair_.first));
object("internal_id", td::JsonLong(score_id_pair_.second));
object("client_id", td::JsonLong(client_id_));
}
protected:
const std::pair<td::int64, td::uint64> score_id_pair_;
const td::uint64 client_id_;
};
class JsonStatsBotStatDouble : public td::Jsonable {
@ -198,7 +197,7 @@ class JsonStatsBotStats : public td::Jsonable {
class JsonStatsBotAdvanced : public JsonStatsBot {
public:
explicit JsonStatsBotAdvanced(std::pair<td::int64, td::uint64> score_id_pair,
explicit JsonStatsBotAdvanced(td::uint64 client_id,
ServerBotInfo bot,
td::int64 active_request_count,
td::int64 active_file_upload_bytes,
@ -206,7 +205,7 @@ class JsonStatsBotAdvanced : public JsonStatsBot {
td::vector<ServerBotStat> stats,
const bool hide_sensible_data,
const double now)
: JsonStatsBot(std::move(score_id_pair)), bot_(std::move(bot)), active_request_count_(active_request_count),
: JsonStatsBot(client_id), bot_(std::move(bot)), active_request_count_(active_request_count),
active_file_upload_bytes_(active_file_upload_bytes), active_file_upload_count_(active_file_upload_count),
stats_(std::move(stats)), hide_sensible_data_(hide_sensible_data), now_(now) {
}
@ -214,8 +213,7 @@ class JsonStatsBotAdvanced : public JsonStatsBot {
auto object = scope->enter_object();
object("id", td::JsonLong(td::to_integer<td::int64>(bot_.id_)));
object("uptime", now_ - bot_.start_time_);
object("score", td::JsonLong(score_id_pair_.first));
object("internal_id", td::JsonLong(score_id_pair_.second));
object("client_id", td::JsonLong(client_id_));
if (!hide_sensible_data_) {
object("token", td::JsonString(bot_.token_));
}

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -504,7 +504,8 @@ void WebhookActor::on_update_error(td::TQueue::EventId event_id, td::Slice error
int next_delay = update.delay_;
int next_effective_delay = retry_after;
if (retry_after == 0 && update.fail_count_ > 0) {
next_delay = td::min(WEBHOOK_MAX_RESEND_TIMEOUT, next_delay * 2);
auto max_timeout = td::Random::fast(WEBHOOK_MAX_RESEND_TIMEOUT, WEBHOOK_MAX_RESEND_TIMEOUT * 2);
next_delay = td::min(max_timeout, next_delay * 2);
next_effective_delay = next_delay;
}
if (parameters_->shared_data_->get_unix_time(now) + next_effective_delay > update.expires_at_) {
@ -589,6 +590,11 @@ void WebhookActor::send_updates() {
}
void WebhookActor::handle(td::unique_ptr<td::HttpQuery> response) {
SCOPE_EXIT {
bool dummy = false;
td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), response, dummy);
};
auto connection_id = get_link_token();
if (response) {
VLOG(webhook) << "Got response from connection " << connection_id;
@ -686,7 +692,7 @@ void WebhookActor::start_up() {
next_ip_address_resolve_time_ = last_success_time_ = td::Time::now() - 3600;
active_new_connection_flood_.add_limit(1, 20);
active_new_connection_flood_.add_limit(0.5, 10);
pending_new_connection_flood_.add_limit(2, 1);

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@ -1,5 +1,5 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -165,7 +165,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.4.1";
parameters->version_ = "6.5";
parameters->shared_data_ = shared_data;
parameters->start_time_ = start_time;
auto net_query_stats = td::create_net_query_stats();
@ -304,7 +304,7 @@ int main(int argc, char *argv[]) {
options.add_checked_option('\0', "file-expiration-time",
PSLICE() << "downloaded files expire after this amount of seconds of not being used (defaults to " << parameters->file_expiration_timeout_seconds_ << ")",
td::OptionParser::parse_integer(parameters->file_expiration_timeout_seconds_));
options.add_checked_option('\0', "proxy",
"HTTP proxy server for outgoing webhook requests in the format http://host:port",
[&](td::Slice address) {
@ -474,7 +474,7 @@ int main(int argc, char *argv[]) {
// LOG(WARNING) << "Bot API server with commit " << td::GitInfo::commit() << ' '
// << (td::GitInfo::is_dirty() ? "(dirty)" : "") << " started";
LOG(WARNING) << "Bot API " << parameters->version_ << " server started";
LOG(WARNING) << "TDLight Bot API " << parameters->version_ << " server started";
// +3 threads for Td
// one thread for ClientManager and all Clients
@ -514,7 +514,7 @@ int main(int argc, char *argv[]) {
.release();
}
constexpr double WATCHDOG_TIMEOUT = 0.5;
constexpr double WATCHDOG_TIMEOUT = 0.25;
auto watchdog_id =
sched.create_actor_unsafe<Watchdog>(thread_count - 2, "Watchdog", td::this_thread::get_id(), WATCHDOG_TIMEOUT);