Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middleware.h #403

Open
AlexSteinerETH opened this issue Feb 17, 2022 · 2 comments
Open

Middleware.h #403

AlexSteinerETH opened this issue Feb 17, 2022 · 2 comments

Comments

@AlexSteinerETH
Copy link

AlexSteinerETH commented Feb 17, 2022

Hi when i run my script i got this error:

/usr/local/include/crow/middleware.h: In instantiation of ‘typename std::enable_if<crow::black_magic::is_callable<F, crow::request, Args ...>::value>::type crow::detail::wrapped_handler_call(crow::request&, crow::response&, const F&, Args&& ...) [with F = main()::<lambda(const crow::request&)>; Args = {}; typename std::enable_if<crow::black_magic::is_callable<F, crow::request, Args ...>::value>::type = void]’:
/usr/local/include/crow/routing.h:583:47:   required from ‘void crow::TaggedRule<Args>::operator()(Func&&) [with Func = main()::<lambda(const crow::request&)>; Args = {}]’
Run.cpp:55:6:   required from here
/usr/local/include/crow/middleware.h:238:27: error: static assertion failed: Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable
  238 |             static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
      |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/crow/middleware.h:241:25: error: invalid use of void expression
  241 |             res = crow::response(f(req, std::forward<Args>(args)...));
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

My code:

#include <iostream>
#include <ctime>
#include <list>


#include <crow.h>

#include "Wallets/Wallets.hpp"
#include "Headers/json.hpp"

using namespace std;
using namespace crow;

Wallets wallets;


int main()
{
    SimpleApp server;

    CROW_ROUTE(server, "/")([]() {
        mustache::context ctx;
        auto main_page = mustache::load("index.html");
        return main_page.render();
    });

    CROW_ROUTE(server, "/wallet").methods("GET"_method)([](const crow::request& req) {
        auto main_page = mustache::load("add_wallet.html");
        return main_page.render();
    });

    CROW_ROUTE(server, "/create-wallet").methods("POST"_method)([](const crow::request& req) {
        cout << endl;

        const Wallet& newWallet = wallets.CreateWallet();

        cout << endl;

        crow::json::wvalue x({{}});
        x["Hash"] = newWallet.wallet_hash;
        x["Phrase"] = newWallet.secret_phrase;

        auto main_page = mustache::load("successfully_wallet_created.html");
        return main_page.render(x);
    });

    CROW_ROUTE(server, "/login").methods("GET"_method)([](const crow::request& req) {
        auto main_page = mustache::load("login_wallet.html");
        return main_page.render();
    });

    
    CROW_ROUTE(server, "/login-wallet").methods("POST"_method)([](const crow::request& req) {
        cout << req.url_params.get("hash") << endl;
    });


    server.port(8080).multithreaded().run();
}

I USE UBUNTU AND I RUN THE CODE WITH :

 #Delete the previous run
rm Run

#Run the server
g++ -std=c++11 Run.cpp -o Run -L /usr/lib/ -lboost_system -lboost_thread -lpthread -ggdb -lz -D CROW_ENABLE_DEBUG $(pkg-config --cflags --libs libmongocxx)

#clear

./Run


Middleware.h


#include "crow/http_request.h"
#include "crow/http_response.h"
#include "crow/utility.h"

#include <tuple>
#include <type_traits>
#include <iostream>
#include <utility>

namespace crow
{

    /// Local middleware should extend ILocalMiddleware
    struct ILocalMiddleware
    {
        using call_global = std::false_type;
    };

    namespace detail
    {
        template<typename MW>
        struct check_before_handle_arity_3_const
        {
            template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::before_handle>
            struct get
            {};
        };

        template<typename MW>
        struct check_before_handle_arity_3
        {
            template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::before_handle>
            struct get
            {};
        };

        template<typename MW>
        struct check_after_handle_arity_3_const
        {
            template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::after_handle>
            struct get
            {};
        };

        template<typename MW>
        struct check_after_handle_arity_3
        {
            template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::after_handle>
            struct get
            {};
        };

        template<typename MW>
        struct check_global_call_false
        {
            template<typename T, typename std::enable_if<T::call_global::value == false, bool>::type = true>
            struct get
            {};
        };

        template<typename T>
        struct is_before_handle_arity_3_impl
        {
            template<typename C>
            static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);

            template<typename C>
            static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);

            template<typename C>
            static std::false_type f(...);

