Compare commits

...

97 Commits

Author SHA1 Message Date
Andrea Cavalli 6f785fd26b Fix crash 2024-02-16 15:24:05 +01:00
Andrea Cavalli 0bc23e3830 Add custom deleteMessages implementation 2024-02-11 12:55:43 +01:00
Andrea Cavalli dd075ae89f Add custom deleteMessages implementation 2024-02-11 12:53:28 +01:00
Andrea Cavalli faa723716f Fix compiler warnings 2024-02-11 12:26:52 +01:00
Andrea Cavalli ffcc85392c
Merge pull request #85 from davidgfnet/master
Rebase/merge upstream @ version 7.0
2024-02-11 12:16:02 +01:00
David Guillen Fandos d2415a9191 Update and rebase to version 7.0
Fix a bunch of small issues here and there related to new API calls.
Custom DeleteMessages (bulk) has been deleted in favour of the upstream
implementation that allows deleting a list of messages (instead of a
range).

Documentation might need a redo :)
2024-02-03 12:34:51 +01:00
levlam 1bf69f7abb Update version to 7.0. 2024-02-03 11:45:30 +01:00
levlam a38d9260af Add Message.users_shared field. 2024-02-03 11:45:30 +01:00
levlam baa0546c31 Support request_users.max_quantity. 2024-02-03 11:45:30 +01:00
David Guillen Fandos d3300e9ba3 Rebase: Support channel emoji status. 2024-02-03 11:45:24 +01:00
levlam f19e58645e Add setMessageReaction method. 2024-02-03 11:43:56 +01:00
levlam 50bb07bc46 Add "message_reaction_count" update. 2024-02-03 11:43:56 +01:00
levlam 668ea399eb Add "message_reaction" updates. 2024-02-03 11:43:56 +01:00
levlam fa489a4979 Add Message.giveaway_winners. 2024-02-03 11:43:56 +01:00
levlam 9aedc15f76 Add "has_public_winners" and "prize_description" giveaway fields. 2024-02-03 11:43:56 +01:00
levlam 7575257ca6 Add fields chat.profile_accent_color_id and chat.profile_background_custom_emoji_id. 2024-02-03 11:43:55 +01:00
levlam 7d84c0a0d8 Update TDLib to 1.8.23. 2024-02-03 11:43:55 +01:00
levlam 92b7a6a556 Add Chat.available_reactions. 2024-02-03 11:43:55 +01:00
levlam 81b2c0e550 Add copyMessages method. 2024-02-03 11:43:55 +01:00
levlam 9c1ecb749b Add forwardMessages method. 2024-02-03 11:43:55 +01:00
levlam ce1474d5ab Add deleteMessages method. 2024-02-03 11:43:55 +01:00
levlam 3161f9a00b Store identifier of inaccessible pinned message. 2024-02-03 11:43:55 +01:00
levlam e6e6cbc72f Add Message.giveaway_completed. 2024-02-03 11:43:55 +01:00
levlam 253d3acddc Support quote position in reply parameters. 2024-02-03 11:43:55 +01:00
levlam 5dce30bc20 Add class TextQuote. 2024-02-03 11:43:55 +01:00
levlam aa0f369132 Update TDLib to 1.8.22. 2024-02-03 11:43:55 +01:00
levlam de0d0ad75d Support chat in ReplyParameters. 2024-02-03 11:43:55 +01:00
David Guillen Fandos 94bfd307f8 Rebase: Support quote in ReplyParameters. 2024-02-03 11:43:50 +01:00
levlam 19a7da41b2 Improve error message. 2024-02-03 11:42:10 +01:00
David Guillen Fandos e117cfa33f Rebase: Add class ReplyParameters and fields "reply_parameters". 2024-02-03 11:42:02 +01:00
David Guillen Fandos 1084ebd5c8 Rebase: Add Client::check_reply_parameters. 2024-02-03 11:37:40 +01:00
David Guillen Fandos 49df33acd7 Rebase: Simplify JsonChat usage. 2024-02-03 11:28:37 +01:00
levlam 4b13a450ae Add Message.quote and Message.quote_entities. 2024-02-03 11:24:11 +01:00
levlam ab0f7878bb Add Message.external_reply. 2024-02-03 11:24:11 +01:00
levlam a7f7cd0a7d Add Message.forward_origin. 2024-02-03 11:24:11 +01:00
levlam 05d9cd05b7 Store td_api::MessageOrigin in MessageInfo. 2024-02-03 11:24:11 +01:00
levlam c3999a2144 Add message.link_preview_options. 2024-02-03 11:24:11 +01:00
levlam ad84bfc214 Allow to specify link preview options for sent text messages. 2024-02-03 11:24:11 +01:00
levlam 34f9b8a860 Add getUserChatBoosts. 2024-02-03 11:24:11 +01:00
David Guillen Fandos 121e2d8a18 Rebase: Add "chat_boost" and "removed_chat_boost" updates. 2024-02-03 11:23:59 +01:00
levlam d02a9fe5c3 Add Chat.background_custom_emoji_id. 2024-02-03 11:21:08 +01:00
levlam a2a226ac42 Add Chat.accent_color_id. 2024-02-03 11:21:08 +01:00
levlam 0da8d14430 Add Chat.has_visible_history. 2024-02-03 11:21:08 +01:00
David Guillen Fandos d7d127430f Rebase: Simplify update*FullInfo handling. 2024-02-03 11:21:00 +01:00
levlam c57bb6830b Add Message.giveaway. 2024-02-03 11:17:36 +01:00
levlam 80406b7028 Add Message.giveaway_created. 2024-02-03 11:17:36 +01:00
levlam 8fe04fc33a Support td_api::textEntityTypeBlockQuote. 2024-02-03 11:17:36 +01:00
levlam 1a34273163 Add Client::get_same_chat_reply_to_message_id(const MessageInfo *message_info). 2024-02-03 11:17:36 +01:00
Andrea Cavalli 8990b79e9e
Merge pull request #84 from a5r0n/official-upstream-update
Official upstream update
2023-12-17 19:49:10 +01:00
a5r0n a35ff4543b
fix merge conflicts 2023-12-16 22:29:04 +02:00
Andrea Cavalli b3eb1acc91
Merge pull request #83 from a5r0n/fix/no-file-limit
fix no_file_limit typo
2023-12-16 20:58:44 +01:00
a5r0n c24c0a2dae
Merge remote-tracking branch 'official-upstream/master' into official-upstream-update 2023-12-15 15:16:35 +02:00
a5r0n bf66a41987
fix: fix no_file_limit typo 2023-12-15 11:58:46 +02:00
levlam 96d0d1c668 Update version to 6.9.2. 2023-11-09 02:32:21 +03:00
levlam 0566e21f93 Keep reply to the top thread message for external replies. 2023-11-05 22:08:06 +03:00
levlam 34ed6c3512 Store td_api::messageReplyToMessage in MessageInfo. 2023-11-05 21:54:58 +03:00
levlam 9447ce07ea Minor improvements. 2023-11-04 02:39:57 +03:00
levlam f169ae654c Slowly recheck webhook IP addresses after loading them from database. 2023-11-01 23:01:08 +03:00
levlam 9a7a293a84 Update TDLib to 1.8.21. 2023-10-31 03:10:35 +03:00
levlam d836f78e41 Log skipped updates. 2023-10-23 11:53:20 +03:00
levlam f15bc7396e Update TDLib to 1.8.20. 2023-10-13 01:15:42 +03:00
levlam 9c413c7f11 Maintain last time when a file was uploaded for all requests. 2023-09-25 19:39:51 +03:00
levlam 5d88023dd1 Update TDLib and version to 6.9.1. 2023-09-23 16:39:14 +03:00
levlam 9e7b09ff0a Update version to 6.9. 2023-09-22 16:23:26 +03:00
levlam d5783a1545 Add more fields to WriteAccessAllowed. 2023-09-19 20:37:10 +03:00
levlam 2b43e08dca Support "can_post_stories", "can_edit_stories" and "can_delete_stories" administrator rights. 2023-09-19 19:37:24 +03:00
levlam 11d19baa2e Update TDLib to 1.8.19. 2023-09-19 19:26:43 +03:00
levlam df1fe4c05f Fail request early if message/caption/explanation text is too long. 2023-09-14 19:11:12 +03:00
levlam 1ec733a3f8 Don't update CPU statistics before returning it to avoid synchronous open of "/proc/stat". 2023-09-14 16:57:28 +03:00
levlam 4e8ba65838 Update TDLib to 1.8.18. 2023-09-13 23:14:57 +03:00
levlam e58e8d3989 Improve query logging. 2023-09-08 18:09:08 +03:00
levlam 95ff757c73 Immediately return an error if more than 50 inline query results are provided. 2023-09-06 18:48:41 +03:00
levlam 70670d7217 Explicitly disallow message updates with "channel_chat_created" content. 2023-09-06 17:06:21 +03:00
levlam 87cdeaadb6 Update TDLib to 1.8.17. 2023-09-06 16:17:47 +03:00
levlam 18b5f287f7 Update CPU statistics on a dedicated thread. 2023-09-03 01:03:53 +03:00
levlam 1cab23c1f1 Improve ServerCpuStat. 2023-09-03 00:55:10 +03:00
levlam 89383695ed Make watchdog timeouts more precise. 2023-08-31 22:51:07 +03:00
levlam 8b2b62bd6f Update version to 6.8. 2023-08-18 18:39:30 +03:00
levlam 375b5d1b7c Update TDLib to 1.8.16. 2023-08-17 00:34:34 +03:00
levlam 980f98299f Improve logging of big queries. 2023-08-08 18:00:24 +03:00
levlam 0868ee6beb Simplify reply markup parsing. 2023-07-31 20:01:53 +03:00
levlam a78edf0703 Use JsonObject member functions to get field values. 2023-07-31 17:53:56 +03:00
levlam 2bbaf87fea Use get_json_object_long_field to fetch "amount". 2023-07-31 14:02:50 +03:00
levlam 9f688af4fb Add dedicated threads for TQueue and webhook databases and webhook certificate processing. 2023-07-25 22:32:05 +03:00
levlam c927614964 Improve threads usage. 2023-07-25 22:26:12 +03:00
levlam ec8e44de5a Improve warnings for old updates. 2023-07-24 21:41:15 +03:00
levlam f4422f5976 Add unpinAllGeneralForumTopicMessages. 2023-07-24 17:19:14 +03:00
levlam afd30f2cfa Support messageStory as empty objects. 2023-07-24 16:14:03 +03:00
levlam 51fba26f78 Add Chat.emoji_status_expiration_date. 2023-07-21 13:33:00 +03:00
levlam 736411c113 Update TDLib to 1.8.15 and support votes by chats in polls. 2023-07-20 17:06:32 +03:00
levlam 1fa5c2c31a Improve processing of new messages. 2023-07-20 16:58:10 +03:00
levlam 9ce2f7df4c Don't drop replies to deleted messages. 2023-07-20 16:30:46 +03:00
levlam 68dc4f54a5 Don't track replies by yet unsent messages. 2023-07-20 16:25:42 +03:00
levlam c8e50b8011 Improve replies handling. 2023-07-19 23:54:47 +03:00
levlam a9a0140476 Keep last time when a file was uploaded. 2023-07-06 14:47:31 +03:00
levlam 84e512c2e4 Make Client::get_reply_markup static. 2023-07-06 14:01:14 +03:00
levlam d9c00c452b Use bot identifier as token for webhook requests. 2023-06-28 20:55:38 +03:00
16 changed files with 2507 additions and 1152 deletions

