pica/server/router.cpp

79 lines
2.8 KiB
C++

// SPDX-FileCopyrightText: 2023 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "router.h"
Router::Router():
get(),
post()
{}
void Router::addRoute(Handler handler) {
std::pair<std::map<std::string, Handler>::const_iterator, bool> result;
switch (handler->method) {
case Request::Method::get:
result = get.emplace(handler->path, std::move(handler));
break;
case Request::Method::post:
result = post.emplace(handler->path, std::move(handler));
break;
default:
throw std::runtime_error("An attempt to register handler with unsupported method type: " + std::to_string((int)handler->method));
}
if (!result.second)
throw std::runtime_error("could'not add route " + handler->path + " to the routing table");
}
void Router::route(const std::string& path, std::unique_ptr<Request> request) {
std::map<std::string, Handler>::const_iterator itr, end;
switch (request->method()) {
case Request::Method::get:
itr = get.find(path);
end = get.end();
break;
case Request::Method::post:
itr = post.find(path);
end = post.end();
break;
default:
return handleMethodNotAllowed(path, std::move(request));
}
if (itr == end)
return handleNotFound(path, std::move(request));
try {
std::cout << "Handling " << path << "..." << std::endl;
itr->second->handle(*request.get());
if (request->currentState() != Request::State::responded)
handleInternalError(path, std::runtime_error("handler failed to handle the request"), std::move(request));
else
std::cout << "Success:\t" << path << std::endl;
} catch (const std::exception& e) {
handleInternalError(path, e, std::move(request));
}
}
void Router::handleNotFound(const std::string& path, std::unique_ptr<Request> request) {
Response notFound(*request.get(), Response::Status::notFound);
notFound.setBody(std::string("Path \"") + path + "\" was not found");
notFound.send();
std::cerr << "Not found:\t" << path << std::endl;
}
void Router::handleInternalError(const std::string& path, const std::exception& exception, std::unique_ptr<Request> request) {
Response error(*request.get(), Response::Status::internalError);
error.setBody(std::string(exception.what()));
error.send();
std::cerr << "Internal error:\t" << path << "\n\t" << exception.what() << std::endl;
}
void Router::handleMethodNotAllowed(const std::string& path, std::unique_ptr<Request> request) {
Response error(*request.get(), Response::Status::methodNotAllowed);
error.setBody(std::string("Method not allowed"));
error.send();
std::cerr << "Method not allowed:\t" << path << std::endl;
}