/* This file is part of Telegram Desktop, the official desktop version of Telegram messaging app, see https://telegram.org Telegram Desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once #include class RPCError { public: RPCError(const MTPrpcError &error) : _code(error.c_rpc_error().verror_code.v) { QString text = qs(error.c_rpc_error().verror_message); if (_code < 0 || _code >= 500) { _type = qsl("INTERNAL_SERVER_ERROR"); _description = text; } else { auto m = QRegularExpression("^([A-Z0-9_]+)(: .*)?$", reMultiline).match(text); if (m.hasMatch()) { _type = m.captured(1); _description = m.captured(2).mid(2); } else { _type = qsl("CLIENT_BAD_RPC_ERROR"); _description = qsl("Bad rpc error received, text = '") + text + '\''; } } } int32 code() const { return _code; } const QString &type() const { return _type; } const QString &description() const { return _description; } enum { NoError, TimeoutError }; 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: virtual void 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; }; template class RPCDoneHandlerBare : public RPCAbstractDoneHandler { // done(from, end) using CallbackType = TReturn (*)(const mtpPrime *, const mtpPrime *); public: RPCDoneHandlerBare(CallbackType onDone) : _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_onDone)(from, end); } private: CallbackType _onDone; }; template class RPCDoneHandlerBareReq : public RPCAbstractDoneHandler { // done(from, end, req_id) using CallbackType = TReturn (*)(const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCDoneHandlerBareReq(CallbackType onDone) : _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); response.read(from, end); (*_onDone)(std::move(response)); } private: CallbackType _onDone; }; template class RPCDoneHandlerReq : public RPCAbstractDoneHandler { // done(result, req_id) using CallbackType = TReturn (*)(const TResponse &, mtpRequestId); public: RPCDoneHandlerReq(CallbackType onDone) : _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { auto response = TResponse(); response.read(from, end); (*_onDone)(std::move(response), requestId); } private: CallbackType _onDone; }; template class RPCDoneHandlerNo : public RPCAbstractDoneHandler { // done() using CallbackType = TReturn (*)(); public: RPCDoneHandlerNo(CallbackType onDone) : _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_onDone)(); } private: CallbackType _onDone; }; template class RPCDoneHandlerNoReq : public RPCAbstractDoneHandler { // done(req_id) using CallbackType = TReturn (*)(mtpRequestId); public: RPCDoneHandlerNoReq(CallbackType onDone) : _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { (*_onDone)(requestId); } 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 = 0, int32 code = RPCError::NoError) : requestId(id), errorCode(code) { } mtpRequestId requestId; int32 errorCode; }; using RPCCallbackClears = QVector ; template inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const mtpPrime *, const mtpPrime *)) { // done(from, end) return RPCDoneHandlerPtr(new RPCDoneHandlerBare(onDone)); } template inline RPCDoneHandlerPtr rpcDone(TReturn (*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 = TReturn (TReceiver::*)(const mtpPrime *, const mtpPrime *); public: RPCDoneHandlerBareOwned(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(from, end); } private: CallbackType _onDone; }; template class RPCDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(from, end, req_id) using CallbackType = TReturn (TReceiver::*)(const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCDoneHandlerBareOwnedReq(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(from, end, requestId); } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) { auto response = TResponse(); response.read(from, end); (static_cast(_owner)->*_onDone)(std::move(response)); } } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) { auto response = TResponse(); response.read(from, end); (static_cast(_owner)->*_onDone)(std::move(response), requestId); } } private: CallbackType _onDone; }; template class RPCDoneHandlerOwnedNo : public RPCOwnedDoneHandler { // done() using CallbackType = TReturn (TReceiver::*)(); public: RPCDoneHandlerOwnedNo(TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(); } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(requestId); } private: CallbackType _onDone; }; template class RPCBindedDoneHandlerBareOwned : public RPCOwnedDoneHandler { // done(b, from, end) using CallbackType = TReturn (TReceiver::*)(T, const mtpPrime *, const mtpPrime *); public: RPCBindedDoneHandlerBareOwned(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b, from, end); } private: CallbackType _onDone; T _b; }; template class RPCBindedDoneHandlerBareOwnedReq : public RPCOwnedDoneHandler { // done(b, from, end, req_id) using CallbackType = TReturn (TReceiver::*)(T, const mtpPrime *, const mtpPrime *, mtpRequestId); public: RPCBindedDoneHandlerBareOwnedReq(T b, TReceiver *receiver, CallbackType onDone) : RPCOwnedDoneHandler(receiver), _b(b), _onDone(onDone) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b, from, end, requestId); } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) { auto response = TResponse(); response.read(from, end); (static_cast(_owner)->*_onDone)(_b, std::move(response)); } } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) { auto response = TResponse(); response.read(from, end); (static_cast(_owner)->*_onDone)(_b, std::move(response), requestId); } } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b); } 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) { } void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (_owner) (static_cast(_owner)->*_onDone)(_b, requestId); } 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 { using DoneHandlers = QSet; DoneHandlers _rpcDoneHandlers; using FailHandlers = QSet; FailHandlers _rpcFailHandlers; void _rpcRegHandler(RPCOwnedDoneHandler *handler) { _rpcDoneHandlers.insert(handler); } void _rpcUnregHandler(RPCOwnedDoneHandler *handler) { _rpcDoneHandlers.remove(handler); } void _rpcRegHandler(RPCOwnedFailHandler *handler) { _rpcFailHandlers.insert(handler); } void _rpcUnregHandler(RPCOwnedFailHandler *handler) { _rpcFailHandlers.remove(handler); } friend class RPCOwnedDoneHandler; friend class RPCOwnedFailHandler; public: template // done(from, end) RPCDoneHandlerPtr rpcDone(TReturn (TReceiver::*onDone)(const mtpPrime *, const mtpPrime *)) { return RPCDoneHandlerPtr(new RPCDoneHandlerBareOwned(static_cast(this), onDone)); } template // done(from, end, req_id) RPCDoneHandlerPtr rpcDone(TReturn (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(TReturn (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(TReturn (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(); } } }; using MTPStateChangedHandler = void (*)(int32 dcId, int32 state); using MTPSessionResetHandler = void (*)(int32 dcId); template class RPCHandlerImplementation : public Base { protected: using Lambda = base::lambda_once; using Parent = RPCHandlerImplementation; public: RPCHandlerImplementation(Lambda handler) : _handler(std::move(handler)) { } protected: Lambda _handler; }; template using RPCDoneHandlerImplementation = RPCHandlerImplementation; template class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation { // done(from, end) public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return this->_handler ? this->_handler(from, end) : void(0); } }; template class RPCDoneHandlerImplementationBareReq : public RPCDoneHandlerImplementation { // done(from, end, req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { return this->_handler ? this->_handler(from, end, requestId) : void(0); } }; template class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation { // done(result) public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { auto response = TResponse(); response.read(from, end); this->_handler(std::move(response)); } } }; template class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation { // done(result, req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { auto response = TResponse(); response.read(from, end); this->_handler(std::move(response), requestId); } } }; template class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation { // done() public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { this->_handler(); } } }; template class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation { // done(req_id) public: using RPCDoneHandlerImplementation::Parent::Parent; void operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override { if (this->_handler) { this->_handler(requestId); } } }; 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 = base::lambda_call_type_t> 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 = base::lambda_call_type_t> 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."); } }