aboutsummaryrefslogtreecommitdiffhomepage
path: root/td/telegram/InlineQueriesManager.h
blob: c11c8480c08fd42cf62f5a440a8244ada51ba35c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once

#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Location.h"
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/Photo.h"
#include "td/telegram/RequestedDialogType.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"

#include "td/actor/actor.h"
#include "td/actor/MultiPromise.h"
#include "td/actor/MultiTimeout.h"

#include "td/utils/common.h"
#include "td/utils/FlatHashMap.h"
#include "td/utils/Promise.h"
#include "td/utils/Status.h"

#include <utility>

namespace td {

class Game;
class Td;
class WebAppOpenParameters;

class InlineQueriesManager final : public Actor {
 public:
  InlineQueriesManager(Td *td, ActorShared<> parent);

  void after_get_difference();

  void answer_inline_query(int64 inline_query_id, bool is_personal,
                           td_api::object_ptr<td_api::inlineQueryResultsButton> &&button,
                           vector<td_api::object_ptr<td_api::InputInlineQueryResult>> &&input_results, int32 cache_time,
                           const string &next_offset, Promise<Unit> &&promise) const;

  void answer_guest_query(int64 guest_query_id, td_api::object_ptr<td_api::InputInlineQueryResult> &&input_result,
                          Promise<td_api::object_ptr<td_api::inlineMessageId>> &&promise) const;

  void save_prepared_inline_message(UserId user_id, td_api::object_ptr<td_api::InputInlineQueryResult> &&input_result,
                                    td_api::object_ptr<td_api::targetChatTypes> &&chat_types,
                                    Promise<td_api::object_ptr<td_api::preparedInlineMessageId>> &&promise);

  void get_prepared_inline_message(UserId bot_user_id, const string &prepared_message_id,
                                   Promise<td_api::object_ptr<td_api::preparedInlineMessage>> &&promise);

  void save_prepared_keyboard_button(UserId user_id, td_api::object_ptr<td_api::keyboardButton> &&button,
                                     Promise<string> &&promise);

  void get_prepared_keyboard_button(UserId bot_user_id, const string &prepared_button_id,
                                    Promise<td_api::object_ptr<td_api::keyboardButton>> &&promise);

  void get_simple_web_view_url(UserId bot_user_id, string &&url, const WebAppOpenParameters &parameters,
                               Promise<td_api::object_ptr<td_api::webAppUrl>> &&promise);

  void send_web_view_data(UserId bot_user_id, string &&button_text, string &&data, Promise<Unit> &&promise) const;

  void answer_web_view_query(const string &web_view_query_id,
                             td_api::object_ptr<td_api::InputInlineQueryResult> &&input_result,
                             Promise<td_api::object_ptr<td_api::inlineMessageId>> &&promise) const;

  void get_weather(Location location, Promise<td_api::object_ptr<td_api::currentWeather>> &&promise);

  void send_inline_query(UserId bot_user_id, DialogId dialog_id, Location user_location, const string &query,
                         const string &offset, Promise<td_api::object_ptr<td_api::inlineQueryResults>> &&promise);

  vector<UserId> get_recent_inline_bots(Promise<Unit> &&promise);

  void remove_recent_inline_bot(UserId bot_user_id, Promise<Unit> &&promise);

  const InlineMessageContent *get_inline_message_content(int64 query_id, const string &result_id);

  UserId get_inline_bot_user_id(int64 query_id) const;

  void on_get_inline_query_results(DialogId dialog_id, UserId bot_user_id, uint64 query_hash,
                                   tl_object_ptr<telegram_api::messages_botResults> &&results,
                                   Promise<td_api::object_ptr<td_api::inlineQueryResults>> promise);

  void on_get_prepared_inline_message(
      UserId bot_user_id, uint64 query_hash,
      telegram_api::object_ptr<telegram_api::messages_preparedInlineMessage> &&prepared_message,
      Promise<td_api::object_ptr<td_api::preparedInlineMessage>> promise);

  const RequestedDialogType *get_requested_dialog_type(UserId bot_user_id, const string &prepared_button_id);

  void on_get_requested_web_view_button(UserId bot_user_id, const string &prepared_button_id,
                                        const RequestedDialogType *requested_dialog_type);

  void on_new_query(int64 query_id, UserId sender_user_id, Location user_location,
                    tl_object_ptr<telegram_api::InlineQueryPeerType> peer_type, const string &query,
                    const string &offset);

  void on_chosen_result(UserId user_id, Location user_location, const string &query, const string &result_id,
                        tl_object_ptr<telegram_api::InputBotInlineMessageID> &&input_bot_inline_message_id);

  static string get_inline_message_id(
      tl_object_ptr<telegram_api::InputBotInlineMessageID> &&input_bot_inline_message_id);

