in Source/Requests/RouteRequest.cs [123:294]
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
Response response = null;
if (WaypointOptimization != null && WaypointOptimization.HasValue && Waypoints.Count >= 2)
{
var wpHash = ServiceHelper.GetSequenceHashCode<SimpleWaypoint>(Waypoints);
var optionHash = Enum.GetName(typeof(TspOptimizationType), WaypointOptimization);
var mode = TravelModeType.Driving;
DateTime? depart = null;
if (RouteOptions != null)
{
optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteOptions.TimeType);
if (RouteOptions.TimeType == RouteTimeType.Departure && RouteOptions.DateTime != null && RouteOptions.DateTime.HasValue)
{
depart = RouteOptions.DateTime;
optionHash += "|" + RouteOptions.DateTime.ToString();
}
mode = RouteOptions.TravelMode;
optionHash += "|" + Enum.GetName(typeof(TravelModeType), mode);
}
else
{
optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteTimeType.Departure);
}
//Check to see if the waypoints have changed since they were last optimized.
if (waypointsHash != wpHash || string.Compare(optimizationOptionHash, optionHash) != 0)
{
var tspResult = await TravellingSalesmen.Solve(Waypoints, mode, WaypointOptimization, depart, BingMapsKey).ConfigureAwait(false);
Waypoints = tspResult.OptimizedWaypoints;
//Update the stored hashes to prevent unneeded optimizations in the future if not needed.
waypointsHash = ServiceHelper.GetSequenceHashCode<SimpleWaypoint>(Waypoints);
optimizationOptionHash = optionHash;
}
}
var requestUrl = GetRequestUrl();
int startIdx = 0;
int endIdx = 0;
if (Waypoints.Count <= batchSize)
{
if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
{
var requestBody = GetTruckPostRequestBody(startIdx, out endIdx);
response = await ServiceHelper.MakeAsyncPostRequest(requestUrl, requestBody, remainingTimeCallback).ConfigureAwait(false);
}
else
{
remainingTimeCallback?.Invoke(1);
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(requestUrl)).ConfigureAwait(false))
{
response = ServiceHelper.DeserializeStream<Response>(responseStream);
}
}
}
else
{
//There is more waypoints than the batchSize value (default 25), break it up into multiple requests. Only allow a single route in the response and no tolerances.
if (RouteOptions != null)
{
if (RouteOptions.MaxSolutions > 1)
{
RouteOptions.MaxSolutions = 1;
}
RouteOptions.Tolerances = null;
}
if (Waypoints == null)
{
throw new Exception("Waypoints not specified.");
}
else if (Waypoints.Count < 2)
{
throw new Exception("Not enough Waypoints specified.");
}
else if (Waypoints[0].IsViaPoint || Waypoints[Waypoints.Count - 1].IsViaPoint)
{
throw new Exception("Start and end waypoints must not be ViaWaypoints.");
}
var requestUrls = new List<string>();
var requestBodies = new List<string>();
while (endIdx < Waypoints.Count - 1)
{
if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
{
requestUrls.Add(requestUrl);
requestBodies.Add(GetTruckPostRequestBody(startIdx, out endIdx));
}
else
{
requestUrls.Add(GetRequestUrl(startIdx, out endIdx));
requestBodies.Add(null);
}
startIdx = endIdx - 1;
}
if (remainingTimeCallback != null)
{
int batchProcessingTime = (int)Math.Ceiling((double)requestUrls.Count / (double)ServiceManager.QpsLimit);
if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
{
//Use an average of 4 seconds per batch for processing truck routes as multiplier for the processing time.
//Other routes typically take less than a second and as such 1 second is used for those but isn't needed as a multiplier.
batchProcessingTime *= 4;
}
remainingTimeCallback(batchProcessingTime);
}
var routes = new Route[requestUrls.Count];
var routeTasks = new List<Task>();
for (var i = 0; i < routes.Length; i++)
{
routeTasks.Add(CalculateRoute(requestUrls[i], requestBodies[i], i, routes));
}
if (routeTasks.Count > 0)
{
await ServiceHelper.WhenAllTaskLimiter(routeTasks).ConfigureAwait(false);
}
try
{
response = new Response()
{
StatusCode = 200,
StatusDescription = "OK",
ResourceSets = new ResourceSet[]
{
new ResourceSet()
{
Resources = new Resource[]
{
await MergeRoutes(routes).ConfigureAwait(false)
}
}
}
};
}
catch (Exception ex)
{
return new Response()
{
StatusCode = 500,
StatusDescription = "Error",
ErrorDetails = new string[]
{
ex.Message
}
};
}
}
return response;
}