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,9 +547,16 @@ paths:
/deleteMessages:
post:
tags:
- added
- modified
description: |-
Delete all the messages with message_id in range between start and end.
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.
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
@ -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,11 +544,16 @@ 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,
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_;
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_;
td::FlatHashMap<int64, int64> temp_to_real_bot_user_id_;
td::FlatHashMap<td::string, td::vector<int64>> awaiting_bot_resolve_queries_;
};
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;
}
td::string ServerCpuStat::get_description() const {
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() {
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,9 +729,10 @@ 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::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));
});
}

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)
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) {