aboutsummaryrefslogblamecommitdiffstats
path: root/src/main.cpp
blob: 42a642a8c14b8a8fbcbf54d893fc26228e60227e (plain) (tree)
1
2
3
4
5
6
7
8
                   

                        
 

                 

                              



                                                      
                                
                                                                                                                      

                       
                                                                                             


                                                 

                                   


                           

                                                                                                                        

                                                                                          








                                                                                                                        
 



                                                                                      
 




                                                                                                                        
 
            

                        
                          



                                                                                                

      


                                                                                                             
                        
                                   
                                                                
                                                                   
 

                                                       
 


                                                                                                       








                                                                                                                 
                                                                                                       



                                          


                                                     
                                                                                                                        
 



                                                                                              
 

                                                                                           
 


                                                                                                      
 



                                                                                                         
 
                                                                

 





























                                                                                                                      

                                                                                           
                
 

                                                                                     
 

                                                                                   
 

                                                                
 
                                                                                                                        
 


                                                                                         
 

                                                                   
 





                                                                                        
 











                                                                            
 




                                                                                           
                    

 
                                                                                                                
#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/