Skip to content

Commit

Permalink
csa: Implement de v2/route endpoint for route and alternatives
Browse files Browse the repository at this point in the history
This endpoint is documented in the docs/APIv2/API.yml file as
`v2/route`.
  • Loading branch information
tahini authored and greenscientist committed Sep 28, 2022
1 parent 683bbd1 commit ee50e74
Showing 1 changed file with 105 additions and 0 deletions.
105 changes: 105 additions & 0 deletions connection_scan_algorithm/src/transit_routing_http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "calculator.hpp"
#include "program_options.hpp"
#include "result_to_v1.hpp"
#include "result_to_v2.hpp"
#include "routing_result.hpp"
#include "osrm_fetcher.hpp"

Expand Down Expand Up @@ -55,6 +56,45 @@ std::string intializeResponse(Calculator::DataStatus status)
}
}

std::string getFastErrorResponse(Calculator::DataStatus status)
{
switch(status)
{
case Calculator::DataStatus::READY: return "";
case Calculator::DataStatus::DATA_READ_ERROR: return "{\"status\": \"data_error\", \"errorCode\": \"DATA_ERROR\"}";
case Calculator::DataStatus::NO_AGENCIES:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_AGENCIES\"}";
case Calculator::DataStatus::NO_LINES:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_LINES\"}";
case Calculator::DataStatus::NO_NODES:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_NODES\"}";
case Calculator::DataStatus::NO_PATHS:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_PATHS\"}";
case Calculator::DataStatus::NO_SCENARIOS:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_SCENARIOS\"}";
case Calculator::DataStatus::NO_SCHEDULES:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_SCHEDULES\"}";
case Calculator::DataStatus::NO_SERVICES:
return "{\"status\": \"data_error\", \"errorCode\": \"MISSING_DATA_SERVICES\"}";
default: return "PARAM_ERROR_UNKNOWN";
}
}

std::string getResponseCode(ParameterException::Type type)
{
switch(type)
{
case ParameterException::Type::EMPTY_SCENARIO: return "EMPTY_SCENARIO";
case ParameterException::Type::MISSING_SCENARIO: return "MISSING_PARAM_SCENARIO";
case ParameterException::Type::MISSING_ORIGIN: return "MISSING_PARAM_ORIGIN";
case ParameterException::Type::MISSING_DESTINATION: return "MISSING_PARAM_DESTINATION";
case ParameterException::Type::MISSING_TIME_OF_TRIP: return "MISSING_PARAM_TIME_OF_TRIP";
case ParameterException::Type::INVALID_ORIGIN: return "INVALID_ORIGIN";
case ParameterException::Type::INVALID_DESTINATION: return "INVALID_DESTINATION";
case ParameterException::Type::INVALID_NUMERICAL_DATA: return "INVALID_NUMERICAL_DATA";
default: return "PARAM_ERROR_UNKNOWN";
}
}

int main(int argc, char** argv) {

Expand Down Expand Up @@ -404,6 +444,71 @@ int main(int argc, char** argv) {

};

// Routing request for a single origin destination
// TODO Copy-pasted and adapted from /route/v1/transit. There's still a lot of common code. Application code should be extracted to common functions outside the web server
server.resource["^/v2/route[/]?$"]["GET"]=[&server, &calculator, &dataStatus](std::shared_ptr<HttpServer::Response> serverResponse, std::shared_ptr<HttpServer::Request> request) {

std::string response = getFastErrorResponse(dataStatus);

if (!response.empty()) {
*serverResponse << "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: " << response.length() << "\r\n\r\n" << response;
return;
}

// prepare benchmarking and timer:
// TODO Shouldn't have to do this, a query is not a benchmark
calculator.algorithmCalculationTime.start();
calculator.benchmarking.clear();

// prepare parameters:
std::vector<std::pair<std::string, std::string>> parametersWithValues;
auto queryFields = request->parse_query_string();
for(auto &field : queryFields)
{
parametersWithValues.push_back(std::make_pair(field.first, field.second));
}

spdlog::debug("-- calculating request -- {}", request->path);

try
{
std::unique_ptr<TrRouting::RoutingResult> routingResult;
TrRouting::AlternativesResult alternativeResult;

RouteParameters queryParams = RouteParameters::createRouteODParameter(parametersWithValues, calculator.scenarioIndexesByUuid, calculator.scenarios);

try {
if (queryParams.isWithAlternatives())
{
alternativeResult = calculator.alternativesRouting(queryParams);
response = ResultToV2Response::resultToJsonString(alternativeResult, queryParams).dump(2);
}
else
{
routingResult = calculator.calculate(queryParams);
if (routingResult.get() != nullptr) {
response = ResultToV2Response::resultToJsonString(*routingResult.get(), queryParams).dump(2);
}
}

spdlog::debug("-- total -- {} microseconds", calculator.algorithmCalculationTime.getDurationMicrosecondsNoStop());

} catch (NoRoutingFoundException e) {
response = ResultToV2Response::noRoutingFoundResponse(queryParams, e.getReason()).dump(2);
}

*serverResponse << "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: " << response.length() << "\r\n\r\n" << response;

} catch (ParameterException exp) {
response = "{\"status\": \"query_error\", \"errorCode\": \"" + getResponseCode(exp.getType()) + "\"}";
*serverResponse << "HTTP/1.1 400 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: " << response.length() << "\r\n\r\n" << response;
} catch (...) {
response = "{\"status\": \"query_error\", \"errorCode\": \"PARAM_ERROR_UNKNOWN\"}";
*serverResponse << "HTTP/1.1 400 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: " << response.length() << "\r\n\r\n" << response;
}

};

server.default_resource["GET"] = [](std::shared_ptr<HttpServer::Response> serverResponse, std::shared_ptr<HttpServer::Request> request) {
spdlog::info("calculating request: {}", request->content.string());

Expand Down

0 comments on commit ee50e74

Please sign in to comment.