-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
133 lines (109 loc) · 3.97 KB
/
main.cpp
File metadata and controls
133 lines (109 loc) · 3.97 KB
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
#include<server.hpp>
#include<filehandle.hpp>
#include <csignal>
#include <cstdlib>
#include <atomic>
// Global shutdown flag — set by signal handler, checked by cleanup ──
static std::atomic<bool> g_shutdown{false};
// Global pointers for signal handler access (signal handlers can't use locals)
static Server* g_server = nullptr;
static FileHandler* g_ft = nullptr;
// Signal handler
void handle_exit(int signum) {
bool expected = false;
if (!g_shutdown.compare_exchange_strong(expected, true)) {
return;
}
// Close the listening socket — this breaks the accept() loop
if (g_server) {
g_server->shutdown();
}
// Clear file caches (releases preloaded memory)
if (g_ft) {
g_ft->clear();
}
WSACleanup();
std::exit(0);
}
int main(){
Router router = Router();
Server server(3000, router);
FileHandler ft;
g_server = &server;
g_ft = &ft;
// Register signal handlers BEFORE starting the server
// server.start() is blocking — if we register after, signals won't work.
std::signal(SIGINT, handle_exit);
std::signal(SIGTERM, handle_exit);
// Preload static files into memory at startup
ft.preloadFiles({
"site/index.html",
"site/about.html",
"site/neon.css",
"site/app.js",
"site/assets/hero.jpg",
"favicon.ico"
}, {
false, // text
false, // text
false, // text
false, // text
true, // binary
true // binary
});
router.addRoute("/",HttpMethod::GET, [&](const HttpRequest& req){
std::string data = ft.readTextFile("site/index.html");
return HtmlResponse(data);
});
router.addRoute("/index.html",HttpMethod::GET, [&](const HttpRequest& req){
std::string data = ft.readTextFile("site/index.html");
return HtmlResponse(data);
});
router.addRoute("/about.html",HttpMethod::GET, [&](const HttpRequest& req){
std::string data = ft.readTextFile("site/about.html");
return HtmlResponse(data);
});
router.addRoute("/neon.css",HttpMethod::GET, [&](const HttpRequest& req){
std::string data = ft.readTextFile("site/neon.css");
return CSSResponse(data);
});
router.addRoute("/app.js",HttpMethod::GET, [&](const HttpRequest& req){
std::string data = ft.readTextFile("site/app.js");
return JSResponse(data);
});
router.addRoute("/assets/hero.jpg",HttpMethod::GET, [&](const HttpRequest& req){
std::vector<char> data = ft.readBinaryFile("site/assets/hero.jpg");
return BinaryResponse(data, "image/x-icon",200);
});
router.addRoute("/favicon.ico",HttpMethod::GET, [&](const HttpRequest& req){
std::vector<char> data = ft.readBinaryFile("favicon.ico");
return BinaryResponse(data, "image/jpeg",200);
});
router.addRoute("/api/getData", HttpMethod::GET, [](const HttpRequest& req){
std::string json = R"({"message":"Response from C++ server"})";
return JsonResponse(json);
});
router.addRoute("/putData", HttpMethod::POST, [](const HttpRequest& req) {
std::string nojson = R"({"message":"Need Json body."})";
std::string badjson = R"({"message":"Json body is bad."})";
if (req.contentType == "application/json") {
auto bodyOpt = req.parseJsonBody();
if (!bodyOpt) return JsonResponse(badjson, 400);
try {
json body = *bodyOpt;
std::string name = body.value("name", "");
std::string resjson = R"({"message":"Name received )" + name + "\"}";
return JsonResponse(resjson);
}
catch (...) {
return JsonResponse(badjson, 400);
}
}
return JsonResponse(nojson, 400);
});
constexpr bool ENABLE_RATE_LIMITING = false;
server.setRateLimitingEnabled(ENABLE_RATE_LIMITING);
server.bindAndListen();
server.start(-1);
return 0;
}