#include #include #include #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 crow::json::wvalue json; typedef std::function handler_function; struct CommandHandler { [[nodiscard]] json exec(std::string const &arguments, std::string const &session) const { return func(arguments, session, payload); } handler_function func{nullptr}; std::string description{""}; void *payload{nullptr}; }; /* ------------------------------------------------------------------------------------------------------------------ */ json helpHandler(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); 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 std::unordered_map commands{ {"stop", {.func = stopHandler, .description = "Stops the bot", .payload = &app}}, {"wiki", {.func = wikiHandler, .description = "Send you to wikipedia"}}, {"klinger", {.func = klingerHandler, .description = "Greats in french. Bonjour!"}}, }; commands.insert({"help", {.func = helpHandler, .description = "This is my holy manual.", .payload = &commands}}); CROW_ROUTE(app, "/") .methods("POST"_method) ([&commands](crow::request const &request) { auto data = crow::json::load(request.body); if (!data) return crow::response(400); if (!data.count("command")) return crow::response(400, "malformed request: missing `command` field\n"); std::string command = (data.count("command") ? data["command"].s() : NO_SUCH_COMMAND); std::string arguments = (data.count("arguments") ? data["arguments"].s() : EMPTY_STRING); std::string session = (data.count("session") ? data["session"].s() : NULL_STRING); if (auto itor = commands.find(command); itor != commands.end()) { auto handler = itor->second; return crow::response{handler.exec(arguments, session)}; } return crow::response{simple_response("No such command!", NULL_STRING, false)}; }); app.port(18080).multithreaded().run(); std::cout << "Stopped successfully" << std::endl; } /* ------------------------------------------------------------------------------------------------------------------ */ json klingerHandler(std::string const &arguments, std::string const &session, void *payload) { (void) payload; return simple_response("Bonjour!"); } json wikiHandler(std::string const &arguments, std::string const &session, void *payload) { (void) payload; std::vector linkAnnotations; linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::link, "Wikipedia"))); linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::underline))); 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 create_response(std::move(reply_vec), session, true); } json helpHandler(std::string const &arguments, std::string const &session, void *payload) { auto commands = *(std::unordered_map *) payload; std::vector reply_vec; reply_vec.push_back(std::move(create_text( "Reading from the gospel according to saint N,\n" "And you shall feast upon the animals intestines as I do in the offering for they will make you strong.\n" "\n" "Dear my fellow users, these are my official commands, which are offered to my believers.\n" "\n"))); for (auto const &itor : commands) { std::vector commandAnnotations; commandAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::italics))); commandAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::underline))); reply_vec.push_back(std::move(create_text("- "))); reply_vec.push_back(std::move(create_text(itor.first, std::move(commandAnnotations)))); reply_vec.push_back(std::move(create_text(" " + itor.second.description + "\n"))); } reply_vec.push_back(std::move(create_text( "\n" "Thanks for using me. Takk skal du ha.\n" "Bussy\n" "N"))); return create_response(std::move(reply_vec), session, true); } json stopHandler(std::string const &arguments, std::string const &session, void *payload) { auto app = (crow::SimpleApp *) payload; app->stop(); std::vector annotations; annotations.push_back(std::move(create_annotation(Reply::AnnotationType::bold))); std::vector reply_vec; reply_vec.push_back(std::move(create_text("stopped", std::move(annotations)))); return create_response(std::move(reply_vec), session, true); } /* ------------------------------------------------------------------------------------------------------------------ */ 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))); return create_response(std::move(reply_vec), session, success); } 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; } 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; } // curl -d '{"command":"klinger", "b":"12"}' -H "Content-Type: application/json" -X POST http://localhost:18080/