/* 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/flat_set.h" #include "core/utils.h" #include class RPCError { public: RPCError(const MTPrpcError &error); int32 code() const { return _code; } const QString &type() const { return _type; } const QString &description() const { return _description; } enum { NoError, TimeoutError }; static RPCError Local(const QString &type, const QString &description) { return MTP_rpc_error( MTP_int(0), MTP_bytes( ("CLIENT_" + type + (description.length() ? (": " + description) : QString())).toUtf8())); } private: int32 _code; QString _type, _description; }; namespace MTP { inline bool isFloodError(const RPCError &error) { return error.type().startsWith(qstr("FLOOD_WAIT_")); } inline bool isTemporaryError(const RPCError &error) { return error.code() < 0 || error.code() >= 500 || isFloodError(error); } inline bool isDefaultHandledError(const RPCError &error) { return isTemporaryError(error); } } // namespace MTP class RPCAbstractDoneHandler { // abstract done public: [[nodiscard]] virtual bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) = 0; virtual ~RPCAbstractDoneHandler() { } }; using RPCDoneHandlerPtr = std::shared_ptr; class RPCAbstractFailHandler { // abstract fail public: virtual bool operator()(mtpRequestId requestId, const RPCError &e) = 0; virtual ~RPCAbstractFailHandler() { } }; using RPCFailHandlerPtr = std::shared_ptr; struct RPCResponseHandler { RPCResponseHandler() = default; RPCResponseHandler(RPCDoneHandlerPtr &&done, RPCFailHandlerPtr &&fail) : onDone(std::move(done)) , onFail(std::move(fail)) { } RPCDoneHandlerPtr onDone; RPCFailHandlerPtr onFail; }; class RPCDoneHandlerBare : public RPCAbstractDoneHandler { // done(from, end) using CallbackType = bool (*)(const mtpPrime *, const mtpPrime *); public: RPCDoneHandlerBare(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return (*_onDone)(from, end); } private: CallbackType _onDone; }; class RPCDoneHandlerBareReq : public RPCAbstractDoneHandler { // done(from, end, req_id) using CallbackType = bool (*)(const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCDoneHandlerBareReq(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return (*_onDone)(from, end, requestId); } private: CallbackType _onDone; }; template class RPCDoneHandlerPlain : public RPCAbstractDoneHandler { // done(result) using CallbackType = TReturn (*)(const TResponse &); public: RPCDoneHandlerPlain(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } (*_onDone)(std::move(response)); return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerReq : public RPCAbstractDoneHandler { // done(result, req_id) using CallbackType = TReturn (*)(const TResponse &, mtpRequestId); public: RPCDoneHandlerReq(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } (*_onDone)(std::move(response), requestId); return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerNo : public RPCAbstractDoneHandler { // done() using CallbackType = TReturn (*)(); public: RPCDoneHandlerNo(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_onDone)(); return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerNoReq : public RPCAbstractDoneHandler { // done(req_id) using CallbackType = TReturn (*)(mtpRequestId); public: RPCDoneHandlerNoReq(CallbackType onDone) : _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_onDone)(requestId); return true; } private: CallbackType _onDone; }; class RPCFailHandlerPlain : public RPCAbstractFailHandler { // fail(error) using CallbackType = bool (*)(const RPCError &); public: RPCFailHandlerPlain(CallbackType onFail) : _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return (*_onFail)(e); } private: CallbackType _onFail; }; class RPCFailHandlerReq : public RPCAbstractFailHandler { // fail(error, req_id) using CallbackType = bool (*)(const RPCError &, mtpRequestId); public: RPCFailHandlerReq(CallbackType onFail) : _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return (*_onFail)(e, requestId); } private: CallbackType _onFail; }; class RPCFailHandlerNo : public RPCAbstractFailHandler { // fail() using CallbackType = bool (*)(); public: RPCFailHandlerNo(CallbackType onFail) : _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return (*_onFail)(); } private: CallbackType _onFail; }; class RPCFailHandlerNoReq : public RPCAbstractFailHandler { // fail(req_id) using CallbackType = bool (*)(mtpRequestId); public: RPCFailHandlerNoReq(CallbackType onFail) : _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return (*_onFail)(requestId); } private: CallbackType _onFail; }; struct RPCCallbackClear { RPCCallbackClear(mtpRequestId id , int32 code = RPCError::NoError) : requestId(id) , errorCode(code) { } mtpRequestId requestId; int32 errorCode; }; inline RPCDoneHandlerPtr rpcDone(bool (*onDone)(const mtpPrime *, const mtpPrime *)) { // done(from, end) return RPCDoneHandlerPtr(new RPCDoneHandlerBare(onDone)); } inline RPCDoneHandlerPtr rpcDone(bool (*onDone)(const mtpPrime *, const mtpPrime *, mtpRequestId)) { // done(from, end, req_id) return RPCDoneHandlerPtr(new RPCDoneHandlerBareReq(onDone)); } template inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &)) { // done(result) return RPCDoneHandlerPtr(new RPCDoneHandlerPlain(onDone)); } template inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &, mtpRequestId)) { // done(result, req_id) return RPCDoneHandlerPtr(new RPCDoneHandlerReq(onDone)); } template inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)()) { // done() return RPCDoneHandlerPtr(new RPCDoneHandlerNo(onDone)); } template inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(mtpRequestId)) { // done(req_id) return RPCDoneHandlerPtr(new RPCDoneHandlerNoReq(onDone)); } inline RPCFailHandlerPtr rpcFail(bool (*onFail)(const RPCError &)) { // fail(error) return RPCFailHandlerPtr(new RPCFailHandlerPlain(onFail)); } inline RPCFailHandlerPtr rpcFail(bool (*onFail)(const RPCError &, mtpRequestId)) { // fail(error, req_id) return RPCFailHandlerPtr(new RPCFailHandlerReq(onFail)); } inline RPCFailHandlerPtr rpcFail(bool (*onFail)()) { // fail() return RPCFailHandlerPtr(new RPCFailHandlerNo(onFail)); } inline RPCFailHandlerPtr rpcFail(bool (*onFail)(mtpRequestId)) { // fail(req_id) return RPCFailHandlerPtr(new RPCFailHandlerNoReq(onFail)); } class RPCSender; class RPCOwnedDoneHandler : public RPCAbstractDoneHandler { // abstract done public: RPCOwnedDoneHandler(RPCSender *owner); void invalidate() { _owner = nullptr; } ~RPCOwnedDoneHandler(); protected: RPCSender *_owner = nullptr; }; class RPCOwnedFailHandler : public RPCAbstractFailHandler { // abstract fail public: RPCOwnedFailHandler(RPCSender *owner); void invalidate() { _owner = nullptr; } ~RPCOwnedFailHandler(); protected: RPCSender *_owner = nullptr; }; template class RPCDoneHandlerBareOwned : public RPCOwnedDoneHandler { // done(from, end) using CallbackType = bool (TReceiver::*)(const mtpPrime *, const mtpPrime *); public: RPCDoneHandlerBareOwned(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return _owner ? (static_cast(_owner)->*_onDone)(from, end) : true; } private: CallbackType _onDone; }; template class RPCDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(from, end, req_id) using CallbackType = bool (TReceiver::*)(const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCDoneHandlerBareOwnedReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return _owner ? (static_cast(_owner)->*_onDone)(from, end, requestId) : true; } private: CallbackType _onDone; }; template class RPCDoneHandlerOwned : public RPCOwnedDoneHandler { // done(result) using CallbackType = TReturn (TReceiver::*)(const TResponse &); public: RPCDoneHandlerOwned(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (_owner) { (static_cast(_owner)->*_onDone)(std::move(response)); } return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerOwnedReq : public RPCOwnedDoneHandler { // done(result, req_id) using CallbackType = TReturn (TReceiver::*)(const TResponse &, mtpRequestId); public: RPCDoneHandlerOwnedReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (_owner) { (static_cast(_owner)->*_onDone)(std::move(response), requestId); } return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerOwnedNo : public RPCOwnedDoneHandler { // done() using CallbackType = TReturn (TReceiver::*)(); public: RPCDoneHandlerOwnedNo(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(); return true; } private: CallbackType _onDone; }; template class RPCDoneHandlerOwnedNoReq : public RPCOwnedDoneHandler { // done(req_id) using CallbackType = TReturn (TReceiver::*)(mtpRequestId); public: RPCDoneHandlerOwnedNoReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(requestId); return true; } private: CallbackType _onDone; }; template class RPCBindedDoneHandlerBareOwned : public RPCOwnedDoneHandler { // done(b, from, end) using CallbackType = bool (TReceiver::*)(T, const mtpPrime *, const mtpPrime *); public: RPCBindedDoneHandlerBareOwned(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return _owner ? (static_cast(_owner)->*_onDone)(_b, from, end) : true; } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(b, from, end, req_id) using CallbackType = bool (TReceiver::*)(T, const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCBindedDoneHandlerBareOwnedReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return _owner ? (static_cast(_owner)->*_onDone)(_b, from, end, requestId) : true; } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerOwned : public RPCOwnedDoneHandler { // done(b, result) using CallbackType = TReturn (TReceiver::*)(T, const TResponse &); public: RPCBindedDoneHandlerOwned(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone), _b(b) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (_owner) { (static_cast(_owner)->*_onDone)(_b, std::move(response)); } return true; } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerOwnedReq : public RPCOwnedDoneHandler { // done(b, result, req_id) using CallbackType = TReturn (TReceiver::*)(T, const TResponse &, mtpRequestId); public: RPCBindedDoneHandlerOwnedReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone), _b(b) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (_owner) { (static_cast(_owner)->*_onDone)(_b, std::move(response), requestId); } return true; } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerOwnedNo : public RPCOwnedDoneHandler { // done(b) using CallbackType = TReturn (TReceiver::*)(T); public: RPCBindedDoneHandlerOwnedNo(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b); return true; } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerOwnedNoReq : public RPCOwnedDoneHandler { // done(b, req_id) using CallbackType = TReturn (TReceiver::*)(T, mtpRequestId); public: RPCBindedDoneHandlerOwnedNoReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b, requestId); return true; } private: CallbackType _onDone; T _b; }; template class RPCFailHandlerOwned : public RPCOwnedFailHandler { // fail(error) using CallbackType = bool (TReceiver::*)(const RPCError &); public: RPCFailHandlerOwned(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(e) : true; } private: CallbackType _onFail; }; template class RPCFailHandlerOwnedReq : public RPCOwnedFailHandler { // fail(error, req_id) using CallbackType = bool (TReceiver::*)(const RPCError &, mtpRequestId); public: RPCFailHandlerOwnedReq(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(e, requestId) : true; } private: CallbackType _onFail; }; template class RPCFailHandlerOwnedNo : public RPCOwnedFailHandler { // fail() using CallbackType = bool (TReceiver::*)(); public: RPCFailHandlerOwnedNo(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)() : true; } private: CallbackType _onFail; }; template class RPCFailHandlerOwnedNoReq : public RPCOwnedFailHandler { // fail(req_id) using CallbackType = bool (TReceiver::*)(mtpRequestId); public: RPCFailHandlerOwnedNoReq(TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(requestId) : true; } private: CallbackType _onFail; }; template class RPCBindedFailHandlerOwned : public RPCOwnedFailHandler { // fail(b, error) using CallbackType = bool (TReceiver::*)(T, const RPCError &); public: RPCBindedFailHandlerOwned(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail), _b(b) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(_b, e) : true; } private: CallbackType _onFail; T _b; }; template class RPCBindedFailHandlerOwnedReq : public RPCOwnedFailHandler { // fail(b, error, req_id) using CallbackType = bool (TReceiver::*)(T, const RPCError &, mtpRequestId); public: RPCBindedFailHandlerOwnedReq(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail), _b(b) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(_b, e, requestId) : true; } private: CallbackType _onFail; T _b; }; template class RPCBindedFailHandlerOwnedNo : public RPCOwnedFailHandler { // fail(b) using CallbackType = bool (TReceiver::*)(T); public: RPCBindedFailHandlerOwnedNo(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail), _b(b) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(_b) : true; } private: CallbackType _onFail; T _b; }; template class RPCBindedFailHandlerOwnedNoReq : public RPCOwnedFailHandler { // fail(b, req_id) using CallbackType = bool (TReceiver::*)(T, mtpRequestId); public: RPCBindedFailHandlerOwnedNoReq(T b, TReceiver *receiver, CallbackType onFail) : RPCOwnedFailHandler(receiver), _onFail(onFail), _b(b) { } bool operator()(mtpRequestId requestId, const RPCError &e) override { return _owner ? (static_cast(_owner)->*_onFail)(_b, requestId) : true; } private: CallbackType _onFail; T _b; }; class RPCSender { public: template // done(from, end) RPCDoneHandlerPtr rpcDone(bool (TReceiver::*onDone)(const mtpPrime *, const mtpPrime *)) { return RPCDoneHandlerPtr(new RPCDoneHandlerBareOwned(static_cast(this), onDone)); } template // done(from, end, req_id) RPCDoneHandlerPtr rpcDone(bool (TReceiver::*onDone)(const mtpPrime *, const mtpPrime *, mtpRequestId)) { return RPCDoneHandlerPtr(new RPCDoneHandlerBareOwnedReq(static_cast(this), onDone)); } template // done(result) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const TResponse &)) { return RPCDoneHandlerPtr(new RPCDoneHandlerOwned(static_cast(this), onDone)); } template // done(result, req_id) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const TResponse &, mtpRequestId)) { return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedReq(static_cast(this), onDone)); } template // done() RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)()) { return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedNo(static_cast(this), onDone)); } template // done(req_id) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(mtpRequestId)) { return RPCDoneHandlerPtr(new RPCDoneHandlerOwnedNoReq(static_cast(this), onDone)); } template // fail(error) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(const RPCError &)) { return RPCFailHandlerPtr(new RPCFailHandlerOwned(static_cast(this), onFail)); } template // fail(error, req_id) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(const RPCError &, mtpRequestId)) { return RPCFailHandlerPtr(new RPCFailHandlerOwnedReq(static_cast(this), onFail)); } template // fail() RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)()) { return RPCFailHandlerPtr(new RPCFailHandlerOwnedNo(static_cast(this), onFail)); } template // fail(req_id) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(mtpRequestId)) { return RPCFailHandlerPtr(new RPCFailHandlerOwnedNo(static_cast(this), onFail)); } template // done(b, from, end) RPCDoneHandlerPtr rpcDone(bool (TReceiver::*onDone)(T, const mtpPrime *, const mtpPrime *), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerBareOwned(b, static_cast(this), onDone)); } template // done(b, from, end, req_id) RPCDoneHandlerPtr rpcDone(bool (TReceiver::*onDone)(T, const mtpPrime *, const mtpPrime *, mtpRequestId), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerBareOwnedReq(b, static_cast(this), onDone)); } template // done(b, result) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const TResponse &), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwned(b, static_cast(this), onDone)); } template // done(b, result, req_id) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, const TResponse &, mtpRequestId), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedReq(b, static_cast(this), onDone)); } template // done(b) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedNo(b, static_cast(this), onDone)); } template // done(b, req_id) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(T, mtpRequestId), T b) { return RPCDoneHandlerPtr(new RPCBindedDoneHandlerOwnedNoReq(b, static_cast(this), onDone)); } template // fail(b, error) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, const RPCError &), T b) { return RPCFailHandlerPtr(new RPCBindedFailHandlerOwned(b, static_cast(this), onFail)); } template // fail(b, error, req_id) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, const RPCError &, mtpRequestId), T b) { return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedReq(b, static_cast(this), onFail)); } template // fail(b) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T), T b) { return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo(b, static_cast(this), onFail)); } template // fail(b, req_id) RPCFailHandlerPtr rpcFail(bool (TReceiver::*onFail)(T, mtpRequestId), T b) { return RPCFailHandlerPtr(new RPCBindedFailHandlerOwnedNo(b, static_cast(this), onFail)); } virtual void rpcClear() { rpcInvalidate(); } virtual ~RPCSender() { rpcInvalidate(); } protected: void rpcInvalidate() { for (auto handler : base::take(_rpcDoneHandlers)) { handler->invalidate(); } for (auto handler : base::take(_rpcFailHandlers)) { handler->invalidate(); } } private: base::flat_set _rpcDoneHandlers; base::flat_set _rpcFailHandlers; void rpcRegHandler(RPCOwnedDoneHandler *handler) { _rpcDoneHandlers.emplace(handler); } void rpcUnregHandler(RPCOwnedDoneHandler *handler) { _rpcDoneHandlers.remove(handler); } void rpcRegHandler(RPCOwnedFailHandler *handler) { _rpcFailHandlers.emplace(handler); } void rpcUnregHandler(RPCOwnedFailHandler *handler) { _rpcFailHandlers.remove(handler); } friend class RPCOwnedDoneHandler; friend class RPCOwnedFailHandler; }; using MTPStateChangedHandler = void (*)(int32 dcId, int32 state); using MTPSessionResetHandler = void (*)(int32 dcId); template class RPCHandlerImplementation : public Base { protected: using Lambda = FnMut; using Parent = RPCHandlerImplementation; public: RPCHandlerImplementation(Lambda handler) : _handler(std::move(handler)) { } protected: Lambda _handler; }; template using RPCDoneHandlerImplementation = RPCHandlerImplementation; class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation { // done(from, end) public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return this->_handler ? this->_handler(from, end) : true; } }; class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation { // done(from, end, req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return this->_handler ? this->_handler(from, end, requestId) : true; } }; template class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation { // done(result) public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (this->_handler) { this->_handler(std::move(response)); } return true; } }; template class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation { // done(result, req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); if (!response.read(from, end)) { return false; } if (this->_handler) { this->_handler(std::move(response), requestId); } return true; } }; template class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation { // done() public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { this->_handler(); } return true; } }; template class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation { // done(req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { this->_handler(requestId); } return true; } }; template constexpr bool rpcDone_canCallBare_v = rpl::details::is_callable_plain_v< Lambda, const mtpPrime*, const mtpPrime*>; template constexpr bool rpcDone_canCallBareReq_v = rpl::details::is_callable_plain_v< Lambda, const mtpPrime*, const mtpPrime*, mtpRequestId>; template constexpr bool rpcDone_canCallNo_v = rpl::details::is_callable_plain_v< Lambda>; template constexpr bool rpcDone_canCallNoReq_v = rpl::details::is_callable_plain_v< Lambda, mtpRequestId>; template struct rpcDone_canCallPlain : std::false_type { }; template struct rpcDone_canCallPlain : std::true_type { using Arg = T; }; template struct rpcDone_canCallPlain : rpcDone_canCallPlain { }; template constexpr bool rpcDone_canCallPlain_v = rpcDone_canCallPlain::value; template struct rpcDone_canCallReq : std::false_type { }; template struct rpcDone_canCallReq : std::true_type { using Arg = T; }; template struct rpcDone_canCallReq : rpcDone_canCallReq { }; template constexpr bool rpcDone_canCallReq_v = rpcDone_canCallReq::value; template struct rpcDone_returnType; template struct rpcDone_returnType { using type = Return; }; template struct rpcDone_returnType { using type = Return; }; template using rpcDone_returnType_t = typename rpcDone_returnType::type; template < typename Lambda, typename Function = crl::deduced_call_type> RPCDoneHandlerPtr rpcDone(Lambda lambda) { using R = rpcDone_returnType_t; if constexpr (rpcDone_canCallBare_v) { return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare(std::move(lambda))); } else if constexpr (rpcDone_canCallBareReq_v) { return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq(std::move(lambda))); } else if constexpr (rpcDone_canCallNo_v) { return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo(std::move(lambda))); } else if constexpr (rpcDone_canCallNoReq_v) { return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq(std::move(lambda))); } else if constexpr (rpcDone_canCallPlain_v) { using T = typename rpcDone_canCallPlain::Arg; return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain(std::move(lambda))); } else if constexpr (rpcDone_canCallReq_v) { using T = typename rpcDone_canCallReq::Arg; return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq(std::move(lambda))); } else { static_assert(false_t(lambda), "Unknown method."); } } template using RPCFailHandlerImplementation = RPCHandlerImplementation; class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation { // fail(error) public: using Parent::Parent; bool operator()(mtpRequestId requestId, const RPCError &error) override { return _handler ? _handler(error) : true; } }; class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation { // fail(error, req_id) public: using Parent::Parent; bool operator()(mtpRequestId requestId, const RPCError &error) override { return this->_handler ? this->_handler(error, requestId) : true; } }; class RPCFailHandlerImplementationNo : public RPCFailHandlerImplementation { // fail() public: using Parent::Parent; bool operator()(mtpRequestId requestId, const RPCError &error) override { return this->_handler ? this->_handler() : true; } }; class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation { // fail(req_id) public: using Parent::Parent; bool operator()(mtpRequestId requestId, const RPCError &error) override { return this->_handler ? this->_handler(requestId) : true; } }; template constexpr bool rpcFail_canCallNo_v = rpl::details::is_callable_plain_v< Lambda>; template constexpr bool rpcFail_canCallNoReq_v = rpl::details::is_callable_plain_v< Lambda, mtpRequestId>; template constexpr bool rpcFail_canCallPlain_v = rpl::details::is_callable_plain_v< Lambda, const RPCError&>; template constexpr bool rpcFail_canCallReq_v = rpl::details::is_callable_plain_v< Lambda, const RPCError&, mtpRequestId>; template < typename Lambda, typename Function = crl::deduced_call_type> RPCFailHandlerPtr rpcFail(Lambda lambda) { if constexpr (rpcFail_canCallNo_v) { return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std::move(lambda))); } else if constexpr (rpcFail_canCallNoReq_v) { return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std::move(lambda))); } else if constexpr (rpcFail_canCallPlain_v) { return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std::move(lambda))); } else if constexpr (rpcFail_canCallReq_v) { return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std::move(lambda))); } else { static_assert(false_t(lambda), "Unknown method."); } }