WebFramework v3.0.12
Web framework for C++.
Loading...
Searching...
No Matches
WebFramework.cpp
1#include "WebFramework.h"
2
3#include <filesystem>
4
5#include "Log.h"
6#include "JSONArrayWrapper.h"
7
8#include "Exceptions/BaseJSONException.h"
9#include "Exceptions/FileDoesNotExistException.h"
10#include "WebNetwork/WebServers/MultithreadedWebServer.h"
11#include "WebNetwork/WebServers/ThreadPoolWebServer.h"
12#include "LoadBalancer/LoadBalancerServer.h"
13#include "Utility/Singletons/HTTPSSingleton.h"
14#include "Utility/Sources.h"
15#include "Proxy/ProxyServer.h"
16#include "Utility/DynamicLibraries.h"
17
18using namespace std;
19
20namespace framework
21{
23 {
24 static string version = "3.0.12";
25
26 return version;
27 }
28
30 {
31 return utility::HTTPSSingleton::get().getUseHTTPS();
32 }
33
34 uint64_t WebFramework::parseLoggingFlags(const json::utility::jsonObject& loggingSettings) const
35 {
36 vector<json::utility::jsonObject> flags;
37
38 return loggingSettings.tryGetArray(json_settings::logFlagsKey, flags) ?
39 Log::createFlags(json::utility::JSONArrayWrapper(flags).getAsStringArray()) :
40 (numeric_limits<uint64_t>::max)();
41 }
42
43 string WebFramework::initLogging() const
44 {
45 json::utility::jsonObject loggingSettings;
46
47 if (!(*config).tryGetObject(json_settings::loggingObject, loggingSettings))
48 {
49 return "";
50 }
51
52 bool usingLogging = false;
53
54 if (loggingSettings.tryGetBool(json_settings::usingLoggingKey, usingLogging) && usingLogging)
55 {
56 string logsPath;
57 const string& dateFormat = loggingSettings.getString(json_settings::dateFormatKey);
58 bool duplicateOutput = false;
59 bool duplicateErrorOutput = false;
60
61 loggingSettings.tryGetString(json_settings::logsPathKey, logsPath);
62
63 loggingSettings.tryGetBool(json_settings::duplicateOutputKey, duplicateOutput);
64 loggingSettings.tryGetBool(json_settings::duplicateErrorOutputKey, duplicateErrorOutput);
65
66 uint64_t logFileSize = 0;
67 uint64_t flags = this->parseLoggingFlags(loggingSettings);
68
69 if (loggingSettings.tryGetUnsignedInt(json_settings::logFileSizeKey, logFileSize))
70 {
71 if (flags == (numeric_limits<uint64_t>::max)())
72 {
73 Log::configure(dateFormat, logsPath, logFileSize);
74 }
75 else
76 {
77 Log::configure(dateFormat, logsPath, logFileSize, flags);
78 }
79 }
80 else
81 {
82 if (flags == (numeric_limits<uint64_t>::max)())
83 {
84 Log::configure(dateFormat, logsPath);
85 }
86 else
87 {
88 Log::configure(dateFormat, logsPath, Log::logFileSize, flags);
89 }
90 }
91
92 if (duplicateOutput)
93 {
94 Log::duplicateLog(cout);
95 }
96
97 if (duplicateErrorOutput)
98 {
99 Log::duplicateErrorLog(cerr);
100 }
101 }
102
103 return "";
104 }
105
106 void WebFramework::initHTTPS(const json::utility::jsonObject& webFrameworkSettings) const
107 {
108 json::utility::jsonObject https;
109
110 if (!webFrameworkSettings.tryGetObject(json_settings::httpsObject, https))
111 {
112 return;
113 }
114
115 bool useHTTPS = false;
116
117 if (https.tryGetBool(json_settings::useHTTPSKey, useHTTPS) && useHTTPS)
118 {
119 utility::HTTPSSingleton& httpsSettings = utility::HTTPSSingleton::get();
120 const filesystem::path& basePath = config.getBasePath();
121
122 httpsSettings.setUseHTTPS(true);
123 httpsSettings.setPathToCertificate(basePath / https.getString(json_settings::pathToCertificateKey));
124 httpsSettings.setPathToKey(basePath / https.getString(json_settings::pathToKey));
125
126 SSL_library_init();
127 SSL_load_error_strings();
128 }
129 }
130
131 void WebFramework::initServer
132 (
133 const json::utility::jsonObject& webFrameworkSettings,
134 const vector<utility::JSONSettingsParser>& jsonSettings,
135 const vector<string>& pathToSources
136 )
137 {
138 const filesystem::path& basePath = config.getBasePath();
139 const json::utility::jsonObject& webServerSettings = (*config).getObject(json_settings::webServerObject);
140 const string& ip = webServerSettings.getString(json_settings::ipKey);
141 string port = to_string(webServerSettings.getInt(json_settings::portKey));
142 DWORD timeout = static_cast<DWORD>(webServerSettings.getInt(json_settings::timeoutKey));
143
144 const string& webServerType = webFrameworkSettings.getString(json_settings::webServerTypeKey);
145 string assetsPath = (basePath / webFrameworkSettings.getString(json_settings::assetsPathKey)).string();
146 string templatesPath = (basePath / webFrameworkSettings.getString(json_settings::templatesPathKey)).string();
147 uint64_t cachingSize = webFrameworkSettings.getUnsignedInt(json_settings::cachingSize);
148
149 if (webServerType == json_settings::multiThreadedWebServerTypeValue)
150 {
151 server = make_unique<MultithreadedWebServer>
152 (
153 *config,
154 jsonSettings,
155 assetsPath,
156 templatesPath,
157 cachingSize,
158 ip,
159 port,
160 timeout,
161 pathToSources
162 );
163 }
164 else if (webServerType == json_settings::threadPoolWebServerTypeValue)
165 {
166 int64_t threadCount = 0;
167 json::utility::jsonObject threadPoolServerObject;
168
169 if ((*config).tryGetObject(json_settings::threadPoolServerObject, threadPoolServerObject))
170 {
171 (*config).tryGetInt(json_settings::threadCountKey, threadCount);
172 }
173
174 server = make_unique<ThreadPoolWebServer>
175 (
176 *config,
177 jsonSettings,
178 assetsPath,
179 templatesPath,
180 cachingSize,
181 ip,
182 port,
183 timeout,
184 pathToSources,
185 static_cast<uint32_t>(threadCount)
186 );
187 }
188 else if (webServerType == json_settings::loadBalancerWebServerTypeValue)
189 {
190 const json::utility::jsonObject& loadBalancerSettings = (*config).getObject(json_settings::loadBalancerObject);
191 const string& heuristic = loadBalancerSettings.getString(json_settings::heuristicKey);
192 const string& loadSource = loadBalancerSettings.getString(json_settings::loadSourceKey);
193 bool serversHTTPS = loadBalancerSettings.getBool(json_settings::serversHTTPSKey);
194 const json::utility::jsonObject& listOfServers = loadBalancerSettings.getObject("listOfServers");
195 unordered_map<string, vector<int64_t>> allServers;
196
197 for (const auto& [key, value] : listOfServers)
198 {
199 allServers.try_emplace
200 (
201 key,
202 json::utility::JSONArrayWrapper(get<vector<json::utility::jsonObject>>(value)).getAsInt64_tArray()
203 );
204 }
205
206 server = make_unique<load_balancer::LoadBalancerServer>
207 (
208 ip,
209 port,
210 timeout,
211 serversHTTPS,
212 heuristic,
213 utility::loadSources(pathToSources),
214 allServers,
215 (*config),
216 assetsPath,
217 cachingSize,
218 templatesPath
219 );
220 }
221 else if (webServerType == json_settings::proxyWebServerTypeValue)
222 {
223 server = make_unique<proxy::ProxyServer>(ip, port, timeout, (*config).getObject(json_settings::proxyObject));
224 }
225 else
226 {
227 throw runtime_error(::exceptions::wrongWebServerType);
228 }
229 }
230
231 WebFramework::WebFramework(const utility::Config& webFrameworkConfig) :
232 config(webFrameworkConfig)
233 {
234 const json::utility::jsonObject& webFrameworkSettings = (*config).getObject(json_settings::webFrameworkObject);
235 const filesystem::path& basePath = config.getBasePath();
236 vector<string> settingsPaths = json::utility::JSONArrayWrapper(webFrameworkSettings.getArray(json_settings::settingsPathsKey)).getAsStringArray();
237 vector<string> pathToSources = json::utility::JSONArrayWrapper(webFrameworkSettings.getArray(json_settings::loadSourcesKey)).getAsStringArray();
238
239 ranges::for_each(settingsPaths, [this, &basePath](string& path) { path = (basePath / path).string(); });
240 ranges::for_each(pathToSources, [this, &basePath](string& source)
241 {
242 if (source == "current")
243 {
244 return;
245 }
246
247 source = (basePath / source).string();
248 });
249
250 if (string errorMessage = this->initLogging(); errorMessage.size())
251 {
252 throw runtime_error(errorMessage);
253 }
254
255 this->initHTTPS(webFrameworkSettings);
256
257 vector<utility::JSONSettingsParser> jsonSettings;
258
259 jsonSettings.reserve(settingsPaths.size());
260
261 transform(settingsPaths.begin(), settingsPaths.end(), back_inserter(jsonSettings), [](const string& i) { return utility::JSONSettingsParser(i); });
262
263 this->initServer
264 (
265 webFrameworkSettings,
266 jsonSettings,
267 pathToSources
268 );
269 }
270
271 WebFramework::WebFramework(const filesystem::path& webFrameworkConfigPath) :
272 WebFramework(utility::Config(webFrameworkConfigPath))
273 {
274
275 }
276
277 void WebFramework::start(bool wait, const function<void()>& onStartServer)
278 {
279 server->start(wait, onStartServer);
280 }
281
282 void WebFramework::stop(bool wait)
283 {
284 server->stop(wait);
285 }
286
287 void WebFramework::kick(const string& ip) const
288 {
289 server->kick(ip);
290 }
291
292 vector<string> WebFramework::getClientsIp() const
293 {
294 vector<pair<string, vector<SOCKET>>> clients = server->getClients();
295 vector<string> result;
296
297 result.reserve(clients.size());
298
299 for (const auto& [ip, _] : clients)
300 {
301 result.push_back(ip);
302 }
303
304 return result;
305 }
306
308 {
309 return server->isServerRunning();
310 }
311
312 const json::JSONParser& WebFramework::getCurrentConfiguration() const
313 {
314 return (*config);
315 }
316}
void kick(const std::string &ip) const
Kick specific client.
void stop(bool wait=true)
Stop server.
void start(bool wait=false, const std::function< void()> &onStartServer=[]() {})
Start server.
static std::string_view getWebFrameworkVersion()
Get current WebFramework version.
bool isServerRunning() const
Is server running.
const json::JSONParser & getCurrentConfiguration() const
Getter for currentConfiguration.
std::vector< std::string > getClientsIp() const
Get ip addresses of all currently connected clients.
static bool getUseHTTPS()
Is server use HTTPS.
const std::filesystem::path & getBasePath() const
Config file directory.
Definition Config.cpp:92