/* 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/timer.h" #include "mtproto/mtproto_response.h" #include "mtproto/mtproto_proxy_data.h" #include "mtproto/details/mtproto_serialized_request.h" #include namespace MTP { class Instance; class AuthKey; using AuthKeyPtr = std::shared_ptr; enum class DcType; namespace details { class Dcenter; class SessionPrivate; enum class TemporaryKeyType; enum class CreatingKeyType; struct SessionOptions { SessionOptions() = default; SessionOptions( const QString &systemLangCode, const QString &cloudLangCode, const QString &langPackName, const ProxyData &proxy, bool useIPv4, bool useIPv6, bool useHttp, bool useTcp); QString systemLangCode; QString cloudLangCode; QString langPackName; ProxyData proxy; bool useIPv4 = true; bool useIPv6 = true; bool useHttp = true; bool useTcp = true; }; class Session; class SessionData final { public: explicit SessionData(not_null creator) : _owner(creator) { } void notifyConnectionInited(const SessionOptions &options); void setOptions(SessionOptions options) { QWriteLocker locker(&_optionsLock); _options = options; } [[nodiscard]] SessionOptions options() const { QReadLocker locker(&_optionsLock); return _options; } not_null toSendMutex() { return &_toSendLock; } not_null haveSentMutex() { return &_haveSentLock; } not_null haveReceivedMutex() { return &_haveReceivedLock; } base::flat_map &toSendMap() { return _toSend; } base::flat_map &haveSentMap() { return _haveSent; } std::vector &haveReceivedMessages() { return _receivedMessages; } // SessionPrivate -> Session interface. void queueTryToReceive(); void queueNeedToResumeAndSend(); void queueConnectionStateChange(int newState); void queueResetDone(); void queueSendAnything(crl::time msCanWait = 0); [[nodiscard]] bool connectionInited() const; [[nodiscard]] AuthKeyPtr getPersistentKey() const; [[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const; [[nodiscard]] CreatingKeyType acquireKeyCreation(DcType type); [[nodiscard]] bool releaseKeyCreationOnDone( const AuthKeyPtr &temporaryKey, const AuthKeyPtr &persistentKeyUsedForBind); [[nodiscard]] bool releaseCdnKeyCreationOnDone( const AuthKeyPtr &temporaryKey); void releaseKeyCreationOnFail(); void destroyTemporaryKey(uint64 keyId); void detach(); private: template void withSession(Callback &&callback); Session *_owner = nullptr; mutable QMutex _ownerMutex; SessionOptions _options; mutable QReadWriteLock _optionsLock; base::flat_map _toSend; // map of request_id -> request, that is waiting to be sent QReadWriteLock _toSendLock; base::flat_map _haveSent; // map of msg_id -> request, that was sent QReadWriteLock _haveSentLock; std::vector _receivedMessages; // list of responses / updates that should be processed in the main thread QReadWriteLock _haveReceivedLock; }; class Session final : public QObject { public: // Main thread. Session( not_null instance, not_null thread, ShiftedDcId shiftedDcId, not_null dc); ~Session(); void start(); void reInitConnection(); void restart(); void refreshOptions(); void stop(); void kill(); void unpaused(); // Thread-safe. [[nodiscard]] ShiftedDcId getDcWithShift() const; [[nodiscard]] AuthKeyPtr getPersistentKey() const; [[nodiscard]] AuthKeyPtr getTemporaryKey(TemporaryKeyType type) const; [[nodiscard]] bool connectionInited() const; void sendPrepared( const SerializedRequest &request, crl::time msCanWait = 0); // SessionPrivate thread. [[nodiscard]] CreatingKeyType acquireKeyCreation(DcType type); [[nodiscard]] bool releaseKeyCreationOnDone( const AuthKeyPtr &temporaryKey, const AuthKeyPtr &persistentKeyUsedForBind); [[nodiscard]] bool releaseCdnKeyCreationOnDone(const AuthKeyPtr &temporaryKey); void releaseKeyCreationOnFail(); void destroyTemporaryKey(uint64 keyId); void notifyDcConnectionInited(); void ping(); void cancel(mtpRequestId requestId, mtpMsgId msgId); int requestState(mtpRequestId requestId) const; int getState() const; QString transport() const; void tryToReceive(); void needToResumeAndSend(); void connectionStateChange(int newState); void resetDone(); void sendAnything(crl::time msCanWait = 0); private: void watchDcKeyChanges(); void watchDcOptionsChanges(); void killConnection(); [[nodiscard]] bool releaseGenericKeyCreationOnDone( const AuthKeyPtr &temporaryKey, const AuthKeyPtr &persistentKeyUsedForBind); const not_null _instance; const ShiftedDcId _shiftedDcId = 0; const not_null _dc; const std::shared_ptr _data; const not_null _thread; SessionPrivate *_private = nullptr; bool _killed = false; bool _needToReceive = false; AuthKeyPtr _dcKeyForCheck; CreatingKeyType _myKeyCreation = CreatingKeyType(); crl::time _msSendCall = 0; crl::time _msWait = 0; bool _ping = false; base::Timer _sender; rpl::lifetime _lifetime; }; } // namespace details } // namespace MTP