Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## Unreleased
ADDED:
- `proxy` source and resource type: Road2 translates `route` and `isochrone` requests to a remote HTTP service (e.g. a Valhalla container) using a declarative mapping file (`source.proxy.url`, `source.proxy.mapping`). See `documentation/configuration/sources/proxy.source` and `valhalla-proxy.mapping`.

## 3.1.8
FIXED:
- Service process crashed with OOM at startup: `assert.deepStrictEqual(x, {})` used as an emptiness check always failed on non-empty catalogs, and building the assertion message serialized the whole object graph (servers, resources, sources). Replaced with `Object.keys(x).length === 0` checks.
Expand Down
45 changes: 45 additions & 0 deletions documentation/configuration/resources/proxy.resource
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"resource": {
"id": "valhalla-proxy",
"type": "proxy",
"description": "Ressource proxy vers un service Valhalla.",
"sources": ["valhalla-proxy"],
"availableOperations": [
{
"id": "route",
"parameters": [
{ "id": "resource", "values": ["valhalla-proxy"] },
{ "id": "start", "values": { "bbox": "-180,-90,180,90", "projection": "EPSG:4326" } },
{ "id": "end", "values": { "bbox": "-180,-90,180,90", "projection": "EPSG:4326" } },
{ "id": "profile", "defaultValueContent": "car", "values": ["car", "pedestrian"] },
{ "id": "optimization", "defaultValueContent": "fastest", "values": ["fastest", "shortest"] },
{ "id": "intermediates", "values": { "bbox": "-180,-90,180,90", "projection": "EPSG:4326" } },
{ "id": "getSteps", "defaultValueContent": "true" },
{ "id": "waysAttributes", "values": ["name"] },
{ "id": "geometryFormat", "defaultValueContent": "geojson", "values": ["geojson", "polyline", "wkt"] },
{ "id": "bbox", "defaultValueContent": "true" },
{ "id": "projection", "defaultValueContent": "EPSG:4326", "values": ["EPSG:4326", "EPSG:2154"] },
{ "id": "date_time" },
{ "id": "timeUnit", "defaultValueContent": "minute", "values": ["hour", "minute", "second", "standard"] },
{ "id": "distanceUnit", "defaultValueContent": "meter", "values": ["meter", "kilometer"] }
]
},
{
"id": "isochrone",
"parameters": [
{ "id": "resource", "values": ["valhalla-proxy"] },
{ "id": "point", "values": { "bbox": "-180,-90,180,90", "projection": "EPSG:4326" } },
{ "id": "costType", "defaultValueContent": "time", "values": ["time", "distance"] },
{ "id": "costValue", "values": { "min": 100, "max": 50000 } },
{ "id": "profile", "defaultValueContent": "car", "values": ["car", "pedestrian"] },
{ "id": "direction", "defaultValueContent": "departure", "values": ["departure", "arrival"] },
{ "id": "date_time" },
{ "id": "projection", "defaultValueContent": "EPSG:4326", "values": ["EPSG:4326", "EPSG:2154"] },
{ "id": "geometryFormat", "defaultValueContent": "geojson", "values": ["geojson", "polyline", "wkt"] },
{ "id": "timeUnit", "defaultValueContent": "second", "values": ["hour", "minute", "second"] },
{ "id": "distanceUnit", "defaultValueContent": "meter", "values": ["meter", "kilometer"] }
]
}
]
}
}
22 changes: 22 additions & 0 deletions documentation/configuration/sources/osrm-proxy.mapping
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"route": {
"method": "GET",
"path": {
"$concat": [
"/route/v1/",
"${cost.profile}",
"/",
{ "$join": { "from": "coordinates", "separator": ";", "as": "${item.0},${item.1}" } }
]
},
"query": {
"overview": "full",
"geometries": "polyline6",
"steps": "true"
},
"response": {
"format": "osrm",
"polylinePrecision": 6
}
}
}
20 changes: 20 additions & 0 deletions documentation/configuration/sources/osrm-proxy.source
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "osrm-proxy-car",
"description": "Service osrm-routed distant (profil voiture)",
"type": "proxy",
"projection": "EPSG:4326",
"bbox": "-180,-90,180,90",
"proxy": {
"url": "http://osrm:5000",
"timeout": 10000,
"mapping": "/home/docker/config/osrm-proxy.mapping"
},
"costs": [
{
"profile": "car",
"optimization": "fastest",
"costType": "time",
"parameters": { "profile": "driving" }
}
]
}
48 changes: 48 additions & 0 deletions documentation/configuration/sources/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Source et ressource de type proxy

