575 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			575 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 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"
 | |
| 
 | |
| 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<RPCAbstractDoneHandler>;
 | |
| 
 | |
| class RPCAbstractFailHandler { // abstract fail
 | |
| public:
 | |
| 	virtual bool operator()(mtpRequestId requestId, const RPCError &e) = 0;
 | |
| 	virtual ~RPCAbstractFailHandler() {
 | |
| 	}
 | |
| };
 | |
| using RPCFailHandlerPtr = std::shared_ptr<RPCAbstractFailHandler>;
 | |
| 
 | |
| 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 <typename TReturn, typename TResponse>
 | |
| 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 <typename TReturn, typename TResponse>
 | |
| 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 <typename TReturn>
 | |
| 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 <typename TReturn>
 | |
| 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 = 0;
 | |
| 	int32 errorCode = 0;
 | |
| 
 | |
| };
 | |
| 
 | |
| 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 <typename TReturn, typename TResponse>
 | |
| inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &)) { // done(result)
 | |
| 	return RPCDoneHandlerPtr(new RPCDoneHandlerPlain<TReturn, TResponse>(onDone));
 | |
| }
 | |
| 
 | |
| template <typename TReturn, typename TResponse>
 | |
| inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(const TResponse &, mtpRequestId)) { // done(result, req_id)
 | |
| 	return RPCDoneHandlerPtr(new RPCDoneHandlerReq<TReturn, TResponse>(onDone));
 | |
| }
 | |
| 
 | |
| template <typename TReturn>
 | |
| inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)()) { // done()
 | |
| 	return RPCDoneHandlerPtr(new RPCDoneHandlerNo<TReturn>(onDone));
 | |
| }
 | |
| 
 | |
| template <typename TReturn>
 | |
| inline RPCDoneHandlerPtr rpcDone(TReturn (*onDone)(mtpRequestId)) { // done(req_id)
 | |
| 	return RPCDoneHandlerPtr(new RPCDoneHandlerNoReq<TReturn>(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));
 | |
| }
 | |
| 
 | |
| using MTPStateChangedHandler = void (*)(int32 dcId, int32 state);
 | |
| using MTPSessionResetHandler = void (*)(int32 dcId);
 | |
| 
 | |
| template <typename Base, typename FunctionType>
 | |
