calculateRoute method

  1. @override
Future<RouteResult> calculateRoute(
  1. RouteRequest request
)
override

Calculate a route for the given request.

Implementation

@override
Future<RouteResult> calculateRoute(RouteRequest request) async {
  final stopwatch = Stopwatch()..start();

  final requestBody = jsonEncode({
    'locations': [
      {'lat': request.origin.latitude, 'lon': request.origin.longitude},
      {
        'lat': request.destination.latitude,
        'lon': request.destination.longitude,
      },
    ],
    'costing': request.costing,
    'directions_options': {
      'language': request.language,
      'units': 'kilometers',
    },
    'costing_options': {
      request.costing: {'use_highways': 0.8, 'use_tolls': 0.5},
    },
  });

  final uri = Uri.parse('$baseUrl/route');

  try {
    final response = await _client
        .post(
          uri,
          headers: {'Content-Type': 'application/json'},
          body: requestBody,
        )
        .timeout(routeTimeout);

    stopwatch.stop();

    // Decode bytes as UTF-8 explicitly: response.body honors the
    // content-type charset header and falls back to Latin-1 when a server
    // omits it. Valhalla returns fully-localized instruction text (e.g.
    // Japanese via directions_options.language), so a charset-less server
    // would mojibake the whole narration — a larger exposure than OSRM's
    // street names.
    final bodyText = utf8.decode(response.bodyBytes);

    if (response.statusCode != 200) {
      final errorBody = _tryParseJson(bodyText);
      final errorMsg = errorBody?['error'] ?? bodyText;
      throw RoutingException(
        'Valhalla route failed (${response.statusCode}): $errorMsg',
      );
    }

    final json = jsonDecode(bodyText) as Map<String, dynamic>;
    return _parseRouteResponse(json, stopwatch.elapsed);
  } on RoutingException {
    rethrow;
  } on Exception catch (e) {
    throw RoutingException('Valhalla network error: $e');
  }
}