/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/basic_types.h" #include "base/flat_set.h" #include "base/timer.h" #include #include #include #include #include namespace TdE2E { struct UserId { uint64 v = 0; friend inline constexpr auto operator<=>(UserId, UserId) = default; friend inline constexpr bool operator==(UserId, UserId) = default; }; struct PrivateKeyId { uint64 v = 0; }; struct CallId { uint64 v = 0; explicit operator bool() const { return v != 0; } }; struct PublicKey { uint64 a = 0; uint64 b = 0; uint64 c = 0; uint64 d = 0; }; struct ParticipantState { UserId id; PublicKey key; }; struct ParticipantsSet { base::flat_set list; friend inline bool operator==( const ParticipantsSet &, const ParticipantsSet &) = default; }; struct Block { QByteArray data; }; enum class CallFailure { Unknown, }; using EncryptionBuffer = std::vector; class EncryptDecrypt final : public std::enable_shared_from_this { public: [[nodiscard]] auto callback() -> Fn; void setCallId(CallId id); void clearCallId(CallId fromId); private: std::atomic _id = 0; }; class Call final { public: explicit Call(UserId myUserId); ~Call(); [[nodiscard]] PublicKey myKey() const; void joined(); void apply( int subchain, int indexAfterLast, const std::vector &blocks, bool fromShortPoll); struct SubchainRequest { int subchain = 0; int height = 0; }; [[nodiscard]] rpl::producer subchainRequests() const; void subchainBlocksRequestFinished(int subchain); [[nodiscard]] rpl::producer sendOutboundBlock() const; [[nodiscard]] std::optional failed() const; [[nodiscard]] rpl::producer failures() const; [[nodiscard]] QByteArray emojiHash() const; [[nodiscard]] rpl::producer emojiHashValue() const; [[nodiscard]] bool hasLastBlock0() const; void refreshLastBlock0(std::optional block); [[nodiscard]] Block makeJoinBlock(); [[nodiscard]] Block makeRemoveBlock(const base::flat_set &ids); [[nodiscard]] auto participantsSetValue() const -> rpl::producer; void registerEncryptDecrypt(std::shared_ptr object); [[nodiscard]] rpl::lifetime &lifetime(); private: static constexpr int kSubChainsCount = 2; struct SubChainState { base::Timer shortPollTimer; base::Timer waitingTimer; crl::time lastUpdate = 0; base::flat_map waiting; bool shortPolling = true; int height = 0; }; void setId(CallId id); void apply(int subchain, const Block &last); void fail(CallFailure reason); void checkForOutboundMessages(); void checkWaitingBlocks(int subchain, bool waited = false); void shortPoll(int subchain); [[nodiscard]] std::int64_t libId() const; CallId _id; UserId _myUserId; PrivateKeyId _myKeyId; PublicKey _myKey; std::optional _failure; rpl::event_stream _failures; std::shared_ptr _encryptDecrypt; SubChainState _subchains[kSubChainsCount]; rpl::event_stream _subchainRequests; rpl::event_stream _outboundBlocks; std::optional _lastBlock0; int _lastBlock0Height = 0; rpl::variable _participantsSet; rpl::variable _emojiHash; rpl::lifetime _lifetime; }; } // namespace TdE2E