#include <iostream>
#include <functional>
#include <unordered_map>
#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<json(std::string const &arguments, std::string const &session, void *payload)> 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<json> &&annotations);
json create_response(std::vector<json> &&reply, std::string const &session = NULL_STRING, bool success = true);
/* ------------------------------------------------------------------------------------------------------------------ */
int main() {
crow::SimpleApp app;
// command --> handler
std::unordered_map<std::string, CommandHandler> 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<json> linkAnnotations;
linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::link, "Wikipedia")));
linkAnnotations.push_back(std::move(create_annotation(Reply::AnnotationType::underline)));
std::vector<json> 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<std::string, CommandHandler> *) payload;
std::vector<json> 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<json> 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<json> annotations;
annotations.push_back(std::move(create_annotation(Reply::AnnotationType::bold)));
std::vector<json> 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<json> 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<json> annotations;
annotations.push_back(std::move(create_annotation()));
return create_text(text, std::move(annotations));
}
json create_text(std::string const &text, std::vector<json> &&annotations) {
json reply(crow::json::type::Object);
reply["text"] = text;
reply["annotations"] = std::move(annotations);
return reply;
}
json create_response(std::vector<json> &&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/