tdlight/td/telegram/logevent/LogEvent.h

297 lines
7.8 KiB
C
Raw Normal View History

//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// 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/Version.h"
#include "td/utils/buffer.h"
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/Storer.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
#include "td/utils/tl_parsers.h"
#include "td/utils/tl_storers.h"
#include <type_traits>
namespace td {
namespace logevent {
template <class ParentT>
class WithVersion : public ParentT {
public:
using ParentT::ParentT;
void set_version(int32 version) {
version_ = version;
}
int32 version() const {
return version_;
}
private:
int32 version_{};
};
template <class ParentT, class ContextT>
class WithContext : public ParentT {
public:
using ParentT::ParentT;
void set_context(ContextT context) {
context_ = context;
}
ContextT context() const {
return context_;
}
private:
ContextT context_{};
};
class LogEvent {
public:
LogEvent() = default;
LogEvent(const LogEvent &) = delete;
LogEvent &operator=(const LogEvent &) = delete;
virtual ~LogEvent() = default;
enum HandlerType : uint32 {
SecretChats = 1,
Users = 2,
Chats = 3,
Channels = 4,
SecretChatInfos = 5,
WebPages = 0x10,
SendMessage = 0x100,
DeleteMessage = 0x101,
DeleteMessagesFromServer = 0x102,
ReadHistoryOnServer = 0x103,
ForwardMessages = 0x104,
ReadMessageContentsOnServer = 0x105,
SendBotStartMessage = 0x106,
SendScreenshotTakenNotificationMessage = 0x107,
SendInlineQueryResultMessage = 0x108,
DeleteDialogHistoryFromServer = 0x109,
ReadAllDialogMentionsOnServer = 0x10a,
DeleteAllChannelMessagesFromUserOnServer = 0x10b,
ToggleDialogIsPinnedOnServer = 0x10c,
ReorderPinnedDialogsOnServer = 0x10d,
SaveDialogDraftMessageOnServer = 0x10e,
UpdateDialogNotificationSettingsOnServer = 0x10f,
UpdateScopeNotificationSettingsOnServer = 0x110,
ResetAllNotificationSettingsOnServer = 0x111,
ChangeDialogReportSpamStateOnServer = 0x112,
GetDialogFromServer = 0x113,
ReadHistoryInSecretChat = 0x114,
ToggleDialogIsMarkedAsUnreadOnServer = 0x115,
GetChannelDifference = 0x140,
ConfigPmcMagic = 0x1f18,
BinlogPmcMagic = 0x4327
};
using Id = uint64;
Id logevent_id() const {
return logevent_id_;
}
void set_logevent_id(Id logevent_id) {
logevent_id_ = logevent_id;
}
virtual StringBuilder &print(StringBuilder &sb) const {
return sb << "[Logevent " << tag("id", logevent_id()) << "]";
}
private:
Id logevent_id_{};
};
inline StringBuilder &operator<<(StringBuilder &sb, const LogEvent &log_event) {
return log_event.print(sb);
}
namespace detail {
template <class EventT>
int32 magic(EventT &event) {
return static_cast<int32>(event.get_type());
}
template <class EventT, class StorerT>
void store(const EventT &event, StorerT &storer) {
EventT::downcast_call(event.get_type(),
[&](auto *ptr) { static_cast<const std::decay_t<decltype(*ptr)> &>(event).store(storer); });
}
template <class DestT, class T>
Result<unique_ptr<DestT>> from_parser(T &&parser) {
auto version = parser.fetch_int();
parser.set_version(version);
parser.set_context(G());
auto magic = static_cast<typename DestT::Type>(parser.fetch_int());
unique_ptr<DestT> event;
DestT::downcast_call(magic, [&](auto *ptr) {
auto tmp = make_unique<std::decay_t<decltype(*ptr)>>();
tmp->parse(parser);
event = std::move(tmp);
});
parser.fetch_end();
TRY_STATUS(parser.get_status());
if (event) {
return std::move(event);
}
return Status::Error(PSLICE() << "Unknown SecretChatEvent type: " << format::as_hex(magic));
}
template <class DestT>
Result<unique_ptr<DestT>> from_buffer_slice(BufferSlice slice) {
return from_parser<DestT>(WithVersion<WithContext<TlBufferParser, Global *>>{&slice});
}
template <class T>
class StorerImpl : public Storer {
public:
explicit StorerImpl(const T &event) : event_(event) {
}
size_t size() const override {
WithContext<TlStorerCalcLength, Global *> storer;
storer.set_context(G());
storer.store_int(T::version());
td::store(magic(event_), storer);
td::store(event_, storer);
return storer.get_length();
}
size_t store(uint8 *ptr) const override {
WithContext<TlStorerUnsafe, Global *> storer(ptr);
storer.set_context(G());
storer.store_int(T::version());
td::store(magic(event_), storer);
td::store(event_, storer);
return static_cast<size_t>(storer.get_buf() - ptr);
}
private:
const T &event_;
};
} // namespace detail
template <class ChildT>
class LogEventBase : public LogEvent {
public:
template <class StorerT>
void store(StorerT &storer) const {
detail::store(static_cast<const ChildT &>(*this), storer);
}
static Result<unique_ptr<ChildT>> from_buffer_slice(BufferSlice slice) {
return detail::from_buffer_slice<ChildT>(std::move(slice));
}
};
template <class ChildT, class ParentT>
class LogEventHelper : public ParentT {
public:
typename ParentT::Type get_type() const override {
return ChildT::type;
}
constexpr int32 magic() const {
return static_cast<int32>(get_type());
}
};
class LogEventParser : public WithVersion<WithContext<TlParser, Global *>> {
public:
explicit LogEventParser(Slice data) : WithVersion<WithContext<TlParser, Global *>>(data) {
set_version(fetch_int());
CHECK(version() < static_cast<int32>(Version::Next)) << "Wrong version " << version();
set_context(G());
}
};
class LogEventStorerCalcLength : public WithContext<TlStorerCalcLength, Global *> {
public:
LogEventStorerCalcLength() : WithContext<TlStorerCalcLength, Global *>() {
store_int(static_cast<int32>(Version::Next) - 1);
set_context(G());
}
};
class LogEventStorerUnsafe : public WithContext<TlStorerUnsafe, Global *> {
public:
explicit LogEventStorerUnsafe(unsigned char *buf) : WithContext<TlStorerUnsafe, Global *>(buf) {
store_int(static_cast<int32>(Version::Next) - 1);
set_context(G());
}
};
} // namespace logevent
using LogEvent = logevent::LogEvent;
using LogEventParser = logevent::LogEventParser;
using LogEventStorerCalcLength = logevent::LogEventStorerCalcLength;
using LogEventStorerUnsafe = logevent::LogEventStorerUnsafe;
template <class T>
Status log_event_parse(T &data, Slice slice) TD_WARN_UNUSED_RESULT;
template <class T>
Status log_event_parse(T &data, Slice slice) {
LogEventParser parser(slice);
parse(data, parser);
parser.fetch_end();
return parser.get_status();
}
template <class T>
class LogEventStorerImpl : public Storer {
public:
explicit LogEventStorerImpl(const T &event) : event_(event) {
}
size_t size() const override {
LogEventStorerCalcLength storer;
td::store(event_, storer);
return storer.get_length();
}
size_t store(uint8 *ptr) const override {
LogEventStorerUnsafe storer(ptr);
td::store(event_, storer);
#ifdef TD_DEBUG
T check_result;
log_event_parse(check_result, Slice(ptr, storer.get_buf())).ensure();
#endif
return static_cast<size_t>(storer.get_buf() - ptr);
}
private:
const T &event_;
};
template <class T>
BufferSlice log_event_store(const T &data) {
LogEventStorerCalcLength storer_calc_length;
store(data, storer_calc_length);
BufferSlice value_buffer{storer_calc_length.get_length()};
LogEventStorerUnsafe storer_unsafe(value_buffer.as_slice().ubegin());
store(data, storer_unsafe);
#ifdef TD_DEBUG
T check_result;
log_event_parse(check_result, value_buffer.as_slice()).ensure();
#endif
return value_buffer;
}
} // namespace td