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;
}
|