View File

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

View File

@ -54,17 +54,6 @@ Get the member list of a supergroup or channel
###### Returns `ChatMember`
##### Method `deleteMessages`
Delete all the messages with message_id in range between `start` and `end`.
The `start` parameter MUST be less than the `end` parameter
Both `start` and `end` must be positive non zero numbers
The method will always return `true` as a result, even if the messages cannot be deleted
This method does not work on private chat or normal groups
It is not suggested to delete more than 200 messages per call
**NOTE**
The maximum number of messages to be deleted in a single batch is determined by the `max-batch-operations` parameter and is 10000 by default
###### Parameters
- `chat_id` Chat id
- `start` First message id to delete
@ -122,6 +111,17 @@ _For Docker containers, `$TELEGRAM_VERBOSITY` can be set._
##### Method `getChat`
The command `getChat` will also try to resolve the username online, if it can't be found locally
##### Method `deleteMessages`
The command `deleteMessages` can also delete all the messages with message_id in range between `start` and `end`.
The `start` parameter MUST be less than the `end` parameter
Both `start` and `end` must be positive non-zero numbers
The method will always return `true` as a result, even if the messages cannot be deleted
This method does not work on private chat or normal groups
It is not suggested to delete more than 200 messages per call
**NOTE**
The maximum number of messages to be deleted in a single batch is determined by the `max-batch-operations` parameter and is 10000 by default
##### Object `Message`
The `Message` object now has two new fields:
- `views`: how many views has the message (usually the views are shown only for channel messages)

2
td

@ -1 +1 @@
Subproject commit 328b8649d859c5ed4088a875cbb059db6029dc0d
Subproject commit 27c3eaeb4964bd5f18d8488e354abde1a4383e49

View File

@ -547,16 +547,23 @@ paths:
/deleteMessages:
post:
tags:
- added
- modified
description: |-
Delete all the messages with message_id in range between start and end.
The start parameter MUST be less than the end parameter
Both start and end must be positive non zero numbers
The method will always return true as a result, even if the messages cannot be deleted
This method does not work on private chat or normal groups It is not suggested to delete more than 200 messages per call.
Use this method to delete multiple messages simultaneously.
This method can delete a set of message ids, or a range of message ids.
If you specify "message_ids", this method tries to delete the specified set of ids:
If some of the specified messages can't be found, they are skipped.
Returns True on success.
*NOTE*
The maximum number of messages to be deleted in a single batch is determined by the max-batch-operations parameter and is 10000 by default.
If you specify "start" and "end", this method deletes all the messages with message_id in range between start and end:
The start parameter MUST be less than the end parameter
Both start and end must be positive non zero numbers
The method will always return true as a result, even if the messages cannot be deleted
This method does not work on private chat or normal groups It is not suggested to delete more than 200 messages per call.
*NOTE*
The maximum number of messages to be deleted in a single batch is determined by the max-batch-operations parameter and is 10000 by default.
requestBody:
content:
application/x-www-form-urlencoded:
@ -568,6 +575,10 @@ paths:
anyOf:
- type: integer
- type: string
message_ids:
type: array
items:
type: integer
start:
description: First message id to delete
type: integer
@ -576,8 +587,6 @@ paths:
type: integer
required:
- chat_id
- start
- end
multipart/form-data:
schema:
type: object
@ -587,6 +596,10 @@ paths:
anyOf:
- type: integer
- type: string
message_ids:
type: array
items:
type: integer
start:
description: First message id to delete
type: integer
@ -595,8 +608,6 @@ paths:
type: integer
required:
- chat_id
- start
- end
application/json:
schema:
type: object
@ -606,6 +617,10 @@ paths:
anyOf:
- type: integer
- type: string
message_ids:
type: array
items:
type: integer
start:
description: First message id to delete
type: integer
@ -614,12 +629,10 @@ paths:
type: integer
required:
- chat_id
- start
- end
required: true
responses:
'200':
description: ''
description: 'Request was successful, the result is returned.'
content:
application/json:
schema:

File diff suppressed because it is too large Load Diff

View File