Une source `proxy` ne calcule rien : elle traduit la requête Road2 (`route`, `isochrone`) en requête HTTP vers un service distant (par exemple Valhalla déployé via son image Docker), puis convertit la réponse au format Road2. Une ressource de type `proxy` s'appuie sur ces sources.

Exemples : `proxy.source`, `valhalla-proxy.mapping` et `../resources/proxy.resource`.

## Configuration de la source

| Clé | Description |
|---|---|
| `type` | `proxy` |
| `proxy.url` | URL du service (http/https) |
| `proxy.timeout` | Timeout en ms (optionnel, 30000 par défaut) |
| `proxy.mapping` | Chemin du fichier de mapping, ou objet de mapping en ligne |
| `costs[]` | `profile`, `optimization`, `costType` pour le choix de la source, et `parameters` : variables libres accessibles dans le mapping sous `cost.*` |

Le nom de la ressource est son `id` dans le fichier `.resource`.

## Fichier de mapping

Un objet par opération (`route`, `isochrone`) :

- `method` : `GET` ou `POST` (défaut `POST`)
- `path` : chemin ajouté à `proxy.url`
- `query` : paramètres d'URL (template)
- `body` : corps JSON (template, pour `POST`)
- `headers` : en-têtes (template)
- `response.format` : `osrm` (route) ou `geojson` (isochrone) ; `response.root` : chemin pointé vers la réponse utile ; `response.polylinePrecision` : précision des polylines (5 par défaut)

### Variables disponibles

- route : `coordinates` (liste de `[x, y]` dans la projection de la source), `start`, `end`, `intermediates`, `optimization`
- isochrone : `point`, `costType`, `costValue`, `direction`
- communes : `resource`, `profile`, `date_time`, `constraints` (champs bannis), `cost` (`costs[].parameters`)

### Templates

- `"${variable.chemin}"` : valeur typée si c'est toute la chaîne, sinon interpolation. Fonctionne aussi dans les clés.
- Les valeurs indéfinies sont omises.
- `{"$for": "liste", "$as": template}` : itération (`item`, `index`)
- `{"$if": "variable", "$then": t, "$else": t}`
- `{"$divide": [a, b]}`, `{"$multiply": [a, b]}`
- `{"$lookup": {"value": "${x}", "table": {...}, "default": v}}`
- `{"$fromEntries": {"from": "liste", "key": "${item}", "value": v}}`
- `{"$concat": [t1, t2, ...]}` : concaténation (utile pour construire `path`)
- `{"$join": {"from": "liste", "separator": ";", "as": template}}` : jointure des éléments d'une liste

