summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/td/telegram/net/TempAuthKeyWatchdog.h
blob: b15e9c9f2facc3ddd96f1675ca23bddd2dfdc92b (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
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// 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/Global.h"
#include "td/telegram/net/NetQueryCreator.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/telegram_api.h"

#include "td/actor/actor.h"

#include "td/utils/common.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Time.h"

#include <map>

namespace td {

class TempAuthKeyWatchdog final : public NetQueryCallback {
  class RegisteredAuthKeyImpl {
   public:
    explicit RegisteredAuthKeyImpl(int64 auth_key_id)
        : watchdog_(G()->temp_auth_key_watchdog()), auth_key_id_(auth_key_id) {
    }
    RegisteredAuthKeyImpl(const RegisteredAuthKeyImpl &other) = delete;
    RegisteredAuthKeyImpl &operator=(const RegisteredAuthKeyImpl &other) = delete;
    RegisteredAuthKeyImpl(RegisteredAuthKeyImpl &&other) = delete;
    RegisteredAuthKeyImpl &operator=(RegisteredAuthKeyImpl &&other) = delete;
    ~RegisteredAuthKeyImpl() {
      send_closure(watchdog_, &TempAuthKeyWatchdog::unregister_auth_key_id_impl, auth_key_id_);
    }

   private:
    ActorId<TempAuthKeyWatchdog> watchdog_;
    int64 auth_key_id_;
  };

 public:
  explicit TempAuthKeyWatchdog(ActorShared<> parent) : parent_(std::move(parent)) {
  }

  using RegisteredAuthKey = unique_ptr<RegisteredAuthKeyImpl>;

  static RegisteredAuthKey register_auth_key_id(int64 id) {
    send_closure(G()->temp_auth_key_watchdog(), &TempAuthKeyWatchdog::register_auth_key_id_impl, id);
    return make_unique<RegisteredAuthKeyImpl>(id);
  }

 private:
  static constexpr double SYNC_WAIT = 0.1;
  static constexpr double SYNC_WAIT_MAX = 1.0;

  ActorShared<> parent_;
  std::map<uint64, uint32> id_count_;
  double sync_at_ = 0;
  bool need_sync_ = false;
  bool run_sync_ = false;

  void register_auth_key_id_impl(int64 id) {
    LOG(INFO) << "Register key " << id;
    if (!++id_count_[id]) {
      id_count_.erase(id);
    }
    need_sync();
  }

  void unregister_auth_key_id_impl(int64 id) {
    LOG(INFO) << "Unregister key " << id;
    if (!--id_count_[id]) {
      id_count_.erase(id);
    }
    need_sync();
  }

  void need_sync() {
    need_sync_ = true;
    try_sync();
    LOG(DEBUG) << "Need sync temp auth keys";
  }

  void try_sync() {
    if (run_sync_ || !need_sync_) {
      return;
    }

    auto now = Time::now();
    if (sync_at_ == 0) {
      sync_at_ = now + SYNC_WAIT_MAX;
    }
    LOG(DEBUG) << "Set sync timeout";
    set_timeout_at(min(sync_at_, now + SYNC_WAIT));
  }

  void timeout_expired() final {
    LOG(DEBUG) << "Sync timeout expired";
    CHECK(!run_sync_);
    if (!need_sync_) {
      LOG(ERROR) << "Do not need sync..";
      return;
    }
    need_sync_ = false;
    run_sync_ = true;
    sync_at_ = 0;
    vector<int64> ids;
    for (auto &id_count : id_count_) {
      ids.push_back(id_count.first);
    }
    if (!G()->close_flag()) {
      LOG(WARNING) << "Start auth_dropTempAuthKeys except keys " << format::as_array(ids);
      auto query = G()->net_query_creator().create_unauth(telegram_api::auth_dropTempAuthKeys(std::move(ids)));
      G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this));
    }
  }

  void on_result(NetQueryPtr query) final {
    run_sync_ = false;
    if (query->is_error()) {
      if (G()->close_flag()) {
        return;
      }
      LOG(ERROR) << "Receive error for auth_dropTempAuthKeys: " << query->error();
      need_sync_ = true;
    } else {
      LOG(INFO) << "Receive OK for auth_dropTempAuthKeys";
    }
    try_sync();
  }
};

}  // namespace td