1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/telegram/net/NetQuery.h"
10 
11 #include "td/actor/actor.h"
12 
13 #include "td/utils/common.h"
14 #include "td/utils/Random.h"
15 
16 #include <limits>
17 #include <unordered_map>
18 
19 namespace td {
20 
21 class SequenceDispatcher final : public NetQueryCallback {
22  public:
23   class Parent : public Actor {
24    public:
25     virtual void ready_to_close() = 0;
26     virtual void on_result() = 0;
27   };
28   SequenceDispatcher() = default;
SequenceDispatcher(ActorShared<Parent> parent)29   explicit SequenceDispatcher(ActorShared<Parent> parent) : parent_(std::move(parent)) {
30   }
31   void send_with_callback(NetQueryPtr query, ActorShared<NetQueryCallback> callback);
32   void on_result(NetQueryPtr query) final;
33   void close_silent();
34 
35  private:
36   enum class State : int32 { Start, Wait, Finish, Dummy };
37   struct Data {
38     State state_;
39     NetQueryRef net_query_ref_;
40     NetQueryPtr query_;
41     ActorShared<NetQueryCallback> callback_;
42     uint64 generation_;
43     double total_timeout_;
44     double last_timeout_;
45   };
46 
47   ActorShared<Parent> parent_;
48   size_t id_offset_ = 1;
49   std::vector<Data> data_;
50   size_t finish_i_ = 0;  // skip state_ == State::Finish
51   size_t next_i_ = 0;
52   size_t last_sent_i_ = std::numeric_limits<size_t>::max();
53   uint64 generation_ = 1;
54   uint32 session_rand_ = Random::secure_int32();
55 
56   static constexpr int32 MAX_SIMULTANEOUS_WAIT = 10;
57   uint32 wait_cnt_ = 0;
58 
59   void check_timeout(Data &data);
60 
61   void try_resend_query(Data &data, NetQueryPtr query);
62   Data &data_from_token();
63   void on_resend_ok(NetQueryPtr query);
64   void on_resend_error();
65   void do_resend(Data &data);
66   void do_finish(Data &data);
67 
68   void loop() final;
69   void try_shrink();
70 
71   void timeout_expired() final;
72   void hangup() final;
73   void tear_down() final;
74 };
75 
76 class MultiSequenceDispatcher final : public SequenceDispatcher::Parent {
77  public:
78   void send_with_callback(NetQueryPtr query, ActorShared<NetQueryCallback> callback, uint64 sequence_id);
79 
80  private:
81   struct Data {
82     int32 cnt_;
83     ActorOwn<SequenceDispatcher> dispatcher_;
84   };
85   std::unordered_map<uint64, Data> dispatchers_;
86   void on_result() final;
87   void ready_to_close() final;
88 };
89 
90 }  // namespace td
91