Skip to content

Commit bafa578

Browse files
committed
Make it compile on other platforms
1 parent cd91658 commit bafa578

File tree

1 file changed

+58
-64
lines changed

1 file changed

+58
-64
lines changed

examples/SecureGzipFileServer.cpp

Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,46 @@
11
#include <iostream>
2-
#include <map>
32
#include <unordered_map>
43
#include <mutex>
54
#include <thread>
65
#include <chrono>
76
#include <filesystem>
87
#include <fstream>
9-
#include <set>
8+
#include <string>
9+
#include <cstdint>
10+
#include <cstring>
11+
#include "App.h"
12+
#include <zlib.h>
13+
14+
#if defined(__linux__)
1015
#include <sys/inotify.h>
1116
#include <unistd.h>
12-
#include <cstring>
13-
#include "App.h" // Ensure uWS is installed and this header is available
17+
#endif
1418

15-
int cooldown = 0; // how much to sleep after reloading files, seconds
19+
int cooldown = 0; // Seconds to sleep after reloading files (Linux only)
1620

17-
// Custom hasher for both std::string and std::string_view
21+
// Custom hasher for transparent lookup with std::string and std::string_view
1822
struct StringViewHasher {
19-
using is_transparent = void; // Enable transparent lookup
20-
21-
std::size_t operator()(const std::string& s) const {
22-
return std::hash<std::string_view>{}(s);
23-
}
24-
25-
std::size_t operator()(std::string_view s) const {
26-
return std::hash<std::string_view>{}(s);
27-
}
23+
using is_transparent = void;
24+
std::size_t operator()(const std::string& s) const { return std::hash<std::string_view>{}(s); }
25+
std::size_t operator()(std::string_view s) const { return std::hash<std::string_view>{}(s); }
2826
};
2927

3028
// Custom equality comparator for transparent lookup
3129
struct StringViewEqual {
32-
using is_transparent = void; // Enable transparent lookup
33-
34-
// Single operator() that handles all combinations
35-
bool operator()(std::string_view lhs, std::string_view rhs) const {
36-
return lhs == rhs;
37-
}
30+
using is_transparent = void;
31+
bool operator()(std::string_view lhs, std::string_view rhs) const { return lhs == rhs; }
3832
};
3933

40-
41-
// Global variables for the file map, mutex, and inotify file descriptor
34+
// Global variables
4235
std::unordered_map<std::string, std::pair<std::string, bool>, StringViewHasher, StringViewEqual> file_map;
4336
std::mutex map_mutex;
37+
#if defined(__linux__)
4438
int inotify_fd;
39+
#endif
4540
unsigned long fileSizes = 0;
4641