| class RPCHandlerImplementation : public Base {
 | |
| protected:
 | |
| 	using Lambda = FnMut<FunctionType>;
 | |
| 	using Parent = RPCHandlerImplementation<Base, FunctionType>;
 | |
| 
 | |
| public:
 | |
| 	RPCHandlerImplementation(Lambda handler) : _handler(std::move(handler)) {
 | |
| 	}
 | |
| 
 | |
| protected:
 | |
| 	Lambda _handler;
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename FunctionType>
 | |
| using RPCDoneHandlerImplementation = RPCHandlerImplementation<RPCAbstractDoneHandler, FunctionType>;
 | |
| 
 | |
| class RPCDoneHandlerImplementationBare : public RPCDoneHandlerImplementation<bool(const mtpPrime*, const mtpPrime*)> { // done(from, end)
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<bool(const mtpPrime*, const mtpPrime*)>::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<bool(const mtpPrime*, const mtpPrime*, mtpRequestId)> { // done(from, end, req_id)
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<bool(const mtpPrime*, const mtpPrime*, mtpRequestId)>::Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override {
 | |
| 		return this->_handler ? this->_handler(from, end, requestId) : true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename R, typename TResponse>
 | |
| class RPCDoneHandlerImplementationPlain : public RPCDoneHandlerImplementation<R(const TResponse&)> { // done(result)
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<R(const TResponse&)>::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 <typename R, typename TResponse>
 | |
| class RPCDoneHandlerImplementationReq : public RPCDoneHandlerImplementation<R(const TResponse&, mtpRequestId)> { // done(result, req_id)
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<R(const TResponse&, mtpRequestId)>::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 <typename R>
 | |
| class RPCDoneHandlerImplementationNo : public RPCDoneHandlerImplementation<R()> { // done()
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<R()>::Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override {
 | |
| 		if (this->_handler) {
 | |
| 			this->_handler();
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename R>
 | |
| class RPCDoneHandlerImplementationNoReq : public RPCDoneHandlerImplementation<R(mtpRequestId)> { // done(req_id)
 | |
| public:
 | |
| 	using RPCDoneHandlerImplementation<R(mtpRequestId)>::Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) override {
 | |
| 		if (this->_handler) {
 | |
| 			this->_handler(requestId);
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcDone_canCallBare_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, const mtpPrime*, const mtpPrime*>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcDone_canCallBareReq_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, const mtpPrime*, const mtpPrime*, mtpRequestId>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcDone_canCallNo_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcDone_canCallNoReq_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, mtpRequestId>;
 | |
| 
 | |
| template <typename Function>
 | |
| struct rpcDone_canCallPlain : std::false_type {
 | |
| };
 | |
| 
 | |
| template <typename Lambda, typename Return, typename T>
 | |
| struct rpcDone_canCallPlain<Return(Lambda::*)(const T&)> : std::true_type {
 | |
| 	using Arg = T;
 | |
| };
 | |
| 
 | |
| template <typename Lambda, typename Return, typename T>
 | |
| struct rpcDone_canCallPlain<Return(Lambda::*)(const T&)const>
 | |
| 	: rpcDone_canCallPlain<Return(Lambda::*)(const T&)> {
 | |
| };
 | |
| 
 | |
| template <typename Function>
 | |
| constexpr bool rpcDone_canCallPlain_v = rpcDone_canCallPlain<Function>::value;
 | |
| 
 | |
| template <typename Function>
 | |
| struct rpcDone_canCallReq : std::false_type {
 | |
| };
 | |
| 
 | |
| template <typename Lambda, typename Return, typename T>
 | |
| struct rpcDone_canCallReq<Return(Lambda::*)(const T&, mtpRequestId)> : std::true_type {
 | |
| 	using Arg = T;
 | |
| };
 | |
| 
 | |
| template <typename Lambda, typename Return, typename T>
 | |
| struct rpcDone_canCallReq<Return(Lambda::*)(const T&, mtpRequestId)const>
 | |
| 	: rpcDone_canCallReq<Return(Lambda::*)(const T&, mtpRequestId)> {
 | |
| };
 | |
| 
 | |
| template <typename Function>
 | |
| constexpr bool rpcDone_canCallReq_v = rpcDone_canCallReq<Function>::value;
 | |
| 
 | |
| template <typename Function>
 | |
| struct rpcDone_returnType;
 | |
| 
 | |
| template <typename Lambda, typename Return, typename ...Args>
 | |
| struct rpcDone_returnType<Return(Lambda::*)(Args...)> {
 | |
| 	using type = Return;
 | |
| };
 | |
| 
 | |
| template <typename Lambda, typename Return, typename ...Args>
 | |
| struct rpcDone_returnType<Return(Lambda::*)(Args...)const> {
 | |
| 	using type = Return;
 | |
| };
 | |
| 
 | |
| template <typename Function>
 | |
| using rpcDone_returnType_t = typename rpcDone_returnType<Function>::type;
 | |
| 
 | |
| template <
 | |
| 	typename Lambda,
 | |
| 	typename Function = crl::deduced_call_type<Lambda>>
 | |
| RPCDoneHandlerPtr rpcDone(Lambda lambda) {
 | |
| 	using R = rpcDone_returnType_t<Function>;
 | |
| 	if constexpr (rpcDone_canCallBare_v<Lambda>) {
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBare(std::move(lambda)));
 | |
| 	} else if constexpr (rpcDone_canCallBareReq_v<Lambda>) {
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationBareReq(std::move(lambda)));
 | |
| 	} else if constexpr (rpcDone_canCallNo_v<Lambda>) {
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNo<R>(std::move(lambda)));
 | |
| 	} else if constexpr (rpcDone_canCallNoReq_v<Lambda>) {
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationNoReq<R>(std::move(lambda)));
 | |
| 	} else if constexpr (rpcDone_canCallPlain_v<Function>) {
 | |
| 		using T = typename rpcDone_canCallPlain<Function>::Arg;
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationPlain<R, T>(std::move(lambda)));
 | |
| 	} else if constexpr (rpcDone_canCallReq_v<Function>) {
 | |
| 		using T = typename rpcDone_canCallReq<Function>::Arg;
 | |
| 		return RPCDoneHandlerPtr(new RPCDoneHandlerImplementationReq<R, T>(std::move(lambda)));
 | |
| 	} else {
 | |
| 		static_assert(false_t(lambda), "Unknown method.");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| template <typename FunctionType>
 | |
| using RPCFailHandlerImplementation = RPCHandlerImplementation<RPCAbstractFailHandler, FunctionType>;
 | |
| 
 | |
| class RPCFailHandlerImplementationPlain : public RPCFailHandlerImplementation<bool(const RPCError&)> { // fail(error)
 | |
| public:
 | |
| 	using Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const RPCError &error) override {
 | |
| 		return _handler ? _handler(error) : true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| class RPCFailHandlerImplementationReq : public RPCFailHandlerImplementation<bool(const RPCError&, mtpRequestId)> { // 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<bool()> { // fail()
 | |
| public:
 | |
| 	using Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const RPCError &error) override {
 | |
| 		return this->_handler ? this->_handler() : true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| class RPCFailHandlerImplementationNoReq : public RPCFailHandlerImplementation<bool(mtpRequestId)> { // fail(req_id)
 | |
| public:
 | |
| 	using Parent::Parent;
 | |
| 	bool operator()(mtpRequestId requestId, const RPCError &error) override {
 | |
| 		return this->_handler ? this->_handler(requestId) : true;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcFail_canCallNo_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcFail_canCallNoReq_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, mtpRequestId>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcFail_canCallPlain_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, const RPCError&>;
 | |
| 
 | |
| template <typename Lambda>
 | |
| constexpr bool rpcFail_canCallReq_v = rpl::details::is_callable_plain_v<
 | |
| 	Lambda, const RPCError&, mtpRequestId>;
 | |
| 
 | |
| template <
 | |
| 	typename Lambda,
 | |
| 	typename Function = crl::deduced_call_type<Lambda>>
 | |
| RPCFailHandlerPtr rpcFail(Lambda lambda) {
 | |
| 	if constexpr (rpcFail_canCallNo_v<Lambda>) {
 | |
| 		return RPCFailHandlerPtr(new RPCFailHandlerImplementationNo(std::move(lambda)));
 | |
| 	} else if constexpr (rpcFail_canCallNoReq_v<Lambda>) {
 | |
| 		return RPCFailHandlerPtr(new RPCFailHandlerImplementationNoReq(std::move(lambda)));
 | |
| 	} else if constexpr (rpcFail_canCallPlain_v<Lambda>) {
 | |
| 		return RPCFailHandlerPtr(new RPCFailHandlerImplementationPlain(std::move(lambda)));
 | |
| 	} else if constexpr (rpcFail_canCallReq_v<Lambda>) {
 | |
| 		return RPCFailHandlerPtr(new RPCFailHandlerImplementationReq(std::move(lambda)));
 | |
| 	} else {
 | |
| 		static_assert(false_t(lambda), "Unknown method.");
 | |
| 	}
 | |
| }
 | 
