/* * This file Copyright (C) 2016 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #pragma once #include #include #include #include #include #include #include #include "RpcClient.h" class RpcQueue : public QObject { Q_OBJECT public: explicit RpcQueue(QObject* parent = nullptr); void setTolerateErrors(bool tolerateErrors = true) { myTolerateErrors = tolerateErrors; } template void add(Func func) { myQueue.enqueue(qMakePair(normalizeFunc(func), ErrorHandlerFunction())); } template void add(Func func, ErrorHandler errorHandler) { myQueue.enqueue(qMakePair(normalizeFunc(func), normalizeErrorHandler(errorHandler))); } RpcResponseFuture future(); // The first function in queue is ran synchronously // (hence it may be e. g. a lambda capturing local variables by reference). void run(); private: // Internally queued function. Takes the last response future, makes a // request and returns a new response future. typedef std::function QueuedFunction; // Internally stored error handler function. Takes the last response future and returns nothing. typedef std::function ErrorHandlerFunction; private slots: void stepFinished(); private: void runNext(const RpcResponseFuture& response); // These overloads convert various forms of input closures to what we store internally. // normal closure, takes response and returns new future template::type, RpcResponseFuture>::value >::type* = nullptr> QueuedFunction normalizeFunc(const Func& func) { return [func](const RpcResponseFuture& r) { return func(r.result()); }; } // closure without argument (first step), takes nothing and returns new future template::type, RpcResponseFuture>::value >::type* = nullptr> QueuedFunction normalizeFunc(const Func& func) { return [func](const RpcResponseFuture&) { return func(); }; } // closure without return value ("auxiliary"), takes response and returns nothing -- internally we reuse the last future template::type, void>::value >::type* = nullptr> QueuedFunction normalizeFunc(const Func& func) { return [func](const RpcResponseFuture& r) { func(r.result()); return r; }; } // closure without argument and return value, takes nothing and returns nothing -- next function will also get nothing template::type, void>::value >::type* = nullptr> QueuedFunction normalizeFunc(const Func& func) { return [func](const RpcResponseFuture& r) { func(); return r; }; } // normal error handler, takes last response template::type, void>::value >::type* = nullptr> ErrorHandlerFunction normalizeErrorHandler(const Func& func) { return [func](const RpcResponseFuture& r) { func(r.result()); }; } // error handler without an argument, takes nothing template::type, void>::value >::type* = nullptr> ErrorHandlerFunction normalizeErrorHandler(const Func& func) { return [func](const RpcResponseFuture& r) { func(); }; } private: bool myTolerateErrors; QFutureInterface myPromise; QQueue> myQueue; ErrorHandlerFunction myNextErrorHandler; QFutureWatcher myFutureWatcher; };