 private:
  static constexpr size_t MAX_RECENT_INLINE_BOTS = 20;  // some reasonable value
  static constexpr int32 INLINE_QUERY_DELAY_MS = 400;   // server-side limit

  Result<tl_object_ptr<telegram_api::InputBotInlineResult>> get_input_bot_inline_result(
      td_api::object_ptr<td_api::InputInlineQueryResult> &&result, bool *is_gallery, bool *force_vertical) const;

  Result<tl_object_ptr<telegram_api::InputBotInlineMessage>> get_inline_message(
      tl_object_ptr<td_api::InputMessageContent> &&input_message_content,
      tl_object_ptr<td_api::ReplyMarkup> &&reply_markup_ptr,
      int32 allowed_media_content_id) const TD_WARN_UNUSED_RESULT;

  bool register_inline_message_content(int64 query_id, const string &result_id, FileId file_id,
                                       tl_object_ptr<telegram_api::BotInlineMessage> &&inline_message,
                                       int32 allowed_media_content_id, bool is_secret_chat, Photo *photo = nullptr,
                                       Game *game = nullptr);

  tl_object_ptr<td_api::thumbnail> register_thumbnail(
      tl_object_ptr<telegram_api::WebDocument> &&web_document_ptr) const;

  static string get_web_document_url(const tl_object_ptr<telegram_api::WebDocument> &web_document_ptr);

  static string get_web_document_content_type(const tl_object_ptr<telegram_api::WebDocument> &web_document_ptr);

  td_api::object_ptr<td_api::InlineQueryResult> get_inline_query_result_object(
      int64 query_id, DialogId dialog_id, telegram_api::object_ptr<telegram_api::BotInlineResult> result_ptr);

  bool update_bot_usage(UserId bot_user_id);

  void save_recently_used_bots();

  bool load_recently_used_bots(Promise<Unit> &promise);

  void do_get_weather(DialogId dialog_id, Location location,
                      Promise<td_api::object_ptr<td_api::currentWeather>> &&promise);

  void on_get_weather(td_api::object_ptr<td_api::inlineQueryResults> results,
                      Promise<td_api::object_ptr<td_api::currentWeather>> &&promise);

  td_api::object_ptr<td_api::inlineQueryResults> get_inline_query_results_object(uint64 query_hash);

  td_api::object_ptr<td_api::preparedInlineMessage> get_prepared_inline_message_object(uint64 query_hash);

  static void on_drop_inline_query_result_timeout_callback(void *inline_queries_manager_ptr, int64 query_hash);

  void on_drop_inline_query_result_timeout(int64 query_hash);

  static void on_drop_inline_query_message_timeout_callback(void *inline_queries_manager_ptr, int64 query_id);

  void on_drop_inline_query_message_timeout(int64 query_id);

  void loop() final;

  void tear_down() final;

  int32 recently_used_bots_loaded_ = 0;  // 0 - not loaded, 1 - load request was sent, 2 - loaded
  MultiPromiseActor resolve_recent_inline_bots_multipromise_{"ResolveRecentInlineBotsMultiPromiseActor"};

  vector<UserId> recently_used_bot_user_ids_;

  struct PendingInlineQuery {
    uint64 query_hash;
    UserId bot_user_id;
    DialogId dialog_id;
    tl_object_ptr<telegram_api::InputPeer> input_peer;
    Location user_location;
    string query;
    string offset;
    Promise<td_api::object_ptr<td_api::inlineQueryResults>> promise;
  };

  double next_inline_query_time_ = 0.0;
  unique_ptr<PendingInlineQuery> pending_inline_query_;
  NetQueryRef sent_query_;

  struct InlineQueryResult {
    td_api::object_ptr<td_api::inlineQueryResults> results;
    double cache_expire_time;
    int32 pending_request_count;
    int64 target_dialog_types_mask;
    bool is_inline_query;
  };

  MultiTimeout drop_inline_query_result_timeout_{"DropInlineQueryResultTimeout"};
  MultiTimeout drop_inline_query_message_timeout_{"DropInlineQueryMessageTimeout"};
  FlatHashMap<uint64, InlineQueryResult> inline_query_results_;  // query_hash -> result

  FlatHashMap<int64, FlatHashMap<string, InlineMessageContent>>
      inline_message_contents_;  // query_id -> [result_id -> inline_message_content]

  FlatHashMap<int64, UserId> query_id_to_bot_user_id_;

  UserId last_requested_web_view_button_bot_user_id_;
  string last_requested_web_view_button_prepared_button_id_;
  unique_ptr<RequestedDialogType> last_requested_web_view_button_requested_dialog_type_;

  Td *td_;
  ActorShared<> parent_;
};

}  // namespace td