aboutsummaryrefslogtreecommitdiff
path: root/src/handler.cpp
blob: 56aea76963feba75d6065185abe1dcb91ac2e20c (plain)
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
#include <winsock2.h>

#include "handler.h"
#include "plugin.h"
#include "internal/convarproxy.h"

#define SLEEP_DURATION 5000

ServerHandler::ServerHandler(Plugin* plugin):
	plugin(plugin)
{
    this->Convar_Port = plugin->ConVar("southrpc_port", DEFAULT_PORT, FCVAR_ARCHIVE, "South RPC HTTP Port (requires restart, default: " DEFAULT_PORT ")");

    if (WSAStartup(MAKEWORD(2, 2), &this->wsaData) != 0) {
        spdlog::error("Failed to open Windows Socket");
        return;
    }

    if (LOBYTE(this->wsaData.wVersion) != 2 ||
        HIBYTE(this->wsaData.wVersion) != 2)
    {
        spdlog::error("Incorrect Winsock version loaded");
        WSACleanup();
        return;
    }

    spdlog::info("Initialized handler");

    this->init = true;

    /* execute_squirrel */
    this->register_callback(
        "methods",
        [this](rapidjson::MemoryPoolAllocator<>& allocator, rapidjson::Value& params) -> rapidjson::Value
        {
            rapidjson::Value method_list;
            method_list.SetArray();

            for (auto const& [key, val] : this->methods)
            {
                rapidjson::Value method_name;
                method_name.SetString(key.c_str(), key.size(), allocator);

                method_list.PushBack(method_name, allocator);
            }

            return method_list;
        }
    );

}

static DWORD WINAPI static_server_run(void* param)
{
    ServerHandler* server = (ServerHandler*)param;

    server->run();

    return 0;
}

void ServerHandler::start()
{
	if (!this->init || this->running)
		return;

    DWORD thread_id;
    this->thread = CreateThread(NULL, 0, static_server_run, (void*)this, 0, &thread_id);
}

void ServerHandler::stop()
{
    if (!this->thread)
        return;

    this->running = false;
    TerminateThread(this->thread, 0);
    this->thread = nullptr;
}

void ServerHandler::run()
{
	this->running = true;

    spdlog::info("Running Handler");

    // The engine won't have loaded convar data until after the entry
    spdlog::info("Waiting for engine to initialize");
    Sleep(SLEEP_DURATION);

    int port = this->Convar_Port->GetInt();
    RPCServer* server = new RPCServer(INADDR_ANY, port);

    if (server->get_http_server().get_socket() == -1)
    {
        spdlog::error("HTTP Server failed to start");
        return;
    }

    spdlog::info("Launched server on port {}", port);

    while (this->running)
    {
    	RPCRequest* request = server->receive_request();
        spdlog::debug("received request");
    	if (!request)
    		continue;

        std::string method_name = request->get_method();

        callback_list::const_iterator method_pos = this->methods.find(method_name);
        if (method_pos != this->methods.end())
        {
            spdlog::info("Invoked method '{}'", method_name);
            request->result(method_pos->second(request->get_allocator(), request->get_params()));
        }
        else
        {
            spdlog::error("Attempted to invoke unknown method '{}'", method_name);
            request->error(rapidjson::Value("Unknown method"));
        }

        delete request;
    }

    delete server;
}