1#include "ExecutorsManager.h"
5#include "Exceptions/FileDoesNotExistException.h"
6#include "Exceptions/BadRequestException.h"
7#include "Exceptions/DatabaseException.h"
13 bool ExecutorsManager::isFileRequest(string_view parameters)
15 size_t index = parameters.find(
'.');
17 if (index == string_view::npos)
22 string_view fileExtension(parameters.begin() + index, parameters.end());
24 return fileExtension.size() > 1 && ranges::all_of(fileExtension, [](
char c) {
return c !=
'/'; });
27 bool ExecutorsManager::isHeavyOperation(BaseExecutor* executor)
31 throw exceptions::BadRequestException();
34 BaseExecutor::executorType executorType = executor->getType();
36 return executorType == BaseExecutor::executorType::heavyOperationStateless ||
37 executorType == BaseExecutor::executorType::heavyOperationStateful;
40 void ExecutorsManager::parseRouteParameters(
const string& parameters, HTTPRequest& request, vector<utility::RouteParameters>::iterator it)
43 size_t startParameter = it->baseRoute.size() + 1;
48 endParameter = parameters.find(
'/', startParameter);
50 switch (
static_cast<utility::RouteParameters::routeParametersType
>(it->parameters[it->indices[i]].index()))
52 case utility::RouteParameters::routeParametersType::stringTypeIndex:
53 request.routeParameters[it->indices[i++]] = parameters.substr(startParameter, endParameter - startParameter);
57 case utility::RouteParameters::routeParametersType::integerTypeIndex:
60 request.routeParameters[it->indices[i++]] = stoll(parameters.substr(startParameter, endParameter - startParameter));
62 catch (
const invalid_argument&)
64 throw exceptions::BadRequestException(
"Can't convert to int64_t");
66 catch (
const out_of_range&)
68 throw exceptions::BadRequestException(
"Out of range of int64_t");
73 case utility::RouteParameters::routeParametersType::doubleTypeIndex:
76 request.routeParameters[it->indices[i++]] = stod(parameters.substr(startParameter, endParameter - startParameter));
78 catch (
const invalid_argument&)
80 throw exceptions::BadRequestException(
"Can't convert to double");
82 catch (
const out_of_range&)
84 throw exceptions::BadRequestException(
"Out of range of double");
90 throw runtime_error(
"Wrong routeParametersType");
93 startParameter = endParameter + 1;
94 }
while (endParameter != string::npos);
97 BaseExecutor* ExecutorsManager::getExecutor(
string& parameters, HTTPRequest& request, unordered_map<
string, unique_ptr<BaseExecutor>>& statefulExecutors)
99 auto executor = statefulExecutors.find(parameters);
101 if (executor == statefulExecutors.end())
103 unique_lock<mutex> scopeLock(checkExecutor);
105 executor = routes.find(parameters);
107 if (executor == routes.end())
109 auto executorSettings = settings.find(parameters);
111 if (executorSettings == settings.end())
113 auto it = find_if(routeParameters.begin(), routeParameters.end(),
114 [¶meters](
const utility::RouteParameters& value) { return parameters.find(value.baseRoute) != string::npos; });
116 if (it == routeParameters.end())
121 executorSettings = settings.find(it->baseRoute);
123 if (executorSettings == settings.end())
128 ExecutorsManager::parseRouteParameters(parameters, request, it);
130 parameters = it->baseRoute;
133 executor = routes.try_emplace
136 unique_ptr<BaseExecutor>(
static_cast<BaseExecutor*
>(creators[executorSettings->second.name]()))
138 executor->second->init(executorSettings->second);
140 BaseExecutor::executorType executorType = executor->second->getType();
142 if (executorType == BaseExecutor::executorType::stateful || executorType == BaseExecutor::executorType::heavyOperationStateful)
144 executor = statefulExecutors.insert(routes.extract(executor)).position;
149 return executor->second.get();
152 ExecutorsManager::ExecutorsManager() :
153 serverType(webServerType::multiThreaded)
158 ExecutorsManager::ExecutorsManager(ExecutorsManager&& other)
noexcept
160 (*this) = move(other);
163 ExecutorsManager& ExecutorsManager::operator = (ExecutorsManager&& other)
noexcept
165 this->routes = move(other.routes);
166 this->creators = move(other.creators);
167 this->settings = move(other.settings);
168 this->resources = move(other.resources);
173 void ExecutorsManager::init
175 const json::JSONParser& configuraion,
176 const filesystem::path& assets,
177 uint64_t cachingSize,
178 const filesystem::path& pathToTemplates,
179 unordered_map<
string, unique_ptr<BaseExecutor>>&& routes,
180 unordered_map<string, createExecutorFunction>&& creators,
181 unordered_map<string, utility::JSONSettingsParser::ExecutorSettings>&& settings,
182 vector<utility::RouteParameters>&& routeParameters
185 const unordered_map<string_view, webServerType> types =
187 { json_settings::multiThreadedWebServerTypeValue, webServerType::multiThreaded },
188 { json_settings::threadPoolWebServerTypeValue, webServerType::threadPool },
189 { json_settings::loadBalancerWebServerTypeValue, webServerType::loadBalancer },
190 { json_settings::proxyWebServerTypeValue, webServerType::proxy }
193 this->routes = move(routes);
194 this->creators = move(creators);
195 this->settings = move(settings);
196 this->routeParameters = move(routeParameters);
198 resources = make_shared<ResourceExecutor>(configuraion, assets, cachingSize, pathToTemplates);
200 resources->init(utility::JSONSettingsParser::ExecutorSettings());
202 serverType = types.at(configuraion.getObject(json_settings::webFrameworkObject).getString(json_settings::webServerTypeKey));
205 optional<function<void(HTTPRequest&, HTTPResponse&)>> ExecutorsManager::service(HTTPRequest& request, HTTPResponse& response, unordered_map<
string, unique_ptr<BaseExecutor>>& statefulExecutors)
207 static const unordered_map<string, void(BaseExecutor::*)(HTTPRequest&, HTTPResponse&)> methods =
209 {
"GET", &BaseExecutor::doGet },
210 {
"POST", &BaseExecutor::doPost },
211 {
"HEAD", &BaseExecutor::doHead },
212 {
"PUT", &BaseExecutor::doPut },
213 {
"DELETE", &BaseExecutor::doDelete },
214 {
"PATCH", &BaseExecutor::doPatch },
215 {
"OPTIONS",&BaseExecutor::doOptions },
216 {
"TRACE", &BaseExecutor::doTrace },
217 {
"CONNECT", &BaseExecutor::doConnect }
222 string parameters = request.getRawParameters();
223 BaseExecutor* executor =
nullptr;
224 bool fileRequest = ExecutorsManager::isFileRequest(parameters);
226 if (parameters.find(
'?') != string::npos)
228 parameters.resize(parameters.find(
'?'));
231 executor = this->getExecutor(parameters, request, statefulExecutors);
233 if (!fileRequest && !executor)
235 throw exceptions::BadRequestException();
238 if (fileRequest && executor)
243 void (BaseExecutor:: * method)(HTTPRequest&, HTTPResponse&) = methods.at(request.getMethod());
245 if (serverType == webServerType::threadPool && (fileRequest ?
false : ExecutorsManager::isHeavyOperation(executor)))
247 return bind(method, executor, placeholders::_1, placeholders::_2);
252 invoke(method, resources.get(), request, response) :
253 invoke(method, executor, request, response);
258 catch (
const exceptions::BaseExecutorException& e)
262 Log::error(
"Executor exception: {}",
"LogExecutor", e.what());
267 catch (
const file_manager::exceptions::FileDoesNotExistException& e)
271 Log::error(
"File request exception. {}",
"LogExecutor", e.what());
276 catch (
const exceptions::DatabaseException& e)
280 Log::error(
"Database exception: {}",
"LogWebFrameworkDatabase", e.what());
285 catch (
const out_of_range&)
289 Log::error(
"Out of range",
"LogExecutor");
294 catch (
const exception& e)
298 Log::error(
"Executor manager exception: {}",
"LogExecutorsManager", e.what());
305 shared_ptr<ResourceExecutor> ExecutorsManager::getResourceExecutor()
const