Mappings fournis : `valhalla-proxy.mapping` (route et isochrone) et `osrm-proxy.mapping` (route seulement, OSRM n'a pas d'isochrone), avec les sources d'exemple `proxy.source` et `osrm-proxy.source`.
32 changes: 32 additions & 0 deletions documentation/configuration/sources/proxy.source
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"id": "valhalla-proxy",
"description": "Service Valhalla distant",
"type": "proxy",
"projection": "EPSG:4326",
"bbox": "-180,-90,180,90",
"proxy": {
"url": "http://valhalla:8002",
"timeout": 10000,
"mapping": "/home/docker/config/valhalla-proxy.mapping"
},
"costs": [
{
"profile": "car",
"optimization": "fastest",
"costType": "time",
"parameters": { "costing": "auto", "contourDivisor": 60 }
},
{
"profile": "car",
"optimization": "shortest",
"costType": "distance",
"parameters": { "costing": "auto_shorter", "contourDivisor": 1000 }
},
{
"profile": "pedestrian",
"optimization": "shortest",
"costType": "distance",
"parameters": { "costing": "pedestrian", "contourDivisor": 1000, "options": { "walking_speed": 4 } }
}
]
}
48 changes: 48 additions & 0 deletions documentation/configuration/sources/valhalla-proxy.mapping
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"route": {
"method": "POST",
"path": "/route",
"body": {
"locations": {
"$for": "coordinates",
"$as": { "lat": "${item.1}", "lon": "${item.0}" }
},
"costing": "${cost.costing}",
"costing_options": { "${cost.costing}": "${cost.options}" },
"format": "osrm",
"date_time": {
"$if": "date_time",
"$then": { "type": 1, "value": "${date_time}" }
}
},
"response": {
"format": "osrm",
"polylinePrecision": 6
}
},
"isochrone": {
"method": "POST",
"path": "/isochrone",
"body": {
"locations": [
{ "lat": "${point.1}", "lon": "${point.0}" }
],
"costing": "${cost.costing}",
"costing_options": { "${cost.costing}": "${cost.options}" },
"contours": [
{ "${costType}": { "$divide": ["${costValue}", "${cost.contourDivisor}"] } }
],
"reverse": {
"$lookup": { "value": "${direction}", "table": { "arrival": true }, "default": false }
},
"polygons": true,
"date_time": {
"$if": "date_time",
"$then": { "type": 1, "value": "${date_time}" }
}
},
"response": {
"format": "geojson"
}
}
}
61 changes: 61 additions & 0 deletions src/js/resources/proxyResource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

const valhallaResource = require('./valhallaResource');
const log4js = require('log4js');

var LOGGER = log4js.getLogger("PROXYRESOURCE");

/**
*
* @class
* @name proxyResource
* @description Classe modélisant une ressource qui délègue les calculs à des sources de type proxy.
* La sélection de la source suit la même logique que valhallaResource (profile/optimization ou profile/costType).
*
*/
module.exports = class proxyResource extends valhallaResource {

/**
*
* @function
* @name initResource
* @description Créer les liens entre la ressource et ses sources proxy
* @param {SourceManager} sourceManager - Manager des sources du service
* @return {boolean}
*
*/
initResource(sourceManager) {

for (const sourceId of this._configuration.sources) {

if (!sourceManager.isLoadedSourceAvailable(sourceId)) {
LOGGER.error("La source n'a pas été chargée");
return false;
}

const source = sourceManager.getSourceById(sourceId);

if (source.type !== "proxy") {
LOGGER.error("La source n'est pas de type 'proxy'");
return false;
}

for (const operation of this._configuration.availableOperations) {
if (!source.isOperationMapped(operation.id)) {
LOGGER.error("L'opération " + operation.id + " n'est pas définie dans le mapping de la source " + sourceId);
return false;
}
}

for (const cost of source.configuration.costs) {
this._linkedSource[cost.profile + cost.optimization] = source.configuration.id;
this._linkedSource[cost.profile + cost.costType] = source.configuration.id;
}

}

return true;

}

}
6 changes: 5 additions & 1 deletion src/js/resources/resourceManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const path = require('path');
const osrmResource = require('../resources/osrmResource');
const pgrResource = require('../resources/pgrResource');
const valhallaResource = require('../resources/valhallaResource');
const proxyResource = require('../resources/proxyResource');
const log4js = require('log4js');

// Création du LOGGER
Expand Down Expand Up @@ -36,7 +37,8 @@ module.exports = class resourceManager {
this._operationsByType = {
"osrm": ["nearest", "route"],
"pgr": ["route", "isochrone"],
"valhalla": ["route", "isochrone"]
"valhalla": ["route", "isochrone"],
"proxy": ["route", "isochrone"]
};

// Manager de source
Expand Down Expand Up @@ -414,6 +416,8 @@ module.exports = class resourceManager {
resource = new pgrResource(resourceJsonObject, resourceOperationHash);
} else if (resourceJsonObject.resource.type === "valhalla") {
resource = new valhallaResource(resourceJsonObject, resourceOperationHash);
} else if (resourceJsonObject.resource.type === "proxy") {
resource = new proxyResource(resourceJsonObject, resourceOperationHash);
} else {
LOGGER.error("Type de la ressource inconnue");
return false;
Expand Down
Loading
Loading