Added basic blueprint support (registration and prefix)

This commit is contained in:
The-EDev 2021-07-05 12:14:31 +03:00
parent a8e55b7a09
commit c46af69f41
4 changed files with 153 additions and 4 deletions

View File

@ -73,6 +73,10 @@ else ()
target_compile_options(example_json_map PRIVATE "${compiler_options}") target_compile_options(example_json_map PRIVATE "${compiler_options}")
target_link_libraries(example_json_map PUBLIC ${REQUIRED_LIBRARIES}) target_link_libraries(example_json_map PUBLIC ${REQUIRED_LIBRARIES})
add_executable(example_blueprint example_blueprint.cpp)
target_compile_options(example_blueprint PRIVATE "${compiler_options}")
target_link_libraries(example_blueprint PUBLIC ${REQUIRED_LIBRARIES})
add_custom_command(OUTPUT example_chat.html add_custom_command(OUTPUT example_chat.html
COMMAND ${CMAKE_COMMAND} -E COMMAND ${CMAKE_COMMAND} -E
copy ${PROJECT_SOURCE_DIR}/example_chat.html ${CMAKE_CURRENT_BINARY_DIR}/example_chat.html copy ${PROJECT_SOURCE_DIR}/example_chat.html ${CMAKE_CURRENT_BINARY_DIR}/example_chat.html

View File

@ -0,0 +1,18 @@
#define CROW_MAIN
#include "crow.h"
int main()
{
crow::SimpleApp app;
crow::Blueprint bp("bp_prefix");
CROW_BP_ROUTE(app, bp, "/")
([]() {
return "Hello world!";
});
app.register_blueprint(bp);
app.port(18080).run();
}

View File

@ -24,8 +24,10 @@
#ifdef CROW_MSVC_WORKAROUND #ifdef CROW_MSVC_WORKAROUND
#define CROW_ROUTE(app, url) app.route_dynamic(url) #define CROW_ROUTE(app, url) app.route_dynamic(url)
#define CROW_BP_ROUTE(app, blueprint, url) app.route_dynamic(blueprint, url)
#else #else
#define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url) #define CROW_ROUTE(app, url) app.route<crow::black_magic::get_parameter_tag(url)>(url)
#define CROW_BP_ROUTE(app, blueprint, url) app.route<crow::black_magic::get_parameter_tag(url)>(blueprint, url)
#endif #endif
#define CROW_CATCHALL_ROUTE(app) app.catchall_route() #define CROW_CATCHALL_ROUTE(app) app.catchall_route()
@ -80,14 +82,28 @@ namespace crow
return router_.new_rule_dynamic(std::move(rule)); return router_.new_rule_dynamic(std::move(rule));
} }
///Create a dynamic route for a blueprint using a rule (**Use CROW_ROUTE instead**)
DynamicRule& route_dynamic(Blueprint& blueprint, std::string&& rule)
{
return blueprint.new_rule_dynamic(std::move(rule));
}
///Create a route using a rule (**Use CROW_ROUTE instead**) ///Create a route using a rule (**Use CROW_ROUTE instead**)
template <uint64_t Tag> template <uint64_t Tag>
auto route(std::string&& rule) auto route(std::string&& rule)
-> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type -> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
{ {//TODO process the blueprint
return router_.new_rule_tagged<Tag>(std::move(rule)); return router_.new_rule_tagged<Tag>(std::move(rule));
} }
///Create a route for a blueprint using a rule (**Use CROW_ROUTE instead**)
template <uint64_t Tag>
auto route(Blueprint& blueprint, std::string&& rule)
-> typename std::result_of<decltype(&Router::new_rule_tagged<Tag>)(Router, std::string&&)>::type
{
return blueprint.new_rule_tagged<Tag>(std::move(rule));
}
///Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**) ///Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**)
CatchallRule& catchall_route() CatchallRule& catchall_route()
{ {
@ -158,12 +174,21 @@ namespace crow
/// crow::LogLevel::Warning (2)<br> /// crow::LogLevel::Warning (2)<br>
/// crow::LogLevel::Error (3)<br> /// crow::LogLevel::Error (3)<br>
/// crow::LogLevel::Critical (4)<br> /// crow::LogLevel::Critical (4)<br>
self_t& loglevel(crow::LogLevel level) self_t& loglevel(LogLevel level)
{ {
crow::logger::setLogLevel(level); crow::logger::setLogLevel(level);
return *this; return *this;
} }
self_t& register_blueprint(Blueprint& blueprint)
{
if (blueprints_.empty() || std::find(blueprints_.begin(), blueprints_.end(), &blueprint) == blueprints_.end())
{
blueprints_.emplace_back(&blueprint);
}//TODO error throwing
return *this;
}
///Set a custom duration and function to run on every tick ///Set a custom duration and function to run on every tick
template <typename Duration, typename Func> template <typename Duration, typename Func>
self_t& tick(Duration d, Func f) { self_t& tick(Duration d, Func f) {
@ -191,7 +216,7 @@ namespace crow
///Go through the rules, upgrade them if possible, and add them to the list of rules ///Go through the rules, upgrade them if possible, and add them to the list of rules
void validate() void validate()
{ {
router_.validate(); router_.validate(blueprints_);
} }
///Notify anything using `wait_for_server_start()` to proceed ///Notify anything using `wait_for_server_start()` to proceed
@ -380,6 +405,8 @@ namespace crow
std::vector<int> signals_{SIGINT, SIGTERM}; std::vector<int> signals_{SIGINT, SIGTERM};
std::vector<Blueprint*> blueprints_;
bool server_started_{false}; bool server_started_{false};
std::condition_variable cv_started_; std::condition_variable cv_started_;
std::mutex start_mutex_; std::mutex start_mutex_;

View File

@ -1029,6 +1029,94 @@ namespace crow
std::vector<Node> nodes_; std::vector<Node> nodes_;
}; };
/// A blueprint can be considered a smaller section of a Crow app, specifically where the router is conecerned.
class Blueprint
{
public:
Blueprint()
{
}
Blueprint(const std::string& prefix):
prefix_(prefix){};
Blueprint(std::string&& prefix):
prefix_(prefix){};
/*
Blueprint(Blueprint& other)
{
prefix_ = std::move(other.prefix_);
all_rules_ = std::move(other.all_rules_);
}
Blueprint(const Blueprint& other)
{
prefix_ = other.prefix_;
all_rules_ = other.all_rules_;
}
*/
Blueprint(Blueprint&& value)
{
*this = std::move(value);
}
Blueprint& operator = (const Blueprint& value) = delete;
Blueprint& operator = (Blueprint&& value) noexcept
{
prefix_ = std::move(value.prefix_);
all_rules_ = std::move(value.all_rules_);
catchall_rule_ = std::move(value.catchall_rule_);
return *this;
}
bool operator == (const Blueprint& value)
{
return value.prefix() == prefix_;
}
bool operator != (const Blueprint& value)
{
return value.prefix() != prefix_;
}
std::string prefix() const
{
return prefix_;
}
DynamicRule& new_rule_dynamic(const std::string& rule)
{
std::string new_rule = '/' + prefix_ + rule;
auto ruleObject = new DynamicRule(new_rule);
all_rules_.emplace_back(ruleObject);
return *ruleObject;
}
template <uint64_t N>
typename black_magic::arguments<N>::type::template rebind<TaggedRule>& new_rule_tagged(const std::string& rule)
{
std::string new_rule = '/' + prefix_ + rule;
using RuleT = typename black_magic::arguments<N>::type::template rebind<TaggedRule>;
auto ruleObject = new RuleT(new_rule);
all_rules_.emplace_back(ruleObject);
return *ruleObject;
}
CatchallRule& catchall_rule()
{
return catchall_rule_;
}
private:
std::string prefix_;
std::vector<std::unique_ptr<BaseRule>> all_rules_;
CatchallRule catchall_rule_;
friend class Router;
};
/// Handles matching requests to existing rules and upgrade requests. /// Handles matching requests to existing rules and upgrade requests.
class Router class Router
@ -1088,8 +1176,20 @@ namespace crow
} }
void validate() void validate(std::vector<Blueprint*>& bp_list)
{ {
//Take all the routes from the registered blueprints and add them to `all_rules_` to be processed.
if (!(bp_list.empty()))
{
for (Blueprint* bp : bp_list)
{
for (auto& rule: bp->all_rules_)
{
all_rules_.push_back(std::move(rule));
}
}
}
for(auto& rule:all_rules_) for(auto& rule:all_rules_)
{ {
if (rule) if (rule)