2019-02-19 14:45:32 +01:00
|
|
|
//
|
2022-01-01 01:35:39 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
2019-02-19 14:45:32 +01:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
2019-11-26 17:53:10 +01:00
|
|
|
#include "td/telegram/FullMessageId.h"
|
2020-04-03 22:39:50 +02:00
|
|
|
#include "td/telegram/MessageEntity.h"
|
2019-02-21 13:42:54 +01:00
|
|
|
#include "td/telegram/net/NetQuery.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
#include "td/telegram/PollId.h"
|
2019-04-12 01:10:33 +02:00
|
|
|
#include "td/telegram/ReplyMarkup.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
#include "td/telegram/td_api.h"
|
|
|
|
#include "td/telegram/telegram_api.h"
|
2020-01-12 02:40:17 +01:00
|
|
|
#include "td/telegram/UserId.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
|
|
|
|
#include "td/actor/actor.h"
|
2022-07-02 22:32:18 +02:00
|
|
|
#include "td/actor/MultiTimeout.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2020-01-27 02:54:01 +01:00
|
|
|
#include "td/utils/buffer.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
#include "td/utils/common.h"
|
2022-02-07 22:04:34 +01:00
|
|
|
#include "td/utils/FlatHashMap.h"
|
2022-03-11 19:38:48 +01:00
|
|
|
#include "td/utils/FlatHashSet.h"
|
2022-06-27 12:30:18 +02:00
|
|
|
#include "td/utils/Promise.h"
|
2019-02-22 21:15:43 +01:00
|
|
|
#include "td/utils/Status.h"
|
2022-11-22 10:23:58 +01:00
|
|
|
#include "td/utils/WaitFreeHashMap.h"
|
2022-11-22 10:58:07 +01:00
|
|
|
#include "td/utils/WaitFreeHashSet.h"
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2020-01-27 02:54:01 +01:00
|
|
|
#include <utility>
|
2019-02-19 14:45:32 +01:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
2019-02-21 15:40:37 +01:00
|
|
|
struct BinlogEvent;
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
class Td;
|
|
|
|
|
2021-07-04 04:58:54 +02:00
|
|
|
class PollManager final : public Actor {
|
2019-02-19 14:45:32 +01:00
|
|
|
public:
|
|
|
|
PollManager(Td *td, ActorShared<> parent);
|
|
|
|
|
|
|
|
PollManager(const PollManager &) = delete;
|
|
|
|
PollManager &operator=(const PollManager &) = delete;
|
|
|
|
PollManager(PollManager &&) = delete;
|
|
|
|
PollManager &operator=(PollManager &&) = delete;
|
2021-07-03 22:51:36 +02:00
|
|
|
~PollManager() final;
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2019-02-22 20:53:02 +01:00
|
|
|
static bool is_local_poll_id(PollId poll_id);
|
|
|
|
|
2020-01-11 01:46:26 +01:00
|
|
|
PollId create_poll(string &&question, vector<string> &&options, bool is_anonymous, bool allow_multiple_answers,
|
2020-04-03 23:05:35 +02:00
|
|
|
bool is_quiz, int32 correct_option_id, FormattedText &&explanation, int32 open_period,
|
|
|
|
int32 close_date, bool is_closed);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2020-02-22 17:21:58 +01:00
|
|
|
void register_poll(PollId poll_id, FullMessageId full_message_id, const char *source);
|
2019-02-19 16:42:59 +01:00
|
|
|
|
2020-02-22 17:21:58 +01:00
|
|
|
void unregister_poll(PollId poll_id, FullMessageId full_message_id, const char *source);
|
2019-02-19 16:42:59 +01:00
|
|
|
|
2019-02-22 16:09:55 +01:00
|
|
|
bool get_poll_is_closed(PollId poll_id) const;
|
|
|
|
|
2020-01-11 01:46:26 +01:00
|
|
|
bool get_poll_is_anonymous(PollId poll_id) const;
|
|
|
|
|
2019-03-03 04:36:30 +01:00
|
|
|
string get_poll_search_text(PollId poll_id) const;
|
|
|
|
|
2019-02-21 13:23:05 +01:00
|
|
|
void set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<int32> &&option_ids,
|
|
|
|
Promise<Unit> &&promise);
|
|
|
|
|
2020-01-18 05:01:05 +01:00
|
|
|
void get_poll_voters(PollId poll_id, FullMessageId full_message_id, int32 option_id, int32 offset, int32 limit,
|
2020-01-13 19:21:58 +01:00
|
|
|
Promise<std::pair<int32, vector<UserId>>> &&promise);
|
|
|
|
|
2019-04-12 01:10:33 +02:00
|
|
|
void stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
|
|
|
|
Promise<Unit> &&promise);
|
2019-02-22 16:09:55 +01:00
|
|
|
|
|
|
|
void stop_local_poll(PollId poll_id);
|
2019-02-19 15:06:48 +01:00
|
|
|
|
2021-09-05 22:11:25 +02:00
|
|
|
PollId dup_poll(PollId poll_id);
|
|
|
|
|
2020-01-15 03:42:10 +01:00
|
|
|
bool has_input_media(PollId poll_id) const;
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
tl_object_ptr<telegram_api::InputMedia> get_input_media(PollId poll_id) const;
|
|
|
|
|
|
|
|
PollId on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll> &&poll_server,
|
2022-05-29 18:31:36 +02:00
|
|
|
tl_object_ptr<telegram_api::pollResults> &&poll_results, const char *source);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2020-01-13 20:56:59 +01:00
|
|
|
void on_get_poll_vote(PollId poll_id, UserId user_id, vector<BufferSlice> &&options);
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
td_api::object_ptr<td_api::poll> get_poll_object(PollId poll_id) const;
|
|
|
|
|
2019-02-21 15:40:37 +01:00
|
|
|
void on_binlog_events(vector<BinlogEvent> &&events);
|
|
|
|
|
2019-03-05 21:21:10 +01:00
|
|
|
static vector<int32> get_vote_percentage(const vector<int32> &voter_counts, int32 total_voter_count);
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
template <class StorerT>
|
|
|
|
void store_poll(PollId poll_id, StorerT &storer) const;
|
|
|
|
|
|
|
|
template <class ParserT>
|
|
|
|
PollId parse_poll(ParserT &parser);
|
|
|
|
|
|
|
|
private:
|
2019-02-21 01:52:58 +01:00
|
|
|
struct PollOption {
|
2019-02-19 14:45:32 +01:00
|
|
|
string text;
|
|
|
|
string data;
|
|
|
|
int32 voter_count = 0;
|
|
|
|
bool is_chosen = false;
|
|
|
|
|
|
|
|
template <class StorerT>
|
|
|
|
void store(StorerT &storer) const;
|
|
|
|
template <class ParserT>
|
|
|
|
void parse(ParserT &parser);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Poll {
|
|
|
|
string question;
|
2019-02-21 01:52:58 +01:00
|
|
|
vector<PollOption> options;
|
2020-01-12 02:40:17 +01:00
|
|
|
vector<UserId> recent_voter_user_ids;
|
2020-04-03 22:39:50 +02:00
|
|
|
FormattedText explanation;
|
2019-02-19 14:45:32 +01:00
|
|
|
int32 total_voter_count = 0;
|
2020-01-11 01:46:26 +01:00
|
|
|
int32 correct_option_id = -1;
|
2020-04-03 23:05:35 +02:00
|
|
|
int32 open_period = 0;
|
2020-04-03 15:50:10 +02:00
|
|
|
int32 close_date = 0;
|
2020-01-11 01:46:26 +01:00
|
|
|
bool is_anonymous = true;
|
|
|
|
bool allow_multiple_answers = false;
|
|
|
|
bool is_quiz = false;
|
2019-02-19 14:45:32 +01:00
|
|
|
bool is_closed = false;
|
2020-04-05 04:35:52 +02:00
|
|
|
bool is_updated_after_close = false;
|
2020-04-04 01:44:25 +02:00
|
|
|
mutable bool was_saved = false;
|
2019-02-19 14:45:32 +01:00
|
|
|
|
|
|
|
template <class StorerT>
|
|
|
|
void store(StorerT &storer) const;
|
|
|
|
template <class ParserT>
|
|
|
|
void parse(ParserT &parser);
|
|
|
|
};
|
|
|
|
|
2020-01-13 19:21:58 +01:00
|
|
|
struct PollOptionVoters {
|
|
|
|
vector<UserId> voter_user_ids;
|
|
|
|
string next_offset;
|
|
|
|
vector<Promise<std::pair<int32, vector<UserId>>>> pending_queries;
|
|
|
|
bool was_invalidated = false; // the list needs to be invalidated when voters are changed
|
|
|
|
};
|
|
|
|
|
2020-01-18 05:01:05 +01:00
|
|
|
static constexpr int32 MAX_GET_POLL_VOTERS = 50; // server side limit
|
2022-05-09 00:46:46 +02:00
|
|
|
static constexpr int32 UNLOAD_POLL_DELAY = 600; // some reasonable value
|
2020-01-13 19:21:58 +01:00
|
|
|
|
2019-02-21 15:40:37 +01:00
|
|
|
class SetPollAnswerLogEvent;
|
2019-02-22 16:09:55 +01:00
|
|
|
class StopPollLogEvent;
|
2019-02-21 15:40:37 +01:00
|
|
|
|
2021-07-03 22:51:36 +02:00
|
|
|
void start_up() final;
|
|
|
|
void tear_down() final;
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2019-02-22 20:53:02 +01:00
|
|
|
static void on_update_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2020-04-05 03:31:59 +02:00
|
|
|
static void on_close_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
|
|
|
|
|
2022-05-09 00:46:46 +02:00
|
|
|
static void on_unload_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
|
|
|
|
|
2019-02-23 18:59:29 +01:00
|
|
|
static td_api::object_ptr<td_api::pollOption> get_poll_option_object(const PollOption &poll_option);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2019-02-21 01:52:58 +01:00
|
|
|
static telegram_api::object_ptr<telegram_api::pollAnswer> get_input_poll_option(const PollOption &poll_option);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2019-02-21 01:52:58 +01:00
|
|
|
static vector<PollOption> get_poll_options(vector<tl_object_ptr<telegram_api::pollAnswer>> &&poll_options);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
|
|
|
bool have_poll(PollId poll_id) const;
|
|
|
|
|
|
|
|
bool have_poll_force(PollId poll_id);
|
|
|
|
|
|
|
|
const Poll *get_poll(PollId poll_id) const;
|
|
|
|
|
2022-05-09 00:46:46 +02:00
|
|
|
const Poll *get_poll(PollId poll_id);
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
Poll *get_poll_editable(PollId poll_id);
|
|
|
|
|
2022-05-09 00:46:46 +02:00
|
|
|
bool can_unload_poll(PollId poll_id);
|
|
|
|
|
|
|
|
void schedule_poll_unload(PollId poll_id);
|
|
|
|
|
2019-02-20 23:54:31 +01:00
|
|
|
void notify_on_poll_update(PollId poll_id);
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
static string get_poll_database_key(PollId poll_id);
|
|
|
|
|
2021-10-19 17:11:16 +02:00
|
|
|
static void save_poll(const Poll *poll, PollId poll_id);
|
2019-02-19 14:45:32 +01:00
|
|
|
|
|
|
|
void on_load_poll_from_database(PollId poll_id, string value);
|
|
|
|
|
2019-02-22 20:53:02 +01:00
|
|
|
double get_polling_timeout() const;
|
|
|
|
|
|
|
|
void on_update_poll_timeout(PollId poll_id);
|
|
|
|
|
2020-04-05 03:31:59 +02:00
|
|
|
void on_close_poll_timeout(PollId poll_id);
|
|
|
|
|
2022-05-09 00:46:46 +02:00
|
|
|
void on_unload_poll_timeout(PollId poll_id);
|
|
|
|
|
2019-02-22 20:53:02 +01:00
|
|
|
void on_online();
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
Poll *get_poll_force(PollId poll_id);
|
|
|
|
|
2019-03-29 03:16:28 +01:00
|
|
|
td_api::object_ptr<td_api::poll> get_poll_object(PollId poll_id, const Poll *poll) const;
|
|
|
|
|
2019-03-10 08:57:15 +01:00
|
|
|
void on_get_poll_results(PollId poll_id, uint64 generation, Result<tl_object_ptr<telegram_api::Updates>> result);
|
2019-03-09 19:07:07 +01:00
|
|
|
|
2020-09-22 01:15:09 +02:00
|
|
|
void do_set_poll_answer(PollId poll_id, FullMessageId full_message_id, vector<string> &&options, uint64 log_event_id,
|
2019-02-21 13:23:05 +01:00
|
|
|
Promise<Unit> &&promise);
|
|
|
|
|
2019-03-11 17:06:53 +01:00
|
|
|
void on_set_poll_answer(PollId poll_id, uint64 generation, Result<tl_object_ptr<telegram_api::Updates>> &&result);
|
2019-02-21 13:23:05 +01:00
|
|
|
|
2020-12-21 23:51:20 +01:00
|
|
|
void on_set_poll_answer_finished(PollId poll_id, Result<Unit> &&result, vector<Promise<Unit>> &&promises);
|
|
|
|
|
2020-01-13 19:21:58 +01:00
|
|
|
void invalidate_poll_voters(const Poll *poll, PollId poll_id);
|
|
|
|
|
|
|
|
void invalidate_poll_option_voters(const Poll *poll, PollId poll_id, size_t option_index);
|
|
|
|
|
|
|
|
PollOptionVoters &get_poll_option_voters(const Poll *poll, PollId poll_id, int32 option_id);
|
|
|
|
|
2020-05-23 19:04:51 +02:00
|
|
|
void on_get_poll_voters(PollId poll_id, int32 option_id, string offset, int32 limit,
|
2020-01-13 19:21:58 +01:00
|
|
|
Result<tl_object_ptr<telegram_api::messages_votesList>> &&result);
|
|
|
|
|
2019-04-12 01:10:33 +02:00
|
|
|
void do_stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
|
2020-09-22 01:15:09 +02:00
|
|
|
uint64 log_event_id, Promise<Unit> &&promise);
|
2019-02-22 16:09:55 +01:00
|
|
|
|
2022-11-22 10:15:58 +01:00
|
|
|
void on_stop_poll_finished(PollId poll_id, FullMessageId full_message_id, uint64 log_event_id, Result<Unit> &&result,
|
|
|
|
Promise<Unit> &&promise);
|
2022-07-24 11:19:51 +02:00
|
|
|
|
2022-06-20 15:53:28 +02:00
|
|
|
void forget_local_poll(PollId poll_id);
|
|
|
|
|
2019-02-22 20:53:02 +01:00
|
|
|
MultiTimeout update_poll_timeout_{"UpdatePollTimeout"};
|
2020-04-05 03:31:59 +02:00
|
|
|
MultiTimeout close_poll_timeout_{"ClosePollTimeout"};
|
2022-05-09 00:46:46 +02:00
|
|
|
MultiTimeout unload_poll_timeout_{"UnloadPollTimeout"};
|
2019-02-22 20:53:02 +01:00
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
Td *td_;
|
|
|
|
ActorShared<> parent_;
|
2022-11-22 10:23:58 +01:00
|
|
|
WaitFreeHashMap<PollId, unique_ptr<Poll>, PollIdHash> polls_;
|
2019-02-19 14:45:32 +01:00
|
|
|
|
2022-11-22 10:58:07 +01:00
|
|
|
WaitFreeHashMap<PollId, WaitFreeHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> server_poll_messages_;
|
|
|
|
WaitFreeHashMap<PollId, WaitFreeHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> other_poll_messages_;
|
2019-02-19 16:42:59 +01:00
|
|
|
|
2019-02-21 13:23:05 +01:00
|
|
|
struct PendingPollAnswer {
|
|
|
|
vector<string> options_;
|
|
|
|
vector<Promise<Unit>> promises_;
|
|
|
|
uint64 generation_ = 0;
|
2020-09-22 01:15:09 +02:00
|
|
|
uint64 log_event_id_ = 0;
|
2019-02-21 13:42:54 +01:00
|
|
|
NetQueryRef query_ref_;
|
2019-02-21 13:23:05 +01:00
|
|
|
};
|
2022-02-07 20:41:07 +01:00
|
|
|
FlatHashMap<PollId, PendingPollAnswer, PollIdHash> pending_answers_;
|
2019-02-21 13:23:05 +01:00
|
|
|
|
2022-02-07 20:41:07 +01:00
|
|
|
FlatHashMap<PollId, vector<PollOptionVoters>, PollIdHash> poll_voters_;
|
2020-01-13 19:21:58 +01:00
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
int64 current_local_poll_id_ = 0;
|
|
|
|
|
2019-02-21 13:23:05 +01:00
|
|
|
uint64 current_generation_ = 0;
|
|
|
|
|
2022-03-11 19:38:48 +01:00
|
|
|
FlatHashSet<PollId, PollIdHash> loaded_from_database_polls_;
|
2019-04-09 12:25:29 +02:00
|
|
|
|
2022-03-11 19:38:48 +01:00
|
|
|
FlatHashSet<PollId, PollIdHash> being_closed_polls_;
|
2019-02-19 14:45:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace td
|