        public:
            static const bool value = decltype(f<T>(nullptr))::value;
        };

        template<typename T>
        struct is_after_handle_arity_3_impl
        {
            template<typename C>
            static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*);

            template<typename C>
            static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*);

            template<typename C>
            static std::false_type f(...);

        public:
            static constexpr bool value = decltype(f<T>(nullptr))::value;
        };

        template<typename MW, typename Context, typename ParentContext>
        typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
          before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
        {
            mw.before_handle(req, res, ctx.template get<MW>(), ctx);
        }

        template<typename MW, typename Context, typename ParentContext>
        typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
          before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
        {
            mw.before_handle(req, res, ctx.template get<MW>());
        }

        template<typename MW, typename Context, typename ParentContext>
        typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
          after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
        {
            mw.after_handle(req, res, ctx.template get<MW>(), ctx);
        }

        template<typename MW, typename Context, typename ParentContext>
        typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
          after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
        {
            mw.after_handle(req, res, ctx.template get<MW>());
        }


        template<template<typename QueryMW> class CallCriteria, // Checks if QueryMW should be called in this context
                 int N, typename Context, typename Container>
        typename std::enable_if<(N < std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
          middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
        {

            using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;

            if (!CallCriteria<CurrentMW>::value)
            {
                return middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx);
            }

            using parent_context_t = typename Context::template partial<N - 1>;
            before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
            if (res.is_completed())
            {
                after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                return true;
            }

            if (middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx))
            {
                after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                return true;
            }

            return false;
        }

        template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
        typename std::enable_if<(N >= std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
          middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
        {
            return false;
        }

        template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
        typename std::enable_if<(N < 0)>::type
          after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
        {
        }

        template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
        typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
        {
            using parent_context_t = typename Context::template partial<N - 1>;
            using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
            if (CallCriteria<CurrentMW>::value)
            {
                after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
            }
        }

        template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
        typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res)
        {
            using parent_context_t = typename Context::template partial<N - 1>;
            using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
            if (CallCriteria<CurrentMW>::value)
            {
                after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
            }
            after_handlers_call_helper<CallCriteria, N - 1, Context, Container>(middlewares, ctx, req, res);
        }

        // A CallCriteria that accepts only global middleware
        template<typename MW>
        struct middleware_call_criteria_only_global
        {
            template<typename C>
            static std::false_type f(typename check_global_call_false<MW>::template get<C>*);

            template<typename C>
            static std::true_type f(...);

            static const bool value = decltype(f<MW>(nullptr))::value;
        };

        // wrapped_handler_call transparently wraps a handler call behind (req, res, args...)
        template<typename F, typename... Args>
        typename std::enable_if<black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
          wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
        {
            static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                          "Handler function with response argument should have void return type");

            f(req, res, std::forward<Args>(args)...);
        }

        template<typename F, typename... Args>
        typename std::enable_if<black_magic::is_callable<F, crow::request&, crow::response&, Args...>::value && !black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
          wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
        {
            static_assert(std::is_same<void, decltype(f(std::declval<crow::request&>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                          "Handler function with response argument should have void return type");

            f(req, res, std::forward<Args>(args)...);
        }

        template<typename F, typename... Args>
        typename std::enable_if<black_magic::is_callable<F, crow::response&, Args...>::value>::type
          wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
        {
            static_assert(std::is_same<void, decltype(f(std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                          "Handler function with response argument should have void return type");

            f(res, std::forward<Args>(args)...);
        }

        template<typename F, typename... Args>
        typename std::enable_if<black_magic::is_callable<F, crow::request, Args...>::value>::type
          wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
        {
            static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
                          "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");

            res = crow::response(f(req, std::forward<Args>(args)...));
            res.end();
        }

        template<typename F, typename... Args>
        typename std::enable_if<black_magic::is_callable<F, Args...>::value>::type
          wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
        {
            static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
                          "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");

            res = crow::response(f(std::forward<Args>(args)...));
            res.end();
        }

        template<typename F, typename App, typename... Middlewares>
        struct handler_middleware_wrapper
        {
            // CallCriteria bound to the current Middlewares pack
            template<typename MW>
            struct middleware_call_criteria
            {
                static constexpr bool value = black_magic::has_type<MW, std::tuple<Middlewares...>>::value;
            };

            template<typename... Args>
            void operator()(crow::request& req, crow::response& res, Args&&... args) const
            {
                auto& ctx = *reinterpret_cast<typename App::context_t*>(req.middleware_context);
                auto& container = *reinterpret_cast<typename App::mw_container_t*>(req.middleware_container);

                auto glob_completion_handler = std::move(res.complete_request_handler_);
                res.complete_request_handler_ = [] {};

                middleware_call_helper<middleware_call_criteria,
                                       0, typename App::context_t, typename App::mw_container_t>(container, req, res, ctx);

                if (res.completed_)
                {
                    glob_completion_handler();
                    return;
                }

                res.complete_request_handler_ = [&ctx, &container, &req, &res, &glob_completion_handler] {
                    after_handlers_call_helper<
                      middleware_call_criteria,
                      std::tuple_size<typename App::mw_container_t>::value - 1,
                      typename App::context_t,
                      typename App::mw_container_t>(container, ctx, req, res);
                    glob_completion_handler();
                };

                wrapped_handler_call(req, res, f, std::forward<Args>(args)...);
            }

            F f;
        };

        template<typename Route, typename App, typename... Middlewares>
        struct handler_call_bridge
        {
            template<typename MW>
            using check_app_contains = typename black_magic::has_type<MW, typename App::mw_container_t>;

            static_assert(black_magic::all_true<(std::is_base_of<crow::ILocalMiddleware, Middlewares>::value)...>::value,
                          "Local middleware has to inherit crow::ILocalMiddleware");

            static_assert(black_magic::all_true<(check_app_contains<Middlewares>::value)...>::value,
                          "Local middleware has to be listed in app middleware");

            template<typename F>
            void operator()(F&& f) const
            {
                auto wrapped = handler_middleware_wrapper<F, App, Middlewares...>{std::forward<F>(f)};
                tptr->operator()(std::move(wrapped));
            }

            Route* tptr;
        };

    } // namespace detail
} // namespace crow
@The-EDev
Copy link

The-EDev commented Feb 17, 2022

it seems like you're using this version of Crow. This is the old repository and hasn't been active in over 4 years.

Edit: yes the middleware.h file you posted is part of CrowCpp/Crow. Feel free to open an issue there.

@AlexSteinerETH
Copy link
Author

Ok i did it

GerHobbelt pushed a commit to GerHobbelt/crow that referenced this issue Aug 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants