Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,145 @@
#include "routing/routing_quality/api/google/google_api.hpp"
#include "platform/http_client.hpp"
#include "coding/serdes_json.hpp"
#include "geometry/mercator.hpp"
#include "base/assert.hpp"
#include "base/logging.hpp"
#include <chrono>
#include <ctime>
#include <sstream>
#include <utility>
namespace
{
auto GetNextDayAtNight(int32_t startTimeZoneUTC)
{
auto now = std::chrono::system_clock::now();
std::time_t nowTimeT = std::chrono::system_clock::to_time_t(now);
std::tm * date = std::localtime(&nowTimeT);
std::time_t constexpr kSecondsInDay = 24 * 60 * 60;
std::time_t nextDay = std::mktime(date) + kSecondsInDay;
std::tm * nextDayDate = std::localtime(&nextDay);
long constexpr kSecondsInHour = 3600;
int const curUTCOffset = static_cast<int>(nextDayDate->tm_gmtoff / kSecondsInHour);
nextDayDate->tm_sec = 0;
nextDayDate->tm_min = 0;
int constexpr kStartHour = 22;
// If in Moscow (UTC+3) it is 20:00, in New York (UTC-5):
// 20:00 - 03:00 (Moscow) = 19:00 (UTC+0), so in New York: 19:00 - 05:00 = 14:00 (UTC-5).
// Thus if we want to find such time (Y hours) in Moscow (UTC+3) so that in New York (UTC-5)
// it's must be X hours, we use such formula:
// 1) Y (UTC+3) - 03:00 = UTC+0
// 2) Y (UTC+3) - 03:00 + 05:00 = X (UTC+5)
// 2 => Y = X + 03:00 - 05:00
// For google api we want to find such Y, that it's will be |kStartHour| hours in any place.
nextDayDate->tm_hour = kStartHour + curUTCOffset - startTimeZoneUTC;
return std::chrono::system_clock::from_time_t(std::mktime(nextDayDate));
}
} // namespace
namespace routing_quality
{
namespace api
{
namespace google
{
// static
std::string const GoogleApi::kApiName = "google";
GoogleApi::GoogleApi(std::string const & token) : RoutingApi(kApiName, token, kMaxRPS) {}
Response GoogleApi::CalculateRoute(Params const & params, int32_t startTimeZoneUTC) const
{
Response response;
GoogleResponse googleResponse = MakeRequest(params, startTimeZoneUTC);
response.m_params = params;
response.m_code = googleResponse.m_code;
for (auto const & route : googleResponse.m_routes)
{
CHECK_EQUAL(route.m_legs.size(), 1, ("No waypoints support for google api."));
auto const & leg = route.m_legs.back();
api::Route apiRoute;
apiRoute.m_eta = leg.m_duration.m_seconds;
apiRoute.m_distance = leg.m_distance.m_meters;
auto const startLatLon = leg.m_steps.front().m_startLocation;
apiRoute.m_waypoints.emplace_back(startLatLon.m_lat, startLatLon.m_lon);
for (auto const & step : leg.m_steps)
{
auto const & prev = step.m_startLocation;
auto const & next = step.m_endLocation;
auto const & prevWaypoint = apiRoute.m_waypoints.back();
CHECK(prevWaypoint.m_lat == prev.m_lat && prevWaypoint.m_lon == prev.m_lon, ());
apiRoute.m_waypoints.emplace_back(next.m_lat, next.m_lon);
}
response.m_routes.emplace_back(std::move(apiRoute));
}
return response;
}
GoogleResponse GoogleApi::MakeRequest(Params const & params, int32_t startTimeZoneUTC) const
{
GoogleResponse googleResponse;
platform::HttpClient request(GetDirectionsURL(params, startTimeZoneUTC));
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
{
auto const & response = request.ServerResponse();
CHECK(!response.empty(), ());
{
googleResponse.m_code = ResultCode::ResponseOK;
coding::DeserializerJson des(response);
des(googleResponse);
}
}
else
{
LOG(LWARNING, (request.ErrorCode(), request.ServerResponse()));
googleResponse.m_code = ResultCode::Error;
}
return googleResponse;
}
std::string GoogleApi::GetDirectionsURL(Params const & params, int32_t startTimeZoneUTC) const
{
CHECK(-12 <= startTimeZoneUTC && startTimeZoneUTC <= 12, ("Invalid UTC zone."));
static std::string const kBaseUrl = "https://maps.googleapis.com/maps/api/directions/json?";
auto const start = mercator::ToLatLon(params.m_waypoints.GetPointFrom());
auto const finish = mercator::ToLatLon(params.m_waypoints.GetPointTo());
auto const nextDayAtNight = GetNextDayAtNight(startTimeZoneUTC);
auto const secondFromEpoch = nextDayAtNight.time_since_epoch().count() / 1000000;
LOG(LDEBUG, ("&departure_time =", secondFromEpoch));
std::stringstream ss;
ss << kBaseUrl << "&origin=" << std::to_string(start.m_lat) << "," << std::to_string(start.m_lon)
<< "&destination=" << std::to_string(finish.m_lat) << "," << std::to_string(finish.m_lon)
<< "&key=" << GetAccessToken() << "&alternatives=true"
<< "&departure_time=" << secondFromEpoch;
return ss.str();
}
} // namespace google
} // namespace api
} // namespace routing_quality

View file

@ -0,0 +1,37 @@
#pragma once
#include "routing/routing_quality/api/api.hpp"
#include "routing/routing_quality/api/google/types.hpp"
#include <cstdint>
#include <string>
namespace routing_quality
{
namespace api
{
namespace google
{
class GoogleApi : public RoutingApi
{
public:
explicit GoogleApi(std::string const & token);
// According to:
// https://developers.google.com/maps/faq#usage_apis
static uint32_t constexpr kMaxRPS = 50;
static std::string const kApiName;
// RoutingApi overrides:
// @{
Response CalculateRoute(Params const & params, int32_t startTimeZoneUTC) const override;
// @}
private:
GoogleResponse MakeRequest(Params const & params, int32_t startTimeZoneUTC) const;
std::string GetDirectionsURL(Params const & params, int32_t startTimeZoneUTC) const;
};
} // namespace google
} // namespace api
} // namespace routing_quality

View file

@ -0,0 +1,32 @@
#include "routing/routing_quality/api/google/types.hpp"
#include <iomanip>
#include <sstream>
#include <tuple>
namespace routing_quality
{
namespace api
{
namespace google
{
bool LatLon::operator==(LatLon const & rhs) const
{
return std::tie(m_lat, m_lon) == std::tie(rhs.m_lat, rhs.m_lon);
}
bool Step::operator==(Step const & rhs) const
{
return std::tie(m_startLocation, m_endLocation) == std::tie(rhs.m_startLocation, rhs.m_endLocation);
}
std::string DebugPrint(LatLon const & latlon)
{
std::stringstream ss;
ss << std::setprecision(20);
ss << "google::LatLon(" << latlon.m_lat << ", " << latlon.m_lon << ")";
return ss.str();
}
} // namespace google
} // namespace api
} // namespace routing_quality

View file

@ -0,0 +1,77 @@
#pragma once
#include "routing/routing_quality/api/api.hpp"
#include "base/visitor.hpp"
#include <string>
#include <vector>
namespace routing_quality
{
namespace api
{
namespace google
{
struct LatLon
{
DECLARE_VISITOR(visitor(m_lat, "lat"), visitor(m_lon, "lng"))
bool operator==(LatLon const & rhs) const;
double m_lat = 0.0;
double m_lon = 0.0;
};
struct Step
{
DECLARE_VISITOR(visitor(m_startLocation, "start_location"), visitor(m_endLocation, "end_location"))
bool operator==(Step const & rhs) const;
LatLon m_startLocation;
LatLon m_endLocation;
};
struct Duration
{
DECLARE_VISITOR(visitor(m_seconds, "value"))
double m_seconds = 0.0;
};
struct Distance
{
DECLARE_VISITOR(visitor(m_meters, "value"))
double m_meters = 0.0;
};
struct Leg
{
DECLARE_VISITOR(visitor(m_distance, "distance"), visitor(m_duration, "duration"), visitor(m_steps, "steps"))
Distance m_distance;
Duration m_duration;
std::vector<Step> m_steps;
};
struct Route
{
DECLARE_VISITOR(visitor(m_legs, "legs"))
std::vector<Leg> m_legs;
};
struct GoogleResponse
{
DECLARE_VISITOR(visitor(m_routes, "routes"))
ResultCode m_code = ResultCode::Error;
std::vector<Route> m_routes;
};
std::string DebugPrint(LatLon const & latlon);
} // namespace google
} // namespace api
} // namespace routing_quality