diff --git a/changelog.md b/changelog.md index c8431a4..9d308c9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # CHANGELOG +## 3.0.0 +CHANGED: +- (breaking) Updated OSRM to 6.0.0 +- Dockerfile now uses Node 24.12 on debian trixie +- Valhalla source now uses JS binding instead of child process + +UPDATED: +- Updated all package.json dependencies to last versions (08/01/2026) + ## 2.3.1 FIXED: - invalid isochrone geometries diff --git a/docker/distributions/debian/Dockerfile b/docker/distributions/debian/Dockerfile index 9b69b86..8f69302 100644 --- a/docker/distributions/debian/Dockerfile +++ b/docker/distributions/debian/Dockerfile @@ -1,10 +1,7 @@ -### TODO : Supprimer la compilation et l'installation de Valhalla dès que l'on aura un binding NodeJS pour lui et donc repasser sur une image node -FROM ghcr.io/valhalla/valhalla@sha256:6fb108a960bdc63c12b1c92ab04517a0c56a019ef45c9b9c8cf847d8de9db72b +FROM node:24.12-trixie-slim -### Mise à jour des +### Mise à jour des paquets RUN apt-get update && apt-get upgrade -y -RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - && \ - apt-get install -y nodejs ### Dossier contenant la configuration de Road2 WORKDIR /home/docker/config @@ -19,7 +16,7 @@ COPY documentation/apis ./documentation/apis COPY *.json ./ ### Installation des dépendances de l'application NodeJS -RUN npm install && npm install -g mocha eslint jsdoc nyc +RUN npm install --no-optional && npm install -g mocha eslint jsdoc nyc ### Volume partagé pour lire les données VOLUME ["/home/docker/data"] diff --git a/package.json b/package.json index 6c5aea4..1f6eee5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "road2", - "version": "2.2.8", + "version": "3.0.0", "description": "Calcul d'itinéraire", "author": "RDEV - IGN", "main": "src/js/road2.js", @@ -16,22 +16,23 @@ "debug": "env NODE_ENV=debug node --inspect=0.0.0.0:9229 ./src/js/road2.js" }, "dependencies": { - "@mapbox/polyline": "1.1.1", - "@turf/turf": "6.5.0", - "assert": "2.0.0", + "@mapbox/polyline": "1.2.1", + "@turf/turf": "7.3.0", + "assert": "2.1.0", "cors": "2.8.5", - "express": "4.18.2", - "got": "11.8.2", - "helmet": "6.0.1", - "https-proxy-agent": "5.0.1", - "log4js": "6.7.1", - "nconf": "0.12.0", - "proj4": "2.8.0", - "swagger-ui-express": "4.6.3" + "express": "5.2.1", + "got": "14.6.6", + "helmet": "8.1.0", + "https-proxy-agent": "7.0.6", + "log4js": "6.9.1", + "nconf": "0.13.0", + "proj4": "2.20.2", + "swagger-ui-express": "5.0.1" }, "optionalDependencies": { - "osrm": "5.26.0", - "pg": "8.9.0" + "@project-osrm/osrm": "6.0.0", + "pg": "8.16.3", + "@valhallajs/valhallajs": "3.6.1" }, "devDependencies": { "sinon": "^7.2.7", @@ -46,7 +47,8 @@ "express", "log4js", "nconf", - "osrm", + "@project-osrm/osrm", + "@valhallajs/valhallajs", "pg", "@mapbox/polyline", "@turf/turf", diff --git a/src/js/sources/osrmSource.js b/src/js/sources/osrmSource.js index b5a507c..3404bda 100644 --- a/src/js/sources/osrmSource.js +++ b/src/js/sources/osrmSource.js @@ -116,7 +116,7 @@ module.exports = class osrmSource extends Source { // Chargement du fichier OSRM if (OSRM) { - this._osrm = new OSRM(osrmFile); + this._osrm = new OSRM({path: osrmFile, algorithm: "CH"}); super.connected = true; } else { throw errorManager.createError("OSRM is not available"); @@ -311,7 +311,7 @@ module.exports = class osrmSource extends Source { LOGGER.error("osrm error for nearest :"); LOGGER.error(err); reject("Internal OSRM error"); - + } else { LOGGER.debug("osrm response for nearest :"); @@ -569,7 +569,7 @@ module.exports = class osrmSource extends Source { } nativeSteps[k].intersections = nativeIntersections; - // Add maneuver extra + // Add maneuver extra let nativeManeuver = {}; // Test with hasOwnProperty because it can be 0 inside this property if (currentOsrmRouteStep.maneuver.hasOwnProperty("bearing_before")) { @@ -585,7 +585,7 @@ module.exports = class osrmSource extends Source { } nativeManeuver.location = [location.x, location.y]; } - + nativeSteps[k].maneuver = nativeManeuver; } @@ -616,7 +616,7 @@ module.exports = class osrmSource extends Source { * Ce traitement est placé ici car c'est à la source de renvoyer une réponse adaptée au proxy. * C'est cette fonction qui doit vérifier le contenu de la réponse. Une fois la réponse envoyée * au proxy, on considère qu'elle est correcte. - * @param {nearestRequest} nearestRequest - Objet nearestRequest + * @param {nearestRequest} nearestRequest - Objet nearestRequest * @param {osrmResponse} osrmResponse - Objet osrmResponse, réponse renvoyée par osrm * */ @@ -633,13 +633,13 @@ module.exports = class osrmSource extends Source { // Création de la réponse let nearestResponse = new NearestResponse(nearestRequest.resource, nearestRequest.coordinates); - // Récupération de l'ensemble des points de la réponse d'OSRM + // Récupération de l'ensemble des points de la réponse d'OSRM if (osrmResponse.waypoints) { LOGGER.debug(osrmResponse); if (osrmResponse.waypoints.length < 1) { throw errorManager.createError(" OSRM response is invalid: the number of waypoints is lower than 1. "); } else { - + for (let i=0; i < osrmResponse.waypoints.length; i++) { if (osrmResponse.waypoints[i].location) { @@ -668,7 +668,7 @@ module.exports = class osrmSource extends Source { } else { throw errorManager.createError(" OSRM response is invalid: no waypoints. "); } - + return nearestResponse; } diff --git a/src/js/sources/valhallaSource.js b/src/js/sources/valhallaSource.js index 43c21cd..36a269f 100644 --- a/src/js/sources/valhallaSource.js +++ b/src/js/sources/valhallaSource.js @@ -12,16 +12,12 @@ const Step = require('../responses/step'); const Distance = require('../geography/distance'); const Duration = require('../time/duration'); const errorManager = require('../utils/errorManager'); -const { exec } = require('child_process'); const turf = require('@turf/turf'); +const { Actor } = require("@valhallajs/valhallajs") // Création du LOGGER const log4js = require('log4js'); const LOGGER = log4js.getLogger("VALHALLASOURCE"); -// Récupération de la valeur du maxBuffer en variable d'environment variable ou valorisation par défaut (1MB) -const maxBuffer = process.env.EXEC_MAX_BUFFER_SIZE ? parseInt(process.env.EXEC_MAX_BUFFER_SIZE, 10) : 1024 * 1024; -// Récupération de la valeur du timeout pour l'execution du valhalla_service en variable d'environnement ou valorisation par défaut (0) -const execTimeout = process.env.EXEC_TIMEOUT ? parseInt(process.env.EXEC_TIMEOUT, 10) : 0; /** * @@ -195,39 +191,32 @@ module.exports = class valhallaSource extends Source { costingOptionsString += "}}"; // Permet de grandement se simplifier le parsing !! const optionsString = `"directions_options":{"format":"osrm"}`; - const commandString = `valhalla_service ${this._configuration.storage.config} route '{${locationsString},${costingString},${costingOptionsString},${optionsString}}' `; - const options = { maxBuffer: maxBuffer, timeout: execTimeout }; + const commandString = `{${locationsString},${costingString},${costingOptionsString},${optionsString}}`; LOGGER.info(commandString); return new Promise( (resolve, reject) => { try { - exec(commandString, options, (err, stdout, stderr) => { - - // Du moment qu'OSRM a répondu, on considère que la source est joignable - this.state = "green"; - - if (err) { - // mais on ne renvoie pas l'erreur à l'utilisateur - reject(errorManager.createError(" No path found ", 404)); - LOGGER.error("valhalla error for route :"); - LOGGER.error(err); - - } else { + Actor.fromConfigFile(this._configuration.storage.config).then((valhallaActor) => { + valhallaActor.route(commandString).then((valhallaResponse) => { + // Du moment que Valhalla a répondu, on considère que la source est joignable + this.state = "green"; LOGGER.debug("valhalla response for route :"); - LOGGER.debug(stdout); + LOGGER.debug(valhallaResponse); try { - resolve(this.writeRouteResponse(request, stdout)); + resolve(this.writeRouteResponse(request, valhallaResponse)); } catch (error) { reject(error); } - - } - + }).catch((err) => { + // mais on ne renvoie pas l'erreur à l'utilisateur + reject(errorManager.createError(" No path found ", 404)); + LOGGER.error("valhalla error for route :"); + LOGGER.error(err); + }); }); - } catch (error) { // Pour une raison que l'on ignore, la source n'est plus joignable this.state = "red"; @@ -303,39 +292,32 @@ module.exports = class valhallaSource extends Source { const contoursString = `"contours":[{"${request.costType}":${costValue}}]`; const reverseString = `"reverse":${reverse}`; const polygonsString = `"polygons":true`; - const commandString = `valhalla_service ${this._configuration.storage.config} isochrone '{${locationsString},${costingString},${costingOptionsString},${contoursString},${reverseString},${polygonsString}}' `; - const options = { maxBuffer: maxBuffer, timeout: execTimeout }; + const commandString = `{${locationsString},${costingString},${costingOptionsString},${contoursString},${reverseString},${polygonsString}}`; LOGGER.info(commandString); return new Promise( (resolve, reject) => { try { - exec(commandString, options, (err, stdout, stderr) => { - - // Du moment qu'OSRM a répondu, on considère que la source est joignable - this.state = "green"; - - if (err) { - // mais on ne renvoie pas l'erreur à l'utilisateur - LOGGER.error("valhalla error for route :"); - LOGGER.error(err); - reject(errorManager.createError(" No path found ", 404)); - - } else { - - LOGGER.debug("valhalla response for iso :"); - LOGGER.debug(stdout); - - try { - resolve(this.writeIsochroneResponse(request, stdout)); - } catch (error) { - reject(error); - } - - } - - }); - + Actor.fromConfigFile(this._configuration.storage.config).then((valhallaActor) => { + valhallaActor.isochrone(commandString).then((valhallaResponse) => { + // Du moment que Valhalla a répondu, on considère que la source est joignable + this.state = "green"; + + LOGGER.debug("valhalla response for iso :"); + LOGGER.debug(valhallaResponse); + + try { + resolve(this.writeIsochroneResponse(request, valhallaResponse)); + } catch (error) { + reject(error); + } + }).catch((err) => { + // mais on ne renvoie pas l'erreur à l'utilisateur + reject(errorManager.createError(" No path found ", 404)); + LOGGER.error("valhalla error for route :"); + LOGGER.error(err); + }); + }); } catch (error) { // Pour une raison que l'on ignore, la source n'est plus joignable this.state = "red";