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/Global.h"
10 #include "td/telegram/Version.h"
11 
12 #include "td/utils/buffer.h"
13 #include "td/utils/common.h"
14 #include "td/utils/format.h"
15 #include "td/utils/logging.h"
16 #include "td/utils/misc.h"
17 #include "td/utils/Slice.h"
18 #include "td/utils/Status.h"
19 #include "td/utils/StorerBase.h"
20 #include "td/utils/StringBuilder.h"
21 #include "td/utils/tl_helpers.h"
22 #include "td/utils/tl_parsers.h"
23 #include "td/utils/tl_storers.h"
24 
25 namespace td {
26 namespace log_event {
27 
28 template <class ParentT>
29 class WithVersion : public ParentT {
30  public:
31   using ParentT::ParentT;
set_version(int32 version)32   void set_version(int32 version) {
33     version_ = version;
34   }
version()35   int32 version() const {
36     return version_;
37   }
38 
39  private:
40   int32 version_{};
41 };
42 
43 template <class ParentT, class ContextT>
44 class WithContext : public ParentT {
45  public:
46   using ParentT::ParentT;
set_context(ContextT context)47   void set_context(ContextT context) {
48     context_ = context;
49   }
context()50   ContextT context() const {
51     return context_;
52   }
53 
54  private:
55   ContextT context_{};
56 };
57 
58 class LogEvent {
59  public:
60   LogEvent() = default;
61   LogEvent(const LogEvent &) = delete;
62   LogEvent &operator=(const LogEvent &) = delete;
63   virtual ~LogEvent() = default;
64   enum HandlerType : uint32 {
65     SecretChats = 1,
66     Users = 2,
67     Chats = 3,
68     Channels = 4,
69     SecretChatInfos = 5,
70     WebPages = 0x10,
71     SetPollAnswer = 0x20,
72     StopPoll = 0x21,
73     SendMessage = 0x100,
74     DeleteMessage = 0x101,
75     DeleteMessagesOnServer = 0x102,
76     ReadHistoryOnServer = 0x103,
77     ForwardMessages = 0x104,
78     ReadMessageContentsOnServer = 0x105,
79     SendBotStartMessage = 0x106,
80     SendScreenshotTakenNotificationMessage = 0x107,
81     SendInlineQueryResultMessage = 0x108,
82     DeleteDialogHistoryOnServer = 0x109,
83     ReadAllDialogMentionsOnServer = 0x10a,
84     DeleteAllChannelMessagesFromSenderOnServer = 0x10b,
85     ToggleDialogIsPinnedOnServer = 0x10c,
86     ReorderPinnedDialogsOnServer = 0x10d,
87     SaveDialogDraftMessageOnServer = 0x10e,
88     UpdateDialogNotificationSettingsOnServer = 0x10f,
89     UpdateScopeNotificationSettingsOnServer = 0x110,
90     ResetAllNotificationSettingsOnServer = 0x111,
91     ToggleDialogReportSpamStateOnServer = 0x112,
92     RegetDialog = 0x113,
93     ReadHistoryInSecretChat = 0x114,
94     ToggleDialogIsMarkedAsUnreadOnServer = 0x115,
95     SetDialogFolderIdOnServer = 0x116,
96     DeleteScheduledMessagesOnServer = 0x117,
97     ToggleDialogIsBlockedOnServer = 0x118,
98     ReadMessageThreadHistoryOnServer = 0x119,
99     BlockMessageSenderFromRepliesOnServer = 0x120,
100     UnpinAllDialogMessagesOnServer = 0x121,
101     DeleteAllCallMessagesOnServer = 0x122,
102     DeleteDialogMessagesByDateOnServer = 0x123,
103     GetChannelDifference = 0x140,
104     AddMessagePushNotification = 0x200,
105     EditMessagePushNotification = 0x201,
106     ConfigPmcMagic = 0x1f18,
107     BinlogPmcMagic = 0x4327
108   };
109 
110   using Id = uint64;
111 
log_event_id()112   Id log_event_id() const {
113     return log_event_id_;
114   }
set_log_event_id(Id log_event_id)115   void set_log_event_id(Id log_event_id) {
116     log_event_id_ = log_event_id;
117   }
118 
print(StringBuilder & sb)119   virtual StringBuilder &print(StringBuilder &sb) const {
120     return sb << "[Logevent " << tag("id", log_event_id()) << "]";
121   }
122 
123  private:
124   Id log_event_id_{};
125 };
126 
127 inline StringBuilder &operator<<(StringBuilder &sb, const LogEvent &log_event) {
128   return log_event.print(sb);
129 }
130 
131 class LogEventParser final : public WithVersion<WithContext<TlParser, Global *>> {
132  public:
LogEventParser(Slice data)133   explicit LogEventParser(Slice data) : WithVersion<WithContext<TlParser, Global *>>(data) {
134     set_version(fetch_int());
135     LOG_CHECK(version() < static_cast<int32>(Version::Next)) << "Wrong version " << version();
136     set_context(G());
137   }
138 };
139 
140 class LogEventStorerCalcLength final : public WithContext<TlStorerCalcLength, Global *> {
141  public:
LogEventStorerCalcLength()142   LogEventStorerCalcLength() : WithContext<TlStorerCalcLength, Global *>() {
143     store_int(static_cast<int32>(Version::Next) - 1);
144     set_context(G());
145   }
146 };
147 
148 class LogEventStorerUnsafe final : public WithContext<TlStorerUnsafe, Global *> {
149  public:
LogEventStorerUnsafe(unsigned char * buf)150   explicit LogEventStorerUnsafe(unsigned char *buf) : WithContext<TlStorerUnsafe, Global *>(buf) {
151     store_int(static_cast<int32>(Version::Next) - 1);
152     set_context(G());
153   }
154 };
155 
156 template <class T>
157 class LogEventStorerImpl final : public Storer {
158  public:
LogEventStorerImpl(const T & event)159   explicit LogEventStorerImpl(const T &event) : event_(event) {
160   }
161 
size()162   size_t size() const final {
163     LogEventStorerCalcLength storer;
164     td::store(event_, storer);
165     return storer.get_length();
166   }
store(uint8 * ptr)167   size_t store(uint8 *ptr) const final {
168     LogEventStorerUnsafe storer(ptr);
169     td::store(event_, storer);
170 #ifdef TD_DEBUG
171     T check_result;
172     log_event_parse(check_result, Slice(ptr, storer.get_buf())).ensure();
173 #endif
174     return static_cast<size_t>(storer.get_buf() - ptr);
175   }
176 
177  private:
178   const T &event_;
179 };
180 
181 }  // namespace log_event
182 
183 using LogEvent = log_event::LogEvent;
184 using LogEventParser = log_event::LogEventParser;
185 using LogEventStorerCalcLength = log_event::LogEventStorerCalcLength;
186 using LogEventStorerUnsafe = log_event::LogEventStorerUnsafe;
187 
188 template <class T>
189 Status log_event_parse(T &data, Slice slice) TD_WARN_UNUSED_RESULT;
190 
191 template <class T>
log_event_parse(T & data,Slice slice)192 Status log_event_parse(T &data, Slice slice) {
193   LogEventParser parser(slice);
194   parse(data, parser);
195   parser.fetch_end();
196   return parser.get_status();
197 }
198 
199 template <class T>
log_event_store(const T & data)200 BufferSlice log_event_store(const T &data) {
201   LogEventStorerCalcLength storer_calc_length;
202   store(data, storer_calc_length);
203 
204   BufferSlice value_buffer{storer_calc_length.get_length()};
205   auto ptr = value_buffer.as_slice().ubegin();
206   LOG_CHECK(is_aligned_pointer<4>(ptr)) << ptr;
207 
208   LogEventStorerUnsafe storer_unsafe(ptr);
209   store(data, storer_unsafe);
210 
211 #ifdef TD_DEBUG
212   T check_result;
213   log_event_parse(check_result, value_buffer.as_slice()).ensure();
214 #endif
215   return value_buffer;
216 }
217 
218 template <class T>
get_log_event_storer(const T & event)219 log_event::LogEventStorerImpl<T> get_log_event_storer(const T &event) {
220   return log_event::LogEventStorerImpl<T>(event);
221 }
222 
223 }  // namespace td
224