47-
#include <zlib.h>
48-
#include <stdexcept>
49-
50-
42+
// Loads file content and compresses it with zlib if beneficial
5143
std::pair<std::string, bool> load_file_content(const std::filesystem::path& path) {
52-
// Load file content
5344
std::ifstream file(path, std::ios::binary);
5445
if (!file) {
5546
std::cerr << "Failed to open file: " << path << std::endl;
@@ -60,76 +51,68 @@ std::pair<std::string, bool> load_file_content(const std::filesystem::path& path
6051
file.seekg(0, std::ios::beg);
6152
std::string content(size, 0);
6253
file.read(&content[0], size);
63-
//std::cout << "Loaded file: " << path << " (" << size << " bytes)" << std::endl;
6454

65-
// Compress in memory using zlib
6655
z_stream zs = {};
67-
zs.zalloc = Z_NULL;
68-
zs.zfree = Z_NULL;
69-
zs.opaque = Z_NULL;
7056
if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
71-
std::cerr << "Failed to initialize zlib" << std::endl;
57+
std::cerr << "Failed to initialize zlib for " << path << std::endl;
7258
return {"", false};
7359
}
74-
7560
zs.next_in = reinterpret_cast<Bytef*>(content.data());
7661
zs.avail_in = content.size();
77-
78-
// Calculate output buffer size (zlib guarantees max output size)
7962
size_t bound = deflateBound(&zs, content.size());
8063
std::string compressed(bound, 0);
8164
zs.next_out = reinterpret_cast<Bytef*>(&compressed[0]);
8265
zs.avail_out = bound;
83-
8466
int ret = deflate(&zs, Z_FINISH);
8567
if (ret != Z_STREAM_END) {
8668
deflateEnd(&zs);
87-
std::cerr << "Failed to compress data" << std::endl;
69+
std::cerr << "Failed to compress " << path << std::endl;
8870
return {"", false};
8971
}
90-
9172
size_t compressed_size = zs.total_out;
9273
deflateEnd(&zs);
93-
94-
// Resize to actual compressed size
9574
compressed.resize(compressed_size);
9675

97-
if (compressed_size > size) {
98-
fileSizes += size;
99-
return {content, false};
76+
if (compressed_size < size) {
77+
fileSizes += compressed_size;
78+
return {compressed, true};
10079
}
101-
102-
//std::cout << "Compressed to: " << compressed_size << " bytes" << std::endl;
103-
fileSizes += compressed_size;
104-
return {compressed, true};
80+
fileSizes += size;
81+
return {content, false};
10582
}
10683

107-
// Function to load all files from the root folder into the map and add inotify watches
108-
void load_files(const std::string& root, int inotify_fd) {
84+
// Loads all files from the root folder into the map; adds inotify watches on Linux if inotify_fd >= 0
85+
void load_files(const std::string& root, int inotify_fd = -1) {
10986
fileSizes = 0;
11087
std::unordered_map<std::string, std::pair<std::string, bool>, StringViewHasher, StringViewEqual> new_map;
11188
for (const auto& entry : std::filesystem::recursive_directory_iterator(root)) {
11289
if (entry.is_regular_file() && !entry.path().filename().string().starts_with(".")) {
11390
std::string relative_path = "/" + std::filesystem::relative(entry.path(), root).generic_string();
11491
auto [content, compressed] = load_file_content(entry.path());
11592
new_map[relative_path] = {content, compressed};
116-
// Add watch to file for IN_MODIFY
117-
inotify_add_watch(inotify_fd, entry.path().c_str(), IN_MODIFY);
93+
#if defined(__linux__)
94+
if (inotify_fd >= 0) {
95+
inotify_add_watch(inotify_fd, entry.path().c_str(), IN_MODIFY);
96+
}
97+
#endif
11898
} else if (entry.is_directory()) {
119-
// Add watch to directory for IN_CREATE | IN_DELETE | IN_MOVE
120-
inotify_add_watch(inotify_fd, entry.path().c_str(), IN_CREATE | IN_DELETE | IN_MOVE);
99+
#if defined(__linux__)
100+
if (inotify_fd >= 0) {
101+
inotify_add_watch(inotify_fd, entry.path().c_str(), IN_CREATE | IN_DELETE | IN_MOVE);
102+
}
103+
#endif
121104
}
122105
}
123106
{
124107
std::lock_guard<std::mutex> lock(map_mutex);
125108
file_map = std::move(new_map);
126-
std::cout << "Reloaded " << (fileSizes / 1024 / 1024) << " MB of files into RAM" << std::endl;
109+
std::cout << "Loaded " << (fileSizes / 1024 / 1024) << " MB of files into RAM" << std::endl;
127110
}
128111
}
129112

130-
// Background thread function to monitor inotify events and reload files on changes
113+
#if defined(__linux__)
114+
// Background thread to monitor inotify events and reload files on changes (Linux only)
131115
void inotify_reloader_function(const std::string& root, int inotify_fd) {
132-
load_files(root, inotify_fd);
133116
char buffer[4096];
134117
while (true) {
135118
int length = read(inotify_fd, buffer, sizeof(buffer));
@@ -144,6 +127,7 @@ void inotify_reloader_function(const std::string& root, int inotify_fd) {
144127
}
145128
}
146129
}
130+
#endif
147131

148132
int main(int argc, char** argv) {
149133
if (argc != 3) {
@@ -153,26 +137,32 @@ int main(int argc, char** argv) {
153137
std::string root = argv[1];
154138
cooldown = std::stoi(argv[2]);
155139
if (cooldown < 0) {
156-
std::cerr << "Cooldown must be a positive integer" << std::endl;
140+
std::cerr << "Cooldown must be a non-negative integer" << std::endl;
157141
return 1;
158142
}
159143

144+
#if defined(__linux__)
160145
inotify_fd = inotify_init();
161146
if (inotify_fd < 0) {
162147
std::cerr << "Failed to initialize inotify: " << strerror(errno) << std::endl;
163148
return 1;
164149
}
165-
150+
load_files(root, inotify_fd);
166151
std::thread inotify_reloader(inotify_reloader_function, root, inotify_fd);
152+
#else
153+
load_files(root); // Load once at startup on macOS and Windows
154+
#endif
167155

168156
uWS::App app;
169157

170-
// We only need to lock once per event loop iteration, not on every request
171-
uWS::Loop::get()->addPostHandler(&inotify_reloader, [](uWS::Loop */*loop*/) {
158+
// Static key for uWS handlers
159+
static char handler_key;
160+
161+
// Add post and pre handlers to lock the mutex around event loop iterations (unchanged as requested)
162+
uWS::Loop::get()->addPostHandler(&handler_key, [](uWS::Loop* /*loop*/) {
172163
std::lock_guard<std::mutex> lock(map_mutex);
173164
});
174-
175-
uWS::Loop::get()->addPreHandler(&inotify_reloader, [](uWS::Loop */*loop*/) {
165+
uWS::Loop::get()->addPreHandler(&handler_key, [](uWS::Loop* /*loop*/) {
176166
std::lock_guard<std::mutex> lock(map_mutex);
177167
});
178168

@@ -188,6 +178,7 @@ int main(int argc, char** argv) {
188178
res->end("Not Found");
189179
}
190180
});
181+
191182
app.get("/*", [](auto* res, auto* req) {
192183
auto it = file_map.find(req->getUrl());
193184
if (it != file_map.end()) {
@@ -209,7 +200,10 @@ int main(int argc, char** argv) {
209200

210201
app.run();
211202

203+
#if defined(__linux__)
212204
inotify_reloader.join();
213205
close(inotify_fd);
206+
#endif
207+
214208
return 0;
215209
}

0 commit comments

Comments
 (0)