@ -70,7 +70,7 @@ class Client final : 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 = 250; // some unreasonably big value
static constexpr int32 MAX_CONCURRENTLY_SENT_CHAT_MESSAGES = 310; // some unreasonably big value
static constexpr std::size_t MIN_PENDING_UPDATES_WARNING = 200;
@ -104,12 +104,18 @@ class Client final : public WebhookActor::Callback {
class JsonDatedFiles;
class JsonUser;
class JsonUsers;
class JsonReactionType;
class JsonReactionCount;
class JsonChatPermissions;
class JsonChatPhotoInfo;
class JsonChatLocation;
class JsonChatInviteLink;
class JsonChat;
class JsonMessageSender;
class JsonMessageOrigin;
class JsonExternalReplyInfo;
class JsonTextQuote;
class JsonLinkPreviewOptions;
class JsonAnimation;
class JsonAudio;
class JsonDocument;
@ -140,7 +146,7 @@ class Client final : public WebhookActor::Callback {
class JsonReplyMarkup;
class JsonMessage;
class JsonMessages;
class JsonDeletedMessage;
class JsonInaccessibleMessage;
class JsonMessageId;
class JsonInlineQuery;
class JsonChosenInlineResult;
@ -159,10 +165,17 @@ class Client final : public WebhookActor::Callback {
class JsonChatMembers;
class JsonChatMemberUpdated;
class JsonChatJoinRequest;
class JsonChatBoostSource;
class JsonChatBoost;
class JsonChatBoostUpdated;
class JsonChatBoostRemoved;
class JsonChatBoosts;
class JsonForumTopicCreated;
class JsonForumTopicEdited;
class JsonForumTopicInfo;
class JsonGameHighScore;
class JsonMessageReactionUpdated;
class JsonMessageReactionCountUpdated;
class JsonAddress;
class JsonOrderInfo;
class JsonSuccessfulPaymentBot;
@ -177,7 +190,11 @@ class Client final : public WebhookActor::Callback {
class JsonChatSetMessageAutoDeleteTime;
class JsonWriteAccessAllowed;
class JsonUserShared;
class JsonUsersShared;
class JsonChatShared;
class JsonGiveaway;
class JsonGiveawayWinners;
class JsonGiveawayCompleted;
class JsonUpdateTypes;
class JsonWebhookInfo;
class JsonStickerSet;
@ -202,6 +219,7 @@ class Client final : public WebhookActor::Callback {
class TdOnGetUserProfilePhotosCallback;
class TdOnSendMessageCallback;
class TdOnSendMessageAlbumCallback;
class TdOnForwardMessagesCallback;
class TdOnDeleteFailedToSendMessageCallback;
class TdOnEditMessageCallback;
class TdOnEditInlineMessageCallback;
@ -224,7 +242,8 @@ class Client final : public WebhookActor::Callback {
class TdOnGetChatPinnedMessageToUnpinCallback;
class TdOnGetGroupMembersCallback;
class TdOnGetSupergroupMembersCallback;
class TdOnGetSupergroupMembersCountCallback;
class TdOnGetSupergroupMemberCountCallback;
class TdOnGetUserChatBoostsCallback;
class TdOnCreateInvoiceLinkCallback;
class TdOnReplacePrimaryChatInviteLinkCallback;
class TdOnGetChatInviteLinkCallback;
@ -274,9 +293,23 @@ class Client final : public WebhookActor::Callback {
virtual ~TdQueryCallback() = default;
};
struct InputReplyParameters {
td::string reply_in_chat_id;
int64 reply_to_message_id = 0;
bool allow_sending_without_reply = false;
object_ptr<td_api::inputTextQuote> quote;
};
struct CheckedReplyParameters {
int64 reply_in_chat_id = 0;
int64 reply_to_message_id = 0;
object_ptr<td_api::inputTextQuote> quote;
};
struct UserInfo;
struct ChatInfo;
struct BotCommandScope;
struct BotUserIds;
enum class AccessRights { Read, ReadMembers, Edit, Write };
@ -297,6 +330,8 @@ class Client final : public WebhookActor::Callback {
template <class OnSuccess>
class TdOnCheckMessageCallback;
template <class OnSuccess>
class TdOnCheckMessagesCallback;
template <class OnSuccess>
class TdOnCheckMessageThreadCallback;
template <class OnSuccess>
class TdOnCheckRemoteFileIdCallback;
@ -338,8 +373,12 @@ class Client final : public WebhookActor::Callback {
td::Slice message_type, PromisedQueryPtr query, OnSuccess on_success);
template <class OnSuccess>
void check_message_thread(int64 chat_id, int64 message_thread_id, int64 reply_to_message_id, PromisedQueryPtr query,
OnSuccess on_success);
void check_messages(td::Slice chat_id_str, td::vector<int64> message_ids, bool allow_empty,
AccessRights access_rights, td::Slice message_type, PromisedQueryPtr query, OnSuccess on_success);
template <class OnSuccess>
void check_reply_parameters(td::Slice chat_id_str, InputReplyParameters &&reply_parameters, int64 message_thread_id,
PromisedQueryPtr query, OnSuccess on_success);
template <class OnSuccess>
void resolve_sticker_set(const td::string &sticker_set_name, PromisedQueryPtr query, OnSuccess on_success);
@ -375,13 +414,20 @@ class Client final : public WebhookActor::Callback {
static bool to_bool(td::MutableSlice value);
static object_ptr<td_api::InputMessageReplyTo> get_input_message_reply_to(CheckedReplyParameters &&reply_parameters);
static td::Result<InputReplyParameters> get_reply_parameters(const Query *query);
static td::Result<InputReplyParameters> get_reply_parameters(td::JsonValue &&value);
static td::Result<object_ptr<td_api::keyboardButton>> get_keyboard_button(td::JsonValue &button);
td::Result<object_ptr<td_api::inlineKeyboardButton>> get_inline_keyboard_button(td::JsonValue &button);
static td::Result<object_ptr<td_api::inlineKeyboardButton>> get_inline_keyboard_button(td::JsonValue &button,
BotUserIds &bot_user_ids);
td::Result<object_ptr<td_api::ReplyMarkup>> get_reply_markup(const Query *query);
static td::Result<object_ptr<td_api::ReplyMarkup>> get_reply_markup(const Query *query, BotUserIds &bot_user_ids);
td::Result<object_ptr<td_api::ReplyMarkup>> get_reply_markup(td::JsonValue &&value);
static td::Result<object_ptr<td_api::ReplyMarkup>> get_reply_markup(td::JsonValue &&value, BotUserIds &bot_user_ids);
static td::Result<object_ptr<td_api::labeledPricePart>> get_labeled_price_part(td::JsonValue &value);
@ -415,13 +461,17 @@ class Client final : public WebhookActor::Callback {
static td::Result<td_api::object_ptr<td_api::inlineQueryResultsButton>> get_inline_query_results_button(
td::MutableSlice value);
td::Result<object_ptr<td_api::InputInlineQueryResult>> get_inline_query_result(const Query *query);
static td::Result<object_ptr<td_api::InputInlineQueryResult>> get_inline_query_result(const Query *query,
BotUserIds &bot_user_ids);
td::Result<object_ptr<td_api::InputInlineQueryResult>> get_inline_query_result(td::JsonValue &&value);
static td::Result<object_ptr<td_api::InputInlineQueryResult>> get_inline_query_result(td::JsonValue &&value,
BotUserIds &bot_user_ids);
td::Result<td::vector<object_ptr<td_api::InputInlineQueryResult>>> get_inline_query_results(const Query *query);
static td::Result<td::vector<object_ptr<td_api::InputInlineQueryResult>>> get_inline_query_results(
const Query *query, BotUserIds &bot_user_ids);
td::Result<td::vector<object_ptr<td_api::InputInlineQueryResult>>> get_inline_query_results(td::JsonValue &&value);
static td::Result<td::vector<object_ptr<td_api::InputInlineQueryResult>>> get_inline_query_results(
td::JsonValue &&value, BotUserIds &bot_user_ids);
struct BotCommandScope {
object_ptr<td_api::BotCommandScope> scope_;
@ -494,12 +544,17 @@ class Client final : public WebhookActor::Callback {
static td::Result<object_ptr<td_api::formattedText>> get_formatted_text(td::string text, td::string parse_mode,
td::JsonValue &&input_entities);
static object_ptr<td_api::linkPreviewOptions> get_link_preview_options(bool disable_web_page_preview);
static td::Result<object_ptr<td_api::linkPreviewOptions>> get_link_preview_options(const Query *query);
static td::Result<object_ptr<td_api::linkPreviewOptions>> get_link_preview_options(td::JsonValue &&value);
static td::Result<object_ptr<td_api::inputMessageText>> get_input_message_text(const Query *query);
static td::Result<object_ptr<td_api::inputMessageText>> get_input_message_text(td::string text,
bool disable_web_page_preview,
td::string parse_mode,
td::JsonValue &&input_entities);
static td::Result<object_ptr<td_api::inputMessageText>> get_input_message_text(
td::string text, object_ptr<td_api::linkPreviewOptions> link_preview_options, td::string parse_mode,
td::JsonValue &&input_entities);
static td::Result<object_ptr<td_api::location>> get_location(const Query *query);
@ -525,6 +580,10 @@ class Client final : public WebhookActor::Callback {
static td::Result<td::vector<td::string>> get_poll_options(const Query *query);
static td::Result<object_ptr<td_api::ReactionType>> get_reaction_type(td::JsonValue &&value);
static td::Result<td::vector<object_ptr<td_api::ReactionType>>> get_reaction_types(const Query *query);
static int32 get_integer_arg(const Query *query, td::Slice field_name, int32 default_value,
int32 min_value = std::numeric_limits<int32>::min(),
int32 max_value = std::numeric_limits<int32>::max());
@ -533,6 +592,9 @@ class Client final : public WebhookActor::Callback {
static int64 get_message_id(const Query *query, td::Slice field_name = td::Slice("message_id"));
static td::Result<td::vector<int64>> get_message_ids(const Query *query, size_t max_count,
td::Slice field_name = td::Slice("message_ids"));
static td::Result<td::Slice> get_inline_message_id(const Query *query,
td::Slice field_name = td::Slice("inline_message_id"));
@ -540,7 +602,7 @@ class Client final : public WebhookActor::Callback {
void decrease_yet_unsent_message_count(int64 chat_id, int32 count);
int64 extract_yet_unsent_message_query_id(int64 chat_id, int64 message_id, bool *is_reply_to_message_deleted);
int64 extract_yet_unsent_message_query_id(int64 chat_id, int64 message_id);
// start custom helper methods
@ -552,7 +614,7 @@ class Client final : public WebhookActor::Callback {
static int64 get_int64_arg(const Query *query, td::Slice field_name, int64 default_value,
int64 min_value = std::numeric_limits<int64>::min(),
int64 max_value = std::numeric_limits<int64>::max());
static td::Result<td_api::object_ptr<td_api::ChatReportReason>> get_report_reason(const Query *query,
static td::Result<td_api::object_ptr<td_api::ReportReason>> get_report_reason(const Query *query,
td::Slice field_name = td::Slice("reason"));
static td::Result<td_api::object_ptr<td_api::SearchMessagesFilter>> get_search_messages_filter(
@ -561,13 +623,15 @@ class Client final : public WebhookActor::Callback {
// end custom helper methods
void on_message_send_succeeded(object_ptr<td_api::message> &&message, int64 old_message_id);
void on_message_send_failed(int64 chat_id, int64 old_message_id, int64 new_message_id, td::Status result);
void on_message_send_failed(int64 chat_id, int64 old_message_id, int64 new_message_id,
object_ptr<td_api::error> &&error);
static bool init_methods();
static bool is_local_method(td::Slice method);
void on_cmd(PromisedQueryPtr query);
void on_cmd(PromisedQueryPtr query, bool force = false);
td::Status process_get_me_query(PromisedQueryPtr &query);
td::Status process_get_my_commands_query(PromisedQueryPtr &query);
@ -602,15 +666,19 @@ class Client final : public WebhookActor::Callback {
td::Status process_send_poll_query(PromisedQueryPtr &query);
td::Status process_stop_poll_query(PromisedQueryPtr &query);
td::Status process_copy_message_query(PromisedQueryPtr &query);
td::Status process_copy_messages_query(PromisedQueryPtr &query);
td::Status process_forward_message_query(PromisedQueryPtr &query);
td::Status process_forward_messages_query(PromisedQueryPtr &query);
td::Status process_send_media_group_query(PromisedQueryPtr &query);
td::Status process_send_chat_action_query(PromisedQueryPtr &query);
td::Status process_set_message_reaction_query(PromisedQueryPtr &query);
td::Status process_edit_message_text_query(PromisedQueryPtr &query);
td::Status process_edit_message_live_location_query(PromisedQueryPtr &query);
td::Status process_edit_message_media_query(PromisedQueryPtr &query);
td::Status process_edit_message_caption_query(PromisedQueryPtr &query);
td::Status process_edit_message_reply_markup_query(PromisedQueryPtr &query);
td::Status process_delete_message_query(PromisedQueryPtr &query);
td::Status process_delete_messages_query(PromisedQueryPtr &query);
td::Status process_create_invoice_link_query(PromisedQueryPtr &query);
td::Status process_set_game_score_query(PromisedQueryPtr &query);
td::Status process_get_game_high_scores_query(PromisedQueryPtr &query);
@ -646,6 +714,7 @@ class Client final : public WebhookActor::Callback {
td::Status process_reopen_general_forum_topic_query(PromisedQueryPtr &query);
td::Status process_hide_general_forum_topic_query(PromisedQueryPtr &query);
td::Status process_unhide_general_forum_topic_query(PromisedQueryPtr &query);
td::Status process_unpin_all_general_forum_topic_messages_query(PromisedQueryPtr &query);
td::Status process_get_chat_member_query(PromisedQueryPtr &query);
td::Status process_get_chat_administrators_query(PromisedQueryPtr &query);
td::Status process_get_chat_member_count_query(PromisedQueryPtr &query);
@ -659,6 +728,7 @@ class Client final : public WebhookActor::Callback {
td::Status process_unban_chat_sender_chat_query(PromisedQueryPtr &query);
td::Status process_approve_chat_join_request_query(PromisedQueryPtr &query);
td::Status process_decline_chat_join_request_query(PromisedQueryPtr &query);
td::Status process_get_user_chat_boosts_query(PromisedQueryPtr &query);
td::Status process_get_sticker_set_query(PromisedQueryPtr &query);
td::Status process_get_custom_emoji_stickers_query(PromisedQueryPtr &query);
td::Status process_upload_sticker_file_query(PromisedQueryPtr &query);
@ -684,7 +754,6 @@ class Client final : public WebhookActor::Callback {
//custom methods
td::Status process_get_message_info_query(PromisedQueryPtr &query);
td::Status process_get_chat_members_query(PromisedQueryPtr &query);
td::Status process_delete_messages_query(PromisedQueryPtr &query);
td::Status process_toggle_group_invites_query(PromisedQueryPtr &query);
td::Status process_ping_query(PromisedQueryPtr &query);
td::Status process_get_memory_stats_query(PromisedQueryPtr &query);
@ -693,6 +762,7 @@ class Client final : public WebhookActor::Callback {
td::Status process_delete_proxy_query(PromisedQueryPtr &query);
td::Status process_enable_proxy_query(PromisedQueryPtr &query);
td::Status process_disable_proxy_query(PromisedQueryPtr &query);
td::Status process_delete_messages_range_query(PromisedQueryPtr &query);
//custom user methods
td::Status process_get_chats_query(PromisedQueryPtr &query);
@ -735,7 +805,10 @@ class Client final : public WebhookActor::Callback {
void on_webhook_closed(td::Status status);
void do_send_message(object_ptr<td_api::InputMessageContent> input_message_content, PromisedQueryPtr query);
void delete_last_send_message_time(td::int64 file_size, double max_delay);
void do_send_message(object_ptr<td_api::InputMessageContent> input_message_content, PromisedQueryPtr query,
bool force = false);
int64 get_send_message_query_id(PromisedQueryPtr query, bool is_multisend);
@ -799,7 +872,6 @@ class Client final : public WebhookActor::Callback {
td::vector<td::string> active_usernames;
td::string editable_username;
td::string language_code;
int64 emoji_status_custom_emoji_id;
object_ptr<td_api::chatPhoto> photo;
td::string bio;
@ -820,16 +892,11 @@ class Client final : public WebhookActor::Callback {
bool added_to_attachment_menu = false;
};
static void add_user(UserInfo *user_info, object_ptr<td_api::user> &&user);
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;
void set_user_status(int64 user_id, object_ptr<td_api::UserStatus> &&status);
struct GroupInfo {
object_ptr<td_api::chatPhoto> photo;
td::string description;
@ -841,9 +908,6 @@ class Client final : public WebhookActor::Callback {
int64 upgraded_to_supergroup_id = 0;
};
static void add_group(GroupInfo *group_info, object_ptr<td_api::basicGroup> &&group);
void set_group_photo(int64 group_id, object_ptr<td_api::chatPhoto> &&photo);
void set_group_description(int64 group_id, td::string &&descripton);
void set_group_invite_link(int64 group_id, td::string &&invite_link);
GroupInfo *add_group_info(int64 group_id);
const GroupInfo *get_group_info(int64 group_id) const;
@ -862,6 +926,7 @@ class Client final : public WebhookActor::Callback {
bool is_supergroup = false;
bool is_forum = false;
bool can_set_sticker_set = false;
bool is_all_history_available = false;
bool has_location = false;
bool join_to_send_messages = false;
bool join_by_request = false;
@ -874,16 +939,6 @@ class Client final : public WebhookActor::Callback {
// end custom properties
};
static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr<td_api::supergroup> &&supergroup);
void set_supergroup_photo(int64 supergroup_id, object_ptr<td_api::chatPhoto> &&photo);
void set_supergroup_description(int64 supergroup_id, td::string &&descripton);
void set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link);
void set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id);
void set_supergroup_can_set_sticker_set(int64 supergroup_id, bool can_set_sticker_set);
void set_supergroup_slow_mode_delay(int64 supergroup_id, int32 slow_mode_delay);
void set_supergroup_linked_chat_id(int64 supergroup_id, int64 linked_chat_id);
void set_supergroup_location(int64 supergroup_id, object_ptr<td_api::chatLocation> location);
void set_supergroup_has_hidden_members(int64 supergroup_id, bool has_hidden_members);
void set_supergroup_has_aggressive_anti_spam_enabled(int64 supergroup_id, bool has_aggressive_anti_spam_enabled);
SupergroupInfo *add_supergroup_info(int64 supergroup_id);
const SupergroupInfo *get_supergroup_info(int64 supergroup_id) const;
@ -892,7 +947,14 @@ class Client final : public WebhookActor::Callback {
Type type = Type::Unknown;
td::string title;
int32 message_auto_delete_time = 0;
int64 emoji_status_custom_emoji_id = 0;
int32 emoji_status_expiration_date = 0;
int32 accent_color_id = -1;
int32 profile_accent_color_id = -1;
int64 background_custom_emoji_id = 0;
int64 profile_background_custom_emoji_id = 0;
bool has_protected_content = false;
object_ptr<td_api::chatAvailableReactionsSome> available_reactions;
object_ptr<td_api::chatPhotoInfo> photo_info;
object_ptr<td_api::chatPermissions> permissions;
union {
@ -918,15 +980,10 @@ class Client final : public WebhookActor::Callback {
int64 message_thread_id = 0;
int32 date = 0;
int32 edit_date = 0;
int64 initial_chat_id = 0;
int64 initial_sender_user_id = 0;
int64 initial_sender_chat_id = 0;
int32 initial_send_date = 0;
int64 initial_message_id = 0;
td::string initial_author_signature;
td::string initial_sender_name;
object_ptr<td_api::MessageOrigin> forward_origin;
td::string author_signature;
int64 reply_to_message_id = 0;
object_ptr<td_api::messageReplyToMessage> reply_to_message;
int64 media_album_id = 0;
int64 via_bot_user_id = 0;
object_ptr<td_api::MessageContent> content;
@ -943,13 +1000,20 @@ class Client final : public WebhookActor::Callback {
bool can_be_saved = false;
bool is_automatic_forward = false;
bool is_topic_message = false;
mutable bool is_reply_to_message_deleted = false;
mutable bool is_content_changed = false;
};
static int64 &get_reply_to_message_id(object_ptr<td_api::message> &message);
static int64 get_same_chat_reply_to_message_id(const td_api::messageReplyToMessage *reply_to,
int64 message_thread_id);
void set_message_reply_to_message_id(MessageInfo *message_info, int64 reply_to_message_id);
static int64 get_same_chat_reply_to_message_id(const object_ptr<td_api::MessageReplyTo> &reply_to,
int64 message_thread_id);
static int64 get_same_chat_reply_to_message_id(const object_ptr<td_api::message> &message);
static int64 get_same_chat_reply_to_message_id(const MessageInfo *message_info);
static void drop_internal_reply_to_message_in_another_chat(object_ptr<td_api::message> &message);
static td::Slice get_sticker_type(const object_ptr<td_api::StickerType> &type);
@ -1034,6 +1098,8 @@ class Client final : public WebhookActor::Callback {
static int32 as_scheduled_message_id(int64 message_id);
static int32 as_client_message_id_unchecked(int64 message_id);
static int64 get_supergroup_chat_id(int64 supergroup_id);
static int64 get_basic_group_chat_id(int64 basic_group_id);
@ -1067,6 +1133,12 @@ class Client final : public WebhookActor::Callback {
void add_update_chat_join_request(object_ptr<td_api::updateNewChatJoinRequest> &&update);
void add_update_chat_boost(object_ptr<td_api::updateChatBoost> &&update);
void add_update_message_reaction(object_ptr<td_api::updateMessageReaction> &&update);
void add_update_message_reaction_count(object_ptr<td_api::updateMessageReactions> &&update);
// append only before Size
enum class UpdateType : int32 {
Message,
@ -1085,6 +1157,10 @@ class Client final : public WebhookActor::Callback {
MyChatMember,
ChatMember,
ChatJoinRequest,
ChatBoostUpdated,
ChatBoostRemoved,
MessageReaction,
MessageReactionCount,
Size
};
@ -1114,9 +1190,11 @@ class Client final : public WebhookActor::Callback {
bool have_message_access(int64 chat_id) const;
// by default ChatMember updates are disabled
// by default ChatMember, MessageReaction, and MessageReactionCount updates are disabled
static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES =
(1 << static_cast<int32>(UpdateType::Size)) - 1 - (1 << static_cast<int32>(UpdateType::ChatMember));
(1 << static_cast<int32>(UpdateType::Size)) - 1 - (1 << static_cast<int32>(UpdateType::ChatMember)) -
(1 << static_cast<int32>(UpdateType::MessageReaction)) -
(1 << static_cast<int32>(UpdateType::MessageReactionCount));
object_ptr<td_api::AuthorizationState> authorization_state_;
bool was_authorized_ = false;
@ -1155,17 +1233,10 @@ class Client final : public WebhookActor::Callback {
td::WaitFreeHashMap<int64, td::unique_ptr<SupergroupInfo>> supergroups_;
td::WaitFreeHashMap<int64, td::unique_ptr<ChatInfo>> chats_;
td::FlatHashMap<FullMessageId, td::FlatHashSet<int64>, FullMessageIdHash>
reply_message_ids_; // message -> replies to it
td::FlatHashMap<FullMessageId, td::FlatHashSet<int64>, FullMessageIdHash>
yet_unsent_reply_message_ids_; // message -> replies to it
td::FlatHashMap<int32, td::vector<PromisedQueryPtr>> file_download_listeners_;
td::FlatHashSet<int32> download_started_file_ids_;
struct YetUnsentMessage {
int64 reply_to_message_id = 0;
bool is_reply_to_message_deleted = false;
int64 send_message_query_id = 0;
};
td::FlatHashMap<FullMessageId, YetUnsentMessage, FullMessageIdHash> yet_unsent_messages_;
@ -1206,11 +1277,15 @@ class Client final : public WebhookActor::Callback {
td::WaitFreeHashMap<int64, td::string> sticker_set_names_;
int64 cur_temp_bot_user_id_ = 1;
td::FlatHashMap<td::string, int64> bot_user_ids_;
td::FlatHashSet<td::string> unresolved_bot_usernames_;
td::FlatHashMap<int64, int64> temp_to_real_bot_user_id_;
td::FlatHashMap<td::string, td::vector<int64>> awaiting_bot_resolve_queries_;
td::WaitFreeHashMap<int64, double> last_send_message_time_;
struct BotUserIds {
int64 default_bot_user_id_ = 0;
int64 cur_temp_bot_user_id_ = 1;
td::FlatHashMap<td::string, int64> bot_user_ids_;
td::FlatHashSet<td::string> unresolved_bot_usernames_;
};
BotUserIds bot_user_ids_;
struct PendingBotResolveQuery {
std::size_t pending_resolve_count = 0;
@ -1220,6 +1295,9 @@ class Client final : public WebhookActor::Callback {
td::FlatHashMap<int64, PendingBotResolveQuery> pending_bot_resolve_queries_;
int64 current_bot_resolve_query_id_ = 1;
td::FlatHashMap<td::string, td::vector<int64>> awaiting_bot_resolve_queries_;
td::FlatHashMap<int64, int64> temp_to_real_bot_user_id_;
td::string dir_;
td::ActorOwn<td::ClientActor> td_client_;
td::ActorContext context_;
@ -1273,6 +1351,8 @@ class Client final : public WebhookActor::Callback {
double previous_get_updates_finish_time_ = 0;
double next_get_updates_conflict_time_ = 0;
int32 log_in_date_ = 0;
int32 flood_limited_query_count_ = 0;
double next_flood_limit_warning_time_ = 0;

View File

@ -296,7 +296,7 @@ void ClientManager::get_stats(td::Promise<td::BufferSlice> promise,
auto top_clients = get_top_clients(50, id_filter);
if(!as_json) {
sb << stat_.get_description() << '\n';
sb << BotStatActor::get_description() << '\n';
}
if (id_filter.empty()) {
if(as_json) {
@ -448,9 +448,6 @@ td::int64 ClientManager::get_tqueue_id(td::int64 user_id, bool is_test_dc) {
}
void ClientManager::start_up() {
//NB: the same scheduler as for database in Td
auto scheduler_id = 1;
// init tqueue
{
auto load_start_time = td::Time::now();
@ -478,7 +475,8 @@ void ClientManager::start_up() {
}
}
auto concurrent_binlog = std::make_shared<td::ConcurrentBinlog>(std::move(binlog), scheduler_id);
auto concurrent_binlog =
std::make_shared<td::ConcurrentBinlog>(std::move(binlog), SharedData::get_binlog_scheduler_id());
auto concurrent_tqueue_binlog = td::make_unique<td::TQueueBinlog<td::BinlogInterface>>();
concurrent_tqueue_binlog->set_binlog(std::move(concurrent_binlog));
tqueue->set_callback(std::move(concurrent_tqueue_binlog));
@ -493,18 +491,18 @@ void ClientManager::start_up() {
// init webhook_db and user_db
auto concurrent_webhook_db = td::make_unique<td::BinlogKeyValue<td::ConcurrentBinlog>>();
auto status = concurrent_webhook_db->init(parameters_->working_directory_ + "webhooks_db.binlog", td::DbKey::empty(),
scheduler_id);
SharedData::get_binlog_scheduler_id());
LOG_IF(FATAL, status.is_error()) << "Can't open webhooks_db.binlog " << status;
parameters_->shared_data_->webhook_db_ = std::move(concurrent_webhook_db);
auto concurrent_user_db = td::make_unique<td::BinlogKeyValue<td::ConcurrentBinlog>>();
status = concurrent_user_db->init(parameters_->working_directory_ + "user_db.binlog", td::DbKey::empty(), scheduler_id);
status = concurrent_user_db->init(parameters_->working_directory_ + "user_db.binlog", td::DbKey::empty(), SharedData::get_binlog_scheduler_id());
LOG_IF(FATAL, status.is_error()) << "Can't open user_db.binlog " << status.error();
parameters_->shared_data_->user_db_ = std::move(concurrent_user_db);
auto &webhook_db = *parameters_->shared_data_->webhook_db_;
auto &user_db = *parameters_->shared_data_->user_db_;
for (auto key_value : webhook_db.get_all()) {
for (const auto &key_value : webhook_db.get_all()) {
if (!token_range_(td::to_integer<td::uint64>(key_value.first))) {
LOG(WARNING) << "DROP WEBHOOK: " << key_value.first << " ---> " << key_value.second;
webhook_db.erase(key_value.first);
@ -516,8 +514,8 @@ void ClientManager::start_up() {
}
// launch watchdog
watchdog_id_ = td::create_actor_on_scheduler<Watchdog>(
"ManagerWatchdog", td::Scheduler::instance()->sched_count() - 3, td::this_thread::get_id(), WATCHDOG_TIMEOUT);
watchdog_id_ = td::create_actor_on_scheduler<Watchdog>("ManagerWatchdog", SharedData::get_watchdog_scheduler_id(),
td::this_thread::get_id(), WATCHDOG_TIMEOUT);
set_timeout_in(600.0);
}
@ -684,7 +682,7 @@ void ClientManager::raw_event(const td::Event::Raw &event) {
void ClientManager::timeout_expired() {
send_closure(watchdog_id_, &Watchdog::kick);
set_timeout_in(WATCHDOG_TIMEOUT / 2);
set_timeout_in(WATCHDOG_TIMEOUT / 10);
double now = td::Time::now();
if (now > next_tqueue_gc_time_) {

View File

@ -54,15 +54,54 @@ struct SharedData {
return static_cast<td::int32>(result);
}
static td::int32 get_database_scheduler_id() {
// the same scheduler as for database in Td
return 1;
}
static td::int32 get_file_gc_scheduler_id() {
// the same scheduler as for file GC in Td
return 2;
}
static td::int32 get_client_scheduler_id() {
// the thread for ClientManager and all Clients
return 4;
}
static td::int32 get_watchdog_scheduler_id() {
// the thread for watchdogs
return 5;
}
static td::int32 get_slow_incoming_http_scheduler_id() {
// the thread for slow incoming HTTP connections
return 6;
}
static td::int32 get_slow_outgoing_http_scheduler_id() {
// the thread for slow outgoing HTTP connections
return 7;
}
static td::int32 get_dns_resolver_scheduler_id() {
// the thread for DNS resolving
return 8;
}
static td::int32 get_binlog_scheduler_id() {
// the thread for TQueue and webhook binlogs
return 9;
}
static td::int32 get_webhook_certificate_scheduler_id() {
// the thread for webhook certificate processing
return 10;
}
static td::int32 get_statistics_thread_id() {
// the thread for CPU usage updating
return 11;
}
static td::int32 get_thread_count() {
return 12;
}
};
struct ClientParameters {
@ -72,7 +111,7 @@ struct ClientParameters {
bool local_mode_ = false;
bool allow_http_ = false;
bool use_relative_path_ = false;
bool no_file_limit_ = true;
bool no_file_limit_ = false;
bool allow_users_ = false;
bool allow_users_registration_ = false;
bool stats_hide_sensible_data_ = false;

View File

@ -6,6 +6,8 @@
//
#pragma once
#include "telegram-bot-api/ClientParameters.h"
#include "td/net/HttpInboundConnection.h"
#include "td/net/TcpListener.h"
@ -61,13 +63,8 @@ class HttpServer final : public td::TcpListener::Callback {
}
void accept(td::SocketFd fd) final {
auto scheduler_count = td::Scheduler::instance()->sched_count();
auto scheduler_id = scheduler_count - 1;
if (scheduler_id > 0) {
scheduler_id--;
}
td::create_actor<td::HttpInboundConnection>("HttpInboundConnection", td::BufferedFd<td::SocketFd>(std::move(fd)), 0,
50, 500, creator_(), scheduler_id)
50, 500, creator_(), SharedData::get_slow_incoming_http_scheduler_id())
.release();
}

View File

@ -44,7 +44,7 @@ Query::Query(td::vector<td::BufferSlice> &&container, td::Slice token, bool is_u
}
td::to_lower_inplace(method_);
start_timestamp_ = td::Time::now();
LOG(INFO) << "QUERY: create " << td::tag("ptr", this) << *this;
LOG(INFO) << "Query " << this << ": " << *this;
if (shared_data_) {
shared_data_->query_count_.fetch_add(1, std::memory_order_relaxed);
if (method_ != "getupdates") {
@ -86,7 +86,7 @@ void Query::set_stat_actor(td::ActorId<BotStatActor> stat_actor) {
void Query::set_ok(td::BufferSlice result) {
CHECK(state_ == State::Query);
LOG(INFO) << "QUERY: got ok " << td::tag("ptr", this) << td::tag("text", result.as_slice());
LOG(INFO) << "Query " << this << ": " << td::tag("method", method_) << td::tag("text", result.as_slice());
answer_ = std::move(result);
state_ = State::OK;
http_status_code_ = 200;
@ -94,7 +94,7 @@ void Query::set_ok(td::BufferSlice result) {
}
void Query::set_error(int http_status_code, td::BufferSlice result) {
LOG(INFO) << "QUERY: got error " << td::tag("ptr", this) << td::tag("code", http_status_code)
LOG(INFO) << "Query " << this << ": " << td::tag("method", method_) << td::tag("code", http_status_code)
<< td::tag("text", result.as_slice());
CHECK(state_ == State::Query);
answer_ = std::move(result);
@ -116,9 +116,25 @@ td::StringBuilder &operator<<(td::StringBuilder &sb, const Query &query) {
auto padded_time =
td::lpad(PSTRING() << td::format::as_time(td::Time::now_cached() - query.start_timestamp()), 10, ' ');
sb << "[bot" << td::rpad(query.token().str(), 46, ' ') << "][time:" << padded_time << ']'
<< td::tag("method", td::lpad(query.method().str(), 20, ' '));
<< td::tag("method", td::lpad(query.method().str(), 25, ' '));
if (!query.args().empty()) {
sb << td::oneline(PSLICE() << query.args());
sb << '{';
for (const auto &arg : query.args()) {
sb << '[';
if (arg.first.size() > 128) {
sb << '<' << arg.first.size() << '>' << td::oneline(arg.first.substr(0, 128)) << "...";
} else {
sb << td::oneline(arg.first);
}
sb << ':';
if (arg.second.size() > 4096) {
sb << '<' << arg.second.size() << '>' << td::oneline(arg.second.substr(0, 4096)) << "...";
} else {
sb << td::oneline(arg.second);
}
sb << ']';
}
sb << '}';
}
if (!query.files().empty()) {
sb << query.files();

View File

@ -38,41 +38,52 @@ class Query final : public td::ListNode {
td::Slice token() const {
return token_;
}
bool is_user() const {
return is_user_;
}
bool is_test_dc() const {
return is_test_dc_;
}
td::Slice method() const {
return method_;
}
bool has_arg(td::Slice key) const {
auto it = std::find_if(args_.begin(), args_.end(),
[&key](const std::pair<td::MutableSlice, td::MutableSlice> &s) { return s.first == key; });
return it != args_.end();
}
td::MutableSlice arg(td::Slice key) const {
auto it = std::find_if(args_.begin(), args_.end(),
[&key](const std::pair<td::MutableSlice, td::MutableSlice> &s) { return s.first == key; });
return it == args_.end() ? td::MutableSlice() : it->second;
}
const td::vector<std::pair<td::MutableSlice, td::MutableSlice>> &args() const {
return args_;
}
td::Slice get_header(td::Slice key) const {
auto it = std::find_if(headers_.begin(), headers_.end(),
[&key](const std::pair<td::MutableSlice, td::MutableSlice> &s) { return s.first == key; });
return it == headers_.end() ? td::Slice() : it->second;
}
const td::HttpFile *file(td::Slice key) const {
auto it = std::find_if(files_.begin(), files_.end(), [&key](const td::HttpFile &f) { return f.field_name == key; });
return it == files_.end() ? nullptr : &*it;
}
const td::vector<td::HttpFile> &files() const {
return files_;
}
td::int64 files_size() const;
td::string get_peer_ip_address() const;
td::BufferSlice &answer() {
@ -156,8 +167,6 @@ class Query final : public td::ListNode {
td::int64 query_size() const;
td::int64 files_size() const;
td::int64 files_max_size() const;
void send_request_stat() const;

View File

@ -7,6 +7,7 @@
#include "telegram-bot-api/Stats.h"
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/port/thread.h"
#include "td/utils/SliceBuilder.h"
#include "td/utils/StringBuilder.h"
@ -19,17 +20,24 @@ ServerCpuStat::ServerCpuStat() {
}
}
void ServerCpuStat::add_event(const td::CpuStat &cpu_stat, double now) {
std::lock_guard<std::mutex> guard(mutex_);
for (auto &stat : stat_) {
stat.add_event(cpu_stat, now);
void ServerCpuStat::update(double now) {
auto r_cpu_stat = td::cpu_stat();
if (r_cpu_stat.is_error()) {
return;
}
auto &cpu_stat = instance();
std::lock_guard<std::mutex> guard(cpu_stat.mutex_);
for (auto &stat : cpu_stat.stat_) {
stat.add_event(r_cpu_stat.ok(), now);
}
LOG(WARNING) << "CPU usage: " << cpu_stat.stat_[1].get_stat(now).as_vector()[0].value_;
}
td::string ServerCpuStat::get_description() const {
td::string ServerCpuStat::get_description() {
td::string res = "DURATION";
for (auto &descr : DESCR) {
res += "\t";
res += '\t';
res += descr;
}
return res;
@ -37,7 +45,7 @@ td::string ServerCpuStat::get_description() const {
static td::string to_percentage(td::uint64 ticks, td::uint64 total_ticks) {
static double multiplier = 100.0 * (td::thread::hardware_concurrency() ? td::thread::hardware_concurrency() : 1);
return PSTRING() << (static_cast<double>(ticks) / static_cast<double>(total_ticks) * multiplier) << "%";
return PSTRING() << (static_cast<double>(ticks) / static_cast<double>(total_ticks) * multiplier) << '%';
}
td::vector<StatItem> CpuStat::as_vector() const {
@ -167,7 +175,7 @@ td::vector<ServerBotStat> BotStatActor::as_json_ready_vector(double now) {
return res;
}
td::string BotStatActor::get_description() const {
td::string BotStatActor::get_description() {
td::string res = "DURATION";
for (auto &descr : DESCR) {
res += "\t";

View File

@ -9,7 +9,6 @@
#include "td/actor/actor.h"
#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/port/Stat.h"
#include "td/utils/Time.h"
#include "td/utils/TimedStat.h"
@ -49,16 +48,10 @@ class ServerCpuStat {
static ServerCpuStat stat;
return stat;
}
static void update(double now) {
auto r_event = td::cpu_stat();
if (r_event.is_error()) {
return;
}
instance().add_event(r_event.ok(), now);
LOG(WARNING) << "CPU usage: " << instance().stat_[1].get_stat(now).as_vector()[0].value_;
}
td::string get_description() const;
static void update(double now);
static td::string get_description();
td::vector<StatItem> as_vector(double now);
td::vector<td::vector<StatItem>> as_json_ready_vector(double now);
@ -72,8 +65,6 @@ class ServerCpuStat {
td::TimedStat<CpuStat> stat_[SIZE];
ServerCpuStat();
void add_event(const td::CpuStat &stat, double now);
};
class ServerBotInfo {
@ -157,7 +148,7 @@ class BotStatActor final : public td::Actor {
}
BotStatActor(const BotStatActor &) = delete;
BotStatActor &operator=(const BotStatActor &other) = delete;
BotStatActor &operator=(const BotStatActor &) = delete;
BotStatActor(BotStatActor &&) = default;
BotStatActor &operator=(BotStatActor &&other) noexcept {
if (!empty()) {
@ -185,8 +176,8 @@ class BotStatActor final : public td::Actor {
td::vector<StatItem> as_vector(double now);
td::vector<ServerBotStat> as_json_ready_vector(double now);
td::string get_description() const;
td::vector<td::string> get_jsonable_description() const;
static td::string get_description();
double get_score(double now);

View File

@ -47,10 +47,8 @@ WebhookActor::WebhookActor(td::ActorShared<Callback> callback, td::int64 tqueue_
, fix_ip_address_(fix_ip_address)
, from_db_flag_(from_db_flag)
, max_connections_(max_connections)
, secret_token_(std::move(secret_token))
, slow_scheduler_id_(td::Scheduler::instance()->sched_count() - 2) {
, secret_token_(std::move(secret_token)) {
CHECK(max_connections_ > 0);
CHECK(slow_scheduler_id_ > 0);
if (!cached_ip_address.empty()) {
auto r_ip_address = td::IPAddress::get_ip_address(cached_ip_address);
@ -73,7 +71,7 @@ WebhookActor::WebhookActor(td::ActorShared<Callback> callback, td::int64 tqueue_
WebhookActor::~WebhookActor() {
td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), update_map_, queue_updates_,
queues_);
queues_, ssl_ctx_);
}
void WebhookActor::relax_wakeup_at(double wakeup_at, const char *source) {
@ -230,7 +228,8 @@ td::Status WebhookActor::create_connection(td::BufferedFd<td::SocketFd> fd) {
auto *conn = connections_.get(id);
conn->actor_id_ = td::create_actor<td::HttpOutboundConnection>(
PSLICE() << "Connect:" << id, std::move(fd), std::move(ssl_stream), 0, 50, 60,
td::ActorShared<td::HttpOutboundConnection::Callback>(actor_id(this), id), slow_scheduler_id_);
td::ActorShared<td::HttpOutboundConnection::Callback>(actor_id(this), id),
SharedData::get_slow_outgoing_http_scheduler_id());
conn->ip_generation_ = ip_generation_;
conn->event_id_ = {};
conn->id_ = id;
@ -623,10 +622,12 @@ void WebhookActor::handle(td::unique_ptr<td::HttpQuery> response) {
if (!method.empty() && method != "deletewebhook" && method != "setwebhook" && method != "close" &&
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);
response->container_.emplace_back(PSLICE() << (tqueue_id_ & ((static_cast<td::int64>(1) << 54) - 1)));
auto token = response->container_.back().as_slice();
auto query = td::make_unique<Query>(
std::move(response->container_), token, tqueue_id_ >= (static_cast<td::int64>(1) << 54), 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::Promise<td::unique_ptr<Query>>()));
send_closure(callback_, &Callback::send, std::move(promised_query));
}
@ -690,7 +691,12 @@ void WebhookActor::handle(td::unique_ptr<td::HttpQuery> response) {
void WebhookActor::start_up() {
max_loaded_updates_ = max_connections_ * 2;
next_ip_address_resolve_time_ = last_success_time_ = td::Time::now() - 3600;
last_success_time_ = td::Time::now() - 2 * IP_ADDRESS_CACHE_TIME;
if (from_db_flag_) {
next_ip_address_resolve_time_ = td::Time::now() + td::Random::fast(0, IP_ADDRESS_CACHE_TIME);
} else {
next_ip_address_resolve_time_ = last_success_time_;
}
active_new_connection_flood_.add_limit(0.5, 10);
@ -723,11 +729,12 @@ void WebhookActor::start_up() {
if (url_.protocol_ != td::HttpUrl::Protocol::Http && !stop_flag_) {
// asynchronously create SSL context
td::Scheduler::instance()->run_on_scheduler(
SharedData::get_database_scheduler_id(), [actor_id = actor_id(this), cert_path = cert_path_](td::Unit) mutable {
send_closure(actor_id, &WebhookActor::on_ssl_context_created,
td::SslCtx::create(cert_path, td::SslCtx::VerifyPeer::On));
});
td::Scheduler::instance()->run_on_scheduler(SharedData::get_webhook_certificate_scheduler_id(),
[actor_id = actor_id(this), cert_path = cert_path_](td::Unit) mutable {
send_closure(
actor_id, &WebhookActor::on_ssl_context_created,
td::SslCtx::create(cert_path, td::SslCtx::VerifyPeer::On));
});
}
yield();

View File

@ -177,7 +177,6 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback {
double last_success_time_ = 0;
double wakeup_at_ = 0;
bool last_update_was_successful_ = true;
td::int32 slow_scheduler_id_ = -1;
void relax_wakeup_at(double wakeup_at, const char *source);

View File

@ -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.7.1";
parameters->version_ = "7.0";
parameters->shared_data_ = shared_data;
parameters->start_time_ = start_time;
auto net_query_stats = td::create_net_query_stats();
@ -476,27 +476,22 @@ int main(int argc, char *argv[]) {
// << (td::GitInfo::is_dirty() ? "(dirty)" : "") << " started";
LOG(WARNING) << "TDLight Bot API " << parameters->version_ << " server started";
// +3 threads for Td
// one thread for ClientManager and all Clients
// one thread for watchdogs
// one thread for slow HTTP connections
// one thread for DNS resolving
const int thread_count = 7;
td::ConcurrentScheduler sched(thread_count, cpu_affinity);
td::ConcurrentScheduler sched(SharedData::get_thread_count() - 1, cpu_affinity);
td::GetHostByNameActor::Options get_host_by_name_options;
get_host_by_name_options.scheduler_id = thread_count;
get_host_by_name_options.scheduler_id = SharedData::get_dns_resolver_scheduler_id();
parameters->get_host_by_name_actor_id_ =
sched.create_actor_unsafe<td::GetHostByNameActor>(0, "GetHostByName", std::move(get_host_by_name_options))
.release();
auto client_manager =
sched.create_actor_unsafe<ClientManager>(thread_count - 3, "ClientManager", std::move(parameters), token_range)
.release();
auto client_manager = sched
.create_actor_unsafe<ClientManager>(SharedData::get_client_scheduler_id(), "ClientManager",
std::move(parameters), token_range)
.release();
sched
.create_actor_unsafe<HttpServer>(
thread_count - 3, "HttpServer", http_ip_address, http_port,
SharedData::get_client_scheduler_id(), "HttpServer", http_ip_address, http_port,
[client_manager, shared_data] {
return td::ActorOwn<td::HttpInboundConnection::Callback>(
td::create_actor<HttpConnection>("HttpConnection", client_manager, shared_data));
@ -506,7 +501,7 @@ int main(int argc, char *argv[]) {
if (http_stat_port != 0) {
sched
.create_actor_unsafe<HttpServer>(
thread_count - 3, "HttpStatsServer", http_stat_ip_address, http_stat_port,
SharedData::get_client_scheduler_id(), "HttpStatsServer", http_stat_ip_address, http_stat_port,
[client_manager] {
return td::ActorOwn<td::HttpInboundConnection::Callback>(
td::create_actor<HttpStatConnection>("HttpStatConnection", client_manager));
@ -515,8 +510,8 @@ int main(int argc, char *argv[]) {
}
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);
auto watchdog_id = sched.create_actor_unsafe<Watchdog>(SharedData::get_watchdog_scheduler_id(), "Watchdog",
td::this_thread::get_id(), WATCHDOG_TIMEOUT);
sched.start();
@ -578,13 +573,15 @@ int main(int argc, char *argv[]) {
next_cron_time = now;
}
next_cron_time += 1.0;
ServerCpuStat::update(now);
auto guard = sched.get_main_guard();
td::Scheduler::instance()->run_on_scheduler(SharedData::get_statistics_thread_id(),
[](td::Unit) { ServerCpuStat::update(td::Time::now()); });
}
if (now >= start_time + 600) {
auto guard = sched.get_main_guard();
send_closure(watchdog_id, &Watchdog::kick);
next_watchdog_kick_time = now + WATCHDOG_TIMEOUT / 2;
next_watchdog_kick_time = now + WATCHDOG_TIMEOUT / 10;
}
if (!need_dump_statistics.test_and_set() || now > last_dump_time + 300.0) {