From b5b8de1b3005ff6c6e3659d32b851a85f6671d88 Mon Sep 17 00:00:00 2001 From: Niklas Halle Date: Sun, 23 Aug 2020 17:40:25 +0200 Subject: added some helper functions and a nice enum for annotation handling, as well as an more complex reply example (multi annotaion, link annotation --- CMakeLists.txt | 3 + README.md | 2 +- include/AnnotationTypes.hpp | 23 ++++++++ include/Enum2String.hpp | 15 +++++ src/Enum2String.cpp | 9 +++ src/main.cpp | 132 +++++++++++++++++++++++++++----------------- 6 files changed, 132 insertions(+), 52 deletions(-) create mode 100644 include/AnnotationTypes.hpp create mode 100644 include/Enum2String.hpp create mode 100644 src/Enum2String.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 53d1f7e..aeecbf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,12 @@ ENDIF () add_executable(${PROJECT_NAME} # Headers + include/AnnotationTypes.hpp + include/Enum2String.hpp # Sources src/main.cpp + src/Enum2String.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/README.md b/README.md index b5fd3d5..f1c42b1 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ The text should be printed as strikethrough. No extra content. The text should be printed as underline. No extra content. ##### `link` -The text should be formatted as a link. Extra content: the uri to link. \ No newline at end of file +The text should be formatted as a link. Extra content: the alt text for the uri - the uri should be the text itself, so that clients ignoring this annotation still show the real uri. \ No newline at end of file diff --git a/include/AnnotationTypes.hpp b/include/AnnotationTypes.hpp new file mode 100644 index 0000000..d61de08 --- /dev/null +++ b/include/AnnotationTypes.hpp @@ -0,0 +1,23 @@ +#if ( !defined(ANNOTATIONTYPES_HPP) || defined(GENERATE_ENUM_STRINGS) ) + +#if (!defined(GENERATE_ENUM_STRINGS)) +#define ANNOTATIONTYPES_HPP +#endif + +#include "Enum2String.hpp" + +/////////////////////////////// +// The enum declaration +/////////////////////////////// +namespace Reply { + BEGIN_ENUM(AnnotationType) { + DECL_ENUM_ELEMENT(none), + DECL_ENUM_ELEMENT(bold), + DECL_ENUM_ELEMENT(italics), + DECL_ENUM_ELEMENT(strikethrough), + DECL_ENUM_ELEMENT(underline), + DECL_ENUM_ELEMENT(link), + } END_ENUM(AnnotationType) +} + +#endif // (!defined(ANNOTATIONTYPES_HPP) || defined(GENERATE_ENUM_STRINGS)) \ No newline at end of file diff --git a/include/Enum2String.hpp b/include/Enum2String.hpp new file mode 100644 index 0000000..4992e0d --- /dev/null +++ b/include/Enum2String.hpp @@ -0,0 +1,15 @@ +#undef DECL_ENUM_ELEMENT +#undef BEGIN_ENUM +#undef END_ENUM + +#ifndef GENERATE_ENUM_STRINGS +#define DECL_ENUM_ELEMENT( element ) element +#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME +#define END_ENUM( ENUM_NAME ) ENUM_NAME; \ + std::string GetString##ENUM_NAME(enum tag##ENUM_NAME index); +#else +#define DECL_ENUM_ELEMENT( element ) #element + #define BEGIN_ENUM( ENUM_NAME ) std::string gs_##ENUM_NAME [] = + #define END_ENUM( ENUM_NAME ) ; std::string GetString##ENUM_NAME(\ + tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; } +#endif \ No newline at end of file diff --git a/src/Enum2String.cpp b/src/Enum2String.cpp new file mode 100644 index 0000000..e64b6ea --- /dev/null +++ b/src/Enum2String.cpp @@ -0,0 +1,9 @@ +/// The strings associated with the enums are generated here +///////////////////////////////////////////////////////////////////// +#include + +#include "AnnotationTypes.hpp" + +#define GENERATE_ENUM_STRINGS // Start string generation +#include "AnnotationTypes.hpp" +#undef GENERATE_ENUM_STRINGS // Stop string generation \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 627d3d0..c704f39 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,15 +4,17 @@ #include "crow.h" +#include "AnnotationTypes.hpp" + #define NULL_STRING std::string("null") #define EMPTY_STRING std::string("") #define NO_SUCH_COMMAND std::string("no_such_command") -typedef std::function handler_func; +typedef crow::json::wvalue json; +typedef std::function handler_func; struct CommandHandler { - [[nodiscard]] crow::json::wvalue exec(std::string const &arguments, std::string const &session) const { + [[nodiscard]] json exec(std::string const &arguments, std::string const &session) const { return func(arguments, session, payload); } @@ -20,18 +22,36 @@ struct CommandHandler { void *payload{nullptr}; }; -crow::json::wvalue stopHandler(std::string const &arguments, std::string const &session, void *payload); -crow::json::wvalue klingerHandler(std::string const &arguments, std::string const &session, void *payload); +/* ------------------------------------------------------------------------------------------------------------------ */ + +json stopHandler(std::string const &arguments, std::string const &session, void *payload); + +json wikiHandler(std::string const &arguments, std::string const &session, void *payload); + +json klingerHandler(std::string const &arguments, std::string const &session, void *payload); + +/* ------------------------------------------------------------------------------------------------------------------ */ + +json simple_response(std::string const &text, std::string const &session = NULL_STRING, bool success = true); -[[maybe_unused]] void decl_me_daddy(int not_an_int) { (void) not_an_int; } +json create_annotation(Reply::AnnotationType annotation = Reply::AnnotationType::none, + std::string const &extra = EMPTY_STRING); + +json create_text(std::string const &text); +json create_text(std::string const &text, std::vector &&annotations); + +json create_response(std::vector &&reply, std::string const &session = NULL_STRING, bool success = true); + +/* ------------------------------------------------------------------------------------------------------------------ */ int main() { crow::SimpleApp app; // command --> handler static std::unordered_map const commands{ - {"stop", {stopHandler, &app}}, - {"klinger", {klingerHandler}} + {"stop", {stopHandler, &app}}, + {"wiki", {wikiHandler}}, + {"klinger", {klingerHandler}}, }; CROW_ROUTE(app, "/") @@ -54,9 +74,7 @@ int main() { return crow::response{handler.exec(arguments, session)}; } - crow::json::wvalue response; - - return crow::response{"no such command!\n"}; + return crow::response{simple_response("No such command!", NULL_STRING, false)}; }); app.port(18080).multithreaded().run(); @@ -64,63 +82,75 @@ int main() { std::cout << "Stopped successfully" << std::endl; } -crow::json::wvalue klingerHandler(std::string const &arguments, std::string const &session, void *payload) { - (void)payload; - - using namespace crow::json; - - crow::json::wvalue response(type::Object); +/* ------------------------------------------------------------------------------------------------------------------ */ - std::vector reply_vec; - - std::vector annotation_vec; - - wvalue annotation(type::Object); - annotation["type"] = "none"; - annotation["extra"] = ""; - - annotation_vec.push_back(std::move(annotation)); +json klingerHandler(std::string const &arguments, std::string const &session, void *payload) { + (void) payload; + return simple_response("Bonjour!"); +} - wvalue reply(type::Object); - reply["text"] = "Bonjour!"; - reply["annotations"] = std::move(annotation_vec); +json wikiHandler(std::string const &arguments, std::string const &session, void *payload) { + (void) payload; - reply_vec.push_back(std::move(reply)); + std::vector linkAnnotations; + linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::link, "Wikipedia"))); + linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::underline))); - response["success"] = true; - response["session"] = NULL_STRING; - response["reply"] = std::move(reply_vec); + std::vector reply_vec; + reply_vec.push_back(std::move(create_text("Visit "))); + reply_vec.push_back(std::move(create_text("https://eo.wikipedia.org/", std::move(linkAnnotations)))); + reply_vec.push_back(std::move(create_text(" today!"))); - return response; + return create_response(std::move(reply_vec), session, true); } -crow::json::wvalue stopHandler(std::string const &arguments, std::string const &session, void *payload) { - auto app = (crow::SimpleApp*) payload; +json stopHandler(std::string const &arguments, std::string const &session, void *payload) { + auto app = (crow::SimpleApp *) payload; app->stop(); - using namespace crow::json; - crow::json::wvalue response(type::Object); + std::vector annotations; + annotations.push_back(std::move(create_annotation(Reply::AnnotationType::bold))); - std::vector reply_vec; + std::vector reply_vec; + reply_vec.push_back(std::move(create_text("stopped", std::move(annotations)))); - std::vector annotation_vec; + return create_response(std::move(reply_vec), session, true); +} - wvalue annotation(type::Object); - annotation["type"] = "bold"; - annotation["extra"] = ""; +/* ------------------------------------------------------------------------------------------------------------------ */ - annotation_vec.push_back(std::move(annotation)); +json simple_response(std::string const &text, std::string const &session, bool success) { + std::vector reply_vec; + reply_vec.push_back(std::move(create_text(text))); - wvalue reply(type::Object); - reply["text"] = "stopped."; - reply["annotations"] = std::move(annotation_vec); + return create_response(std::move(reply_vec), session, success); +} - reply_vec.push_back(std::move(reply)); +json create_annotation(Reply::AnnotationType annotationType, std::string const &extra) { + json annotation(crow::json::type::Object); + annotation["type"] = Reply::GetStringAnnotationType(annotationType); + annotation["extra"] = extra; + return annotation; +} - response["success"] = true; - response["session"] = NULL_STRING; - response["reply"] = std::move(reply_vec); +json create_text(std::string const &text) { + std::vector annotations; + annotations.push_back(std::move(create_annotation())); + return create_text(text, std::move(annotations)); +} + +json create_text(std::string const &text, std::vector &&annotations) { + json reply(crow::json::type::Object); + reply["text"] = text; + reply["annotations"] = std::move(annotations); + return reply; +} +json create_response(std::vector &&reply, std::string const &session, bool success) { + json response(crow::json::type::Object); + response["success"] = success; + response["session"] = session; + response["reply"] = std::move(reply); return response; } -- cgit v1.2.3-54-g00ecf