aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.cpp
blob: 42a642a8c14b8a8fbcbf54d893fc26228e60227e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#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/