From 1b496f25ba5f4efc7d84953cf095325d54ffeca6 Mon Sep 17 00:00:00 2001 From: Loic Date: Fri, 17 Feb 2023 17:00:12 +0100 Subject: [PATCH 1/7] wip: creation of health objects/algo --- src/js/administrator/administrator.js | 97 ++++++++++++++++ .../apis/admin/1.0.0/controller/controller.js | 83 ++++++++++++++ src/js/apis/admin/1.0.0/index.js | 31 +++++- src/js/requests/healthRequest.js | 54 +++++++++ src/js/requests/isochroneRequest.js | 28 ++++- src/js/requests/nearestRequest.js | 28 ++++- src/js/requests/request.js | 26 ----- src/js/requests/routeRequest.js | 28 ++++- src/js/responses/healthResponse.js | 104 ++++++++++++++++++ src/js/service/serviceAdministered.js | 11 ++ src/js/service/serviceInsider.js | 15 +++ src/js/service/serviceManager.js | 44 ++++++++ src/js/service/serviceProcess.js | 12 ++ src/js/sources/source.js | 4 +- 14 files changed, 529 insertions(+), 36 deletions(-) create mode 100644 src/js/apis/admin/1.0.0/controller/controller.js create mode 100644 src/js/requests/healthRequest.js create mode 100644 src/js/responses/healthResponse.js diff --git a/src/js/administrator/administrator.js b/src/js/administrator/administrator.js index c4f2f075..7fa7f58b 100644 --- a/src/js/administrator/administrator.js +++ b/src/js/administrator/administrator.js @@ -9,6 +9,7 @@ const assert = require('assert').strict; const serverManager = require('../server/serverManager'); const serviceManager = require('../service/serviceManager'); const apisManager = require('../apis/apisManager'); +const HealthResponse = require('../responses/healthResponse'); // Création du LOGGER const LOGGER = log4js.getLogger("ADMINISTRATOR"); @@ -324,6 +325,9 @@ module.exports = class Administrator { // Application Express let administrator = express(); + // Stockage de l'instance Administrator dans l'app expressJS afin que les informations soient accessibles par les requêtes + administrator.set("administrator", this); + // Gestion des en-têtes avec helmet selon les préconisations d'ExpressJS administrator.use(helmet()); @@ -474,6 +478,99 @@ module.exports = class Administrator { } + /** + * + * @function + * @name computeHealthRequest + * @description Gestion de la requête d'état du serveur + * Cette fonction ne suit pas le m$eme chemin que les autres car elle est globale + * et ne concerne pas un service particulier + * Elle renvoit une healthResponse complète et c'est au niveau de l'API qu'on peut la modifier + * @param {HealthRequest} healthRequest - Instance de la classe HealthRequest + * + */ + + async computeHealthRequest(healthRequest) { + + LOGGER.info("computeHealthRequest..."); + + let gotOrange = false; + let gotRed = false; + + let healthResponse = new HealthResponse(); + + // Étant donné que l'administrateur est en train de répondre, on le met au vert + // À voir s'il y a des fonctionnalités qui pourraient le mettre à l'orange ou au rouge + // Dans ce cas là, il faudra que l'administrator ait un attribut d'état et que celui-ci soit lu dans cette fonction + healthResponse.adminState = "green"; + + // Pour chaque service, on demande au serviceManager l'état du service + for (let i = 0; i < this._configuration.administration.services.length; i++) { + + let curServiceId = this._configuration.administration.services[i].id; + LOGGER.debug("Demande de l'état du service : " + curServiceId); + let curHealthResponse = await this._serviceManager.computeRequest(curServiceId, healthRequest); + + if (!curHealthResponse.serviceStates[0]) { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } + + if (!curHealthResponse.serviceStates[0].state) { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné d'état"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } + + // Pour la suite, on note la présence d'orange et de rouge dans les services + if (curHealthResponse.serviceStates[0].state === "orange") { + LOGGER.debug("Le service " + curServiceId + " est orange"); + gotOrange = true; + } else if (curHealthResponse.serviceStates[0].state === "red") { + LOGGER.debug("Le service " + curServiceId + " est red"); + gotRed = true; + } else if (curHealthResponse.serviceStates[0].state === "green") { + // Tout va bien, rien à faire + LOGGER.debug("Le service " + curServiceId + " est green"); + } else { + // Cela ne devrait pas arriver, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " est dans un état inconnu"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } + + // On stocke le retour de ce service + healthResponse.serviceStates.push(curHealthResponse.serviceStates[0]); + + } + + // En fonction des états définis précédemment, on va définir l'état global + // Pour faire simple : + // - global est orange si un des services est orange + // - un service est orange si une des sources est indisponible (cela est traité dans le service) + // - global est rouge si un des services est rouge + // - service est rouge si la moitié, ou plus, de ses sources sont indisponibles (cela est traité dans le service) + if (gotRed) { + healthResponse.adminState = "red"; + } else { + if (gotOrange) { + healthResponse.adminState = "orange"; + } + } + + return healthResponse; + + } + } diff --git a/src/js/apis/admin/1.0.0/controller/controller.js b/src/js/apis/admin/1.0.0/controller/controller.js new file mode 100644 index 00000000..8a18cc86 --- /dev/null +++ b/src/js/apis/admin/1.0.0/controller/controller.js @@ -0,0 +1,83 @@ +'use strict'; + +const errorManager = require('../../../../utils/errorManager'); +const log4js = require('log4js'); +const HealthRequest = require('../../../../requests/healthRequest'); + +var LOGGER = log4js.getLogger("CONTROLLER"); + +module.exports = { + + /** + * + * @function + * @name checkHealthParameters + * @description Vérification des paramètres d'une requête sur /health + * @param {object} parameters - ensemble des paramètres de la requête + * @return {object} HealthRequest - Instance de la classe HealthRequest + * + */ + + checkHealthParameters: function(parameters) { + + LOGGER.debug("checkHealthParameters()"); + + // Il n'y a aucun paramètre obligatoire donc on peut créer l'objet request + let healthRequest = new HealthRequest(); + + // Verbose + if (parameters.verbose) { + + LOGGER.debug("user verbose:"); + LOGGER.debug(parameters.verbose); + + if (parameters.verbose === "true") { + healthRequest.verbose = true; + } else if (parameters.verbose === "false") { + healthRequest.verbose = false; + } else { + throw errorManager.createError(" Parameter 'verbose' is invalid: value should be 'true' or 'false'", 400); + } + + } else { + // paramètre non obligatoire + LOGGER.debug("default verbose used: false"); + } + + return healthRequest; + + }, + + /** + * + * @function + * @name writeHealthResponse + * @description Ré-écriture de la réponse pour une requête sur /health + * @param {object} HealthRequest - Instance de la classe HealthRequest + * @param {object} HealthResponse - Instance de la classe HealthResponse + * @return {object} userResponse - Réponse envoyée à l'utilisateur + * + */ + + writeHealthResponse: function(healthRequest, healthResponse) { + + let userResponse = {}; + + LOGGER.debug("writeHealthResponse()"); + + userResponse.state = healthResponse.globalState; + + if (!healthRequest.verbose) { + return userResponse; + } + + userResponse.administrator = {}; + userResponse.administrator.state = healthResponse.adminState; + + userResponse.services = new Array(); + + return userResponse; + + } + +} \ No newline at end of file diff --git a/src/js/apis/admin/1.0.0/index.js b/src/js/apis/admin/1.0.0/index.js index ef879b34..9cc5829a 100644 --- a/src/js/apis/admin/1.0.0/index.js +++ b/src/js/apis/admin/1.0.0/index.js @@ -4,6 +4,7 @@ const express = require('express'); const log4js = require('log4js'); const packageJSON = require('../../../../../package.json'); +const controller = require('./controller/controller'); var LOGGER = log4js.getLogger("ADMIN"); var router = express.Router(); @@ -32,7 +33,6 @@ router.route("/version") // Health // Pour avoir l'état du service -// TODO: implémenter une véritable vérification de l'état router.route("/health") .get(async function(req, res, next) { @@ -40,10 +40,31 @@ router.route("/health") LOGGER.debug("requete GET sur /admin/1.0.0/health?"); LOGGER.debug(req.originalUrl); - res.set('content-type', 'application/json'); - res.status(200).json({ - "state": "green" - }); + // On récupère l'instance d'Administrator pour répondre aux requêtes + let administrator = req.app.get("administrator"); + + // on récupère l'ensemble des paramètres de la requête + let parameters = req.query; + LOGGER.debug(parameters); + + try { + + // Vérification des paramètres de la requête + const healthRequest = controller.checkHealthParameters(parameters); + LOGGER.debug(healthRequest); + // Envoie au service et récupération de l'objet réponse + const healthResponse = await administrator.computeHealthRequest(healthRequest); + LOGGER.debug(healthResponse); + // Formattage de la réponse + const userResponse = controller.writeHealthResponse(healthRequest, healthResponse); + LOGGER.debug(userResponse); + + res.set('content-type', 'application/json'); + res.status(200).json(userResponse); + + } catch (error) { + return next(error); + } }); diff --git a/src/js/requests/healthRequest.js b/src/js/requests/healthRequest.js new file mode 100644 index 00000000..edcba9ac --- /dev/null +++ b/src/js/requests/healthRequest.js @@ -0,0 +1,54 @@ +'use strict'; + +const Request = require('./request'); + +/** +* +* @class +* @name healthRequest +* @description Classe modélisant une requête d'état du serveur Road2. +* +*/ + +module.exports = class healthRequest extends Request { + + /** + * + * @function + * @name constructor + * @description Constructeur de la classe healthRequest + * + */ + + constructor() { + + super("health","healthRequest"); + + this._verbose = false; + + } + + /** + * + * @function + * @name get verbose + * @description Récupérer le caractère verbeux de la requête + * + */ + get verbose() { + return this._verbose; + } + + /** + * + * @function + * @name set verbose + * @description Attribuer le caractère verbeux de la requête. + * @param {Boolean} + * + */ + set verbose(v) { + this._verbose = v; + } + +} diff --git a/src/js/requests/isochroneRequest.js b/src/js/requests/isochroneRequest.js index 62e248b6..e4ed838b 100644 --- a/src/js/requests/isochroneRequest.js +++ b/src/js/requests/isochroneRequest.js @@ -35,7 +35,10 @@ module.exports = class isochroneRequest extends Request { constructor(resource, point, costType, costValue, profile, direction, askedProjection, geometryFormat, timeUnit, distanceUnit) { // Constructeur parent - super("isochrone", resource, "isochroneRequest"); + super("isochrone", "isochroneRequest"); + + // Ressource concernée + this._resource = resource; // Initialisation du reste des paramètres this._point = point; @@ -61,6 +64,29 @@ module.exports = class isochroneRequest extends Request { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la requête + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la requête + * @param {string} res - Id de la ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/src/js/requests/nearestRequest.js b/src/js/requests/nearestRequest.js index b640d838..e0aebea3 100644 --- a/src/js/requests/nearestRequest.js +++ b/src/js/requests/nearestRequest.js @@ -28,7 +28,10 @@ module.exports = class nearestRequest extends Request { constructor(resource, coordinates) { // Constructeur parent - super("nearest", resource, "nearestRequest"); + super("nearest", "nearestRequest"); + + // Ressource concernée + this._resource = resource; // Coordonnées du point fourni this._coordinates = coordinates; @@ -38,6 +41,29 @@ module.exports = class nearestRequest extends Request { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la requête + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la requête + * @param {string} res - Id de la ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/src/js/requests/request.js b/src/js/requests/request.js index 107952f4..7d7352bf 100644 --- a/src/js/requests/request.js +++ b/src/js/requests/request.js @@ -27,37 +27,11 @@ module.exports = class Request { // Opération concernée this._operation = operation; - // Ressource concernée - this._resource = resource; - // Type de la requête (ne doit pas être modifié) this._type = type; } - /** - * - * @function - * @name get resource - * @description Récupérer la ressource de la requête - * - */ - get resource () { - return this._resource; - } - - /** - * - * @function - * @name set resource - * @description Attribuer la ressource de la requête - * @param {string} res - Id de la ressource - * - */ - set resource (res) { - this._resource = res; - } - /** * * @function diff --git a/src/js/requests/routeRequest.js b/src/js/requests/routeRequest.js index c651ff94..3410036c 100644 --- a/src/js/requests/routeRequest.js +++ b/src/js/requests/routeRequest.js @@ -29,7 +29,10 @@ module.exports = class routeRequest extends Request { constructor(resource, start, end, profile, optimization) { // Constructeur parent - super("route", resource, "routeRequest"); + super("route", "routeRequest"); + + // Ressource concernée + this._resource = resource; // Point de départ this._start = start; @@ -73,6 +76,29 @@ module.exports = class routeRequest extends Request { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la requête + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la requête + * @param {string} res - Id de la ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/src/js/responses/healthResponse.js b/src/js/responses/healthResponse.js new file mode 100644 index 00000000..6715f62a --- /dev/null +++ b/src/js/responses/healthResponse.js @@ -0,0 +1,104 @@ +'use strict'; + +/** +* +* @class +* @name healthResponse +* @description Classe modélisant une réponse de l'état du serveur (health). +* +*/ + +module.exports = class healthResponse { + + + /** + * + * @function + * @name constructor + * @description Constructeur de la classe healthResponse + * + */ + constructor() { + + // État global + this._globalState = "unknown"; + + // État de l'administrateur + this._adminState = "unknown"; + + // États des services + // Un administrateur peut n'avoir aucun service + this._serviceStates = []; + + } + + /** + * + * @function + * @name get globalState + * @description Récupérer le globalState + * + */ + get globalState () { + return this._globalState; + } + + /** + * + * @function + * @name set globalState + * @description Attribuer le globalState + * @param {string} st - État + * + */ + set globalState (st) { + this._globalState = st; + } + + /** + * + * @function + * @name get adminState + * @description Récupérer le adminState + * + */ + get adminState () { + return this._adminState; + } + + /** + * + * @function + * @name set adminState + * @description Attribuer le adminState + * @param {string} st - État + * + */ + set adminState (st) { + this._adminState = st; + } + + /** + * + * @function + * @name get serviceStates + * @description Récupérer le serviceStates + * + */ + get serviceStates () { + return this._serviceStates; + } + + /** + * + * @function + * @name set serviceStates + * @description Attribuer le serviceStates + * @param {Array} st - États des services + * + */ + set serviceStates (st) { + this._serviceStates = st; + } + +} diff --git a/src/js/service/serviceAdministered.js b/src/js/service/serviceAdministered.js index 2789d8ce..1a068801 100644 --- a/src/js/service/serviceAdministered.js +++ b/src/js/service/serviceAdministered.js @@ -65,5 +65,16 @@ module.exports = class ServiceAdministered { } + /** + * + * @function + * @name computeRequest + * @description Fonction pour utiliser pour envoyer une requête à un service selon le mode adaptée à la classe fille. Elle doit être ré-écrite dans chaque classe fille. + * + */ + computeRequest() { + + } + } diff --git a/src/js/service/serviceInsider.js b/src/js/service/serviceInsider.js index 4505850f..edf84805 100644 --- a/src/js/service/serviceInsider.js +++ b/src/js/service/serviceInsider.js @@ -143,4 +143,19 @@ module.exports = class ServiceInsider extends ServiceAdministered { } + /** + * + * @function + * @name computeRequest + * @description Fonction pour utiliser pour envoyer une requête à un service selon le mode adaptée à la classe fille. Elle doit être ré-écrite dans chaque classe fille. + * @param {object} request - Instance fille de la classe Request + * + */ + computeRequest(request) { + + // L'instance de Service est accessible, il suffit de faire appel à la fonction qui traite les requêtes + return this._serviceInstance.computeAdminRequest(request); + + } + } diff --git a/src/js/service/serviceManager.js b/src/js/service/serviceManager.js index 443abad3..cba75369 100644 --- a/src/js/service/serviceManager.js +++ b/src/js/service/serviceManager.js @@ -128,4 +128,48 @@ module.exports = class serviceManager { } + /** + * + * @function + * @name computeRequest + * @description Gestion d'une requête pour un service + * La requête est envoyé au service puis la réponse du service est retournée + * @param {string} serviceId - Id du service selon l'administrateur + * @param {object} request - Instance fille de la classe Request + * + */ + async computeRequest(serviceId, request) { + + LOGGER.info("computeRequest..."); + + // Quelques vérifications + if (!serviceId) { + LOGGER.error("Aucun id de service"); + } + if (typeof(serviceId) !== "string") { + LOGGER.error("L'id de service n'est pas une string"); + } else { + LOGGER.debug("serviceId: " + serviceId); + } + if (!request) { + LOGGER.error("Aucune requête"); + } + if (typeof(request) !== "object") { + LOGGER.error("La requête n'est pas un objet"); + } else { + LOGGER.debug("request:"); + LOGGER.debug(request); + } + + // On récupère le service administré + let administeredService = this._loadedServiceAdministeredCatalog[serviceId]; + if (!administeredService) { + LOGGER.error("Aucun service associé à cet ID: " + serviceId); + } + + // On envoit la requête et renvoit la réponse + return administeredService.computeRequest(request); + + } + } \ No newline at end of file diff --git a/src/js/service/serviceProcess.js b/src/js/service/serviceProcess.js index ab8c978e..2aee9d95 100644 --- a/src/js/service/serviceProcess.js +++ b/src/js/service/serviceProcess.js @@ -90,4 +90,16 @@ module.exports = class ServiceProcess extends ServiceAdministered { } + /** + * + * @function + * @name computeRequest + * @description Fonction pour utiliser pour envoyer une requête à un service selon le mode adaptée à la classe fille. Elle doit être ré-écrite dans chaque classe fille. + * @param {object} request - Instance fille de la classe Request + * + */ + computeRequest(request) { + + } + } diff --git a/src/js/sources/source.js b/src/js/sources/source.js index a2ccbf09..d8dadae6 100644 --- a/src/js/sources/source.js +++ b/src/js/sources/source.js @@ -42,8 +42,8 @@ module.exports = class Source { // État de la connexion de la source this._connected = false; - // État de la source (même si connectée, elle peut être disfonctionnelle) - // Peut être : "green" si la dernière requête a fonctionnée, "orange" si la source est connectée mais injoignable, "red" à l'initialisation ou si plus gros problème + // État de la source (même si connectée, elle peut être dysfonctionnelle) + // "green" si la dernière requête a fonctionnée, "red" à l'initialisation ou si la donnée n'est plus accessible // Ajouter la gestion de ce paramètre dans chaque classe fille this._state = "red"; From 78733804bc17ac1a890f479458ec9a5546b8c696 Mon Sep 17 00:00:00 2001 From: Loic Date: Fri, 24 Feb 2023 22:38:00 +0100 Subject: [PATCH 2/7] [test]: maj de request --- test/unit/mocha/requests/testsRequest.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/unit/mocha/requests/testsRequest.js b/test/unit/mocha/requests/testsRequest.js index 60a7f48e..4724d968 100644 --- a/test/unit/mocha/requests/testsRequest.js +++ b/test/unit/mocha/requests/testsRequest.js @@ -17,10 +17,6 @@ describe('Test de la classe Request', function() { assert.equal(request.operation, "route"); }); - it('Get Resource', function() { - assert.equal(request.resource, "corse-osm"); - }); - it('Get Type', function() { assert.equal(request.type, "routeRequest"); }); @@ -34,11 +30,6 @@ describe('Test de la classe Request', function() { assert.equal(request.operation, "nearest"); }); - it('Set Resource', function() { - request.resource = "corse-osm-2"; - assert.equal(request.resource, "corse-osm-2"); - }); - // Le type ne devrait pas changer car il dépend de la classe fille appelée it('Set Type ne change rien', function() { request.type = "otherRequest"; From fd0499b7004720502c58d5b50a8b727b9c62179b Mon Sep 17 00:00:00 2001 From: Loic Date: Thu, 2 Mar 2023 15:49:32 +0100 Subject: [PATCH 3/7] wip: it works for sameProcess services --- docker/dev/docker-compose.yml | 1 + src/js/administrator/administrator.js | 9 +- .../apis/admin/1.0.0/controller/controller.js | 2 +- src/js/requests/request.js | 3 +- src/js/responses/healthResponse.js | 2 +- src/js/service/service.js | 90 ++++++++++++++++++- src/js/service/serviceManager.js | 2 + src/js/sources/source.js | 6 +- src/js/sources/sourceManager.js | 29 ++++-- test/unit/mocha/requests/testsRequest.js | 2 +- 10 files changed, 124 insertions(+), 22 deletions(-) diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index a7869ec5..9a5d4e71 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -14,6 +14,7 @@ services: command : "npm run debug -- --ROAD2_CONF_FILE=../config/road2.json" ports: - 8080:8080 + - 8079:8079 - 9229:9229 - 9230:9230 - 443:443 diff --git a/src/js/administrator/administrator.js b/src/js/administrator/administrator.js index 7fa7f58b..2e8db45f 100644 --- a/src/js/administrator/administrator.js +++ b/src/js/administrator/administrator.js @@ -549,6 +549,7 @@ module.exports = class Administrator { } // On stocke le retour de ce service + curHealthResponse.serviceStates[0].id = curServiceId; healthResponse.serviceStates.push(curHealthResponse.serviceStates[0]); } @@ -556,14 +557,14 @@ module.exports = class Administrator { // En fonction des états définis précédemment, on va définir l'état global // Pour faire simple : // - global est orange si un des services est orange - // - un service est orange si une des sources est indisponible (cela est traité dans le service) // - global est rouge si un des services est rouge - // - service est rouge si la moitié, ou plus, de ses sources sont indisponibles (cela est traité dans le service) if (gotRed) { - healthResponse.adminState = "red"; + healthResponse.globalState = "red"; } else { if (gotOrange) { - healthResponse.adminState = "orange"; + healthResponse.globalState = "orange"; + } else { + healthResponse.globalState = "green"; } } diff --git a/src/js/apis/admin/1.0.0/controller/controller.js b/src/js/apis/admin/1.0.0/controller/controller.js index 8a18cc86..41eddac6 100644 --- a/src/js/apis/admin/1.0.0/controller/controller.js +++ b/src/js/apis/admin/1.0.0/controller/controller.js @@ -74,7 +74,7 @@ module.exports = { userResponse.administrator = {}; userResponse.administrator.state = healthResponse.adminState; - userResponse.services = new Array(); + userResponse.services = healthResponse.serviceStates; return userResponse; diff --git a/src/js/requests/request.js b/src/js/requests/request.js index 7d7352bf..83e93562 100644 --- a/src/js/requests/request.js +++ b/src/js/requests/request.js @@ -18,11 +18,10 @@ module.exports = class Request { * @name constructor * @description Constructeur de la classe Request * @param {string} operation - Type d'opération concernée - * @param {string} resource - Ressource concernée * @param {string} type - Type de la requête * */ - constructor(operation, resource, type) { + constructor(operation, type) { // Opération concernée this._operation = operation; diff --git a/src/js/responses/healthResponse.js b/src/js/responses/healthResponse.js index 6715f62a..6f436a45 100644 --- a/src/js/responses/healthResponse.js +++ b/src/js/responses/healthResponse.js @@ -28,7 +28,7 @@ module.exports = class healthResponse { // États des services // Un administrateur peut n'avoir aucun service - this._serviceStates = []; + this._serviceStates = new Array(); } diff --git a/src/js/service/service.js b/src/js/service/service.js index 78cfbf0e..9703baac 100644 --- a/src/js/service/service.js +++ b/src/js/service/service.js @@ -14,6 +14,8 @@ const ProjectionManager = require('../geography/projectionManager'); const ServerManager = require('../server/serverManager'); const LogManager = require('../utils/logManager'); const log4js = require('log4js'); +const errorManager = require('../utils/errorManager'); +const HealthResponse = require('../responses/healthResponse'); // Création du LOGGER const LOGGER = log4js.getLogger("SERVICE"); @@ -732,7 +734,7 @@ module.exports = class Service { } - if (this._sourceManager.source.length === 0) { + if (this._sourceManager.sources.length === 0) { LOGGER.fatal("Aucune ressource n'a pu etre chargee"); return false; } @@ -947,7 +949,7 @@ module.exports = class Service { let sourceId = resource.getSourceIdFromRequest(request); // La source est dans le catalogue du sourceManager - let source = this._sourceManager.source[sourceId]; + let source = this._sourceManager.sources[sourceId]; // --- //On renvoie la requête vers le moteur @@ -963,4 +965,88 @@ module.exports = class Service { } + /** + * + * @function + * @name computeAdminRequest + * @description Fonction utilisée pour traiter une requête venant de l'administrateur + * @param {object} request - Instance fille de la classe Request + * + */ + + computeAdminRequest(request) { + + LOGGER.info("computeAdminRequest..."); + + // On part du principe qu'un maximum de vérifications ont été faites avant par l'administrateur + // On essaye de réduire l'exécution par le service + + // En fonction du type de la requête, on va appeler différentes fonctions + // Le if est un choix modifiable. Pour le moment c'est ainsi car dans le cas du serviceProcess, on ne peut pas y échapper. + if (request.type === "healthRequest") { + return this.computeHealthRequest(request); + } else { + throw errorManager.createError("Unknown request type"); + } + + } + + /** + * + * @function + * @name computeHealthRequest + * @description Fonction utilisée pour connaître l'état du service + * @param {HealthRequest} healthRequest - Instance de la classe HealthRequest + * + */ + + computeHealthRequest(healthRequest) { + + LOGGER.info("computeHealthRequest..."); + + let healthResponse = new HealthResponse(); + let nbRed = 0; + let nbSources = this._sourceManager.loadedSourceId.length; + let serviceState = {}; + serviceState.sources = new Array(); + + // Récupération de la disponibilité de chaque source + for (let sourceId in this._sourceManager.sources) { + + let sourceState = this._sourceManager.sources[sourceId].state; + + if (sourceState === "red") { + nbRed++; + } else if (sourceState === "green" || sourceState === "init") { + // Les cas "green" et "init" sont considérés comme équivalent + } else { + // État inconnu donc on lève une alerte et on le met manuellement à "unknown" pour ne pas renvoyer n'importe quoi à l'administrateur + sourceState = "unknown"; + nbRed++; + } + + serviceState.sources.push({id: sourceId, state: sourceState}); + + } + + // Pour faire simple : + // - un service est orange si une des sources est indisponible + // - service est rouge si la moitié, ou plus, de ses sources sont indisponibles + if (nbRed > 0) { + + if (nbRed >= nbSources / 2) { + serviceState.state = "red"; + } else { + serviceState.state = "orange"; + } + + } else { + serviceState.state = "green"; + } + + healthResponse.serviceStates.push(serviceState); + return healthResponse; + + } + } diff --git a/src/js/service/serviceManager.js b/src/js/service/serviceManager.js index cba75369..ef5183df 100644 --- a/src/js/service/serviceManager.js +++ b/src/js/service/serviceManager.js @@ -4,6 +4,7 @@ const log4js = require('log4js'); const Service = require('./service'); const ServiceInsider = require('./serviceInsider'); const ServiceProcess = require('./serviceProcess'); +const errorManager = require('../utils/errorManager'); // Création du LOGGER const LOGGER = log4js.getLogger("SERVICEMANAGER"); @@ -165,6 +166,7 @@ module.exports = class serviceManager { let administeredService = this._loadedServiceAdministeredCatalog[serviceId]; if (!administeredService) { LOGGER.error("Aucun service associé à cet ID: " + serviceId); + throw errorManager.createError("Unknown service : " + serviceId); } // On envoit la requête et renvoit la réponse diff --git a/src/js/sources/source.js b/src/js/sources/source.js index d8dadae6..8c344639 100644 --- a/src/js/sources/source.js +++ b/src/js/sources/source.js @@ -43,9 +43,11 @@ module.exports = class Source { this._connected = false; // État de la source (même si connectée, elle peut être dysfonctionnelle) - // "green" si la dernière requête a fonctionnée, "red" à l'initialisation ou si la donnée n'est plus accessible + // "green" si la dernière requête a fonctionnée, + // "red" si la donnée n'est plus accessible, + // "init" à sa création (utile pour une requête /health de l'administrateur) // Ajouter la gestion de ce paramètre dans chaque classe fille - this._state = "red"; + this._state = "init"; } diff --git a/src/js/sources/sourceManager.js b/src/js/sources/sourceManager.js index de76b916..fe30acc8 100644 --- a/src/js/sources/sourceManager.js +++ b/src/js/sources/sourceManager.js @@ -30,7 +30,7 @@ module.exports = class sourceManager { this._checkedSourceId = new Array(); // Catalogue des sources du manager - this._source = {}; + this._sources = {}; // Descriptions des sources chargées par le manager this._loadedSourceConfiguration = {}; @@ -59,12 +59,23 @@ module.exports = class sourceManager { /** * * @function - * @name get source - * @description Récupérer l'ensemble des ids de sources chargées + * @name get loadedSourceId + * @description Récupérer l'ensemble des id de sources chargées * */ - get source() { - return this._source; + get loadedSourceId() { + return this._loadedSourceId; + } + + /** + * + * @function + * @name get sources + * @description Récupérer l'ensemble des sources chargées + * + */ + get sources() { + return this._sources; } /** @@ -105,7 +116,7 @@ module.exports = class sourceManager { getSourceById(id) { if (this.isLoadedSourceAvailable(id)) { - return this._source[id]; + return this._sources[id]; } else { return null; } @@ -915,7 +926,7 @@ module.exports = class sourceManager { let source; - if (this._source[sourceJsonObject.id]) { + if (this._sources[sourceJsonObject.id]) { LOGGER.info("La source " + sourceJsonObject.id + " existe déjà"); return true; } @@ -948,7 +959,7 @@ module.exports = class sourceManager { // Notamment dans la gestion (ajout/suppression/modification) de sources durant la vie du service this._loadedSourceId.push(sourceJsonObject.id); this._loadedSourceConfiguration[sourceJsonObject.id] = sourceJsonObject; - this._source[sourceJsonObject.id] = source; + this._sources[sourceJsonObject.id] = source; return true; @@ -969,7 +980,7 @@ module.exports = class sourceManager { try { - await this._source[sourceId].connect(); + await this._sources[sourceId].connect(); LOGGER.info("Source connectee."); return true; diff --git a/test/unit/mocha/requests/testsRequest.js b/test/unit/mocha/requests/testsRequest.js index 4724d968..f4553bc3 100644 --- a/test/unit/mocha/requests/testsRequest.js +++ b/test/unit/mocha/requests/testsRequest.js @@ -9,7 +9,7 @@ describe('Test de la classe Request', function() { logManager.manageLogs(); }); - let request = new Request("route", "corse-osm", "routeRequest"); + let request = new Request("route", "routeRequest"); describe('Test du constructeur et des getters', function() { From 7f80723d691b2e2decbdedd8101e21f8ffc08aa7 Mon Sep 17 00:00:00 2001 From: Loic Date: Fri, 3 Mar 2023 17:56:58 +0100 Subject: [PATCH 4/7] works for newProcesses --- src/js/administrator/administrator.js | 25 +++++-- src/js/responses/healthResponse.js | 3 + src/js/service/main.js | 6 ++ src/js/service/service.js | 47 +++++++++++++- src/js/service/serviceInsider.js | 2 + src/js/service/serviceManager.js | 12 ++-- src/js/service/serviceProcess.js | 93 ++++++++++++++++++++++++++- 7 files changed, 173 insertions(+), 15 deletions(-) diff --git a/src/js/administrator/administrator.js b/src/js/administrator/administrator.js index 2e8db45f..5a79ed09 100644 --- a/src/js/administrator/administrator.js +++ b/src/js/administrator/administrator.js @@ -509,9 +509,20 @@ module.exports = class Administrator { let curServiceId = this._configuration.administration.services[i].id; LOGGER.debug("Demande de l'état du service : " + curServiceId); + + // Le passage potentiel par IPC fait perdre les méthodes donc dans la suite, on est obligé de prendre les attributs avec _ let curHealthResponse = await this._serviceManager.computeRequest(curServiceId, healthRequest); - if (!curHealthResponse.serviceStates[0]) { + if (curHealthResponse._type !== "healthResponse") { + // Ce n'est pas normal, on renvoit une erreur pour ce service + // et on met le flag rouge + LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse du bon type"); + gotRed = true; + healthResponse.serviceStates.push({"serviceId":curServiceId,"state":"unknown"}); + continue; + } + + if (!curHealthResponse._serviceStates[0]) { // Ce n'est pas normal, on renvoit une erreur pour ce service // et on met le flag rouge LOGGER.error("Le service " + curServiceId + " n'a pas donné de réponse"); @@ -520,7 +531,7 @@ module.exports = class Administrator { continue; } - if (!curHealthResponse.serviceStates[0].state) { + if (!curHealthResponse._serviceStates[0].state) { // Ce n'est pas normal, on renvoit une erreur pour ce service // et on met le flag rouge LOGGER.error("Le service " + curServiceId + " n'a pas donné d'état"); @@ -530,13 +541,13 @@ module.exports = class Administrator { } // Pour la suite, on note la présence d'orange et de rouge dans les services - if (curHealthResponse.serviceStates[0].state === "orange") { + if (curHealthResponse._serviceStates[0].state === "orange") { LOGGER.debug("Le service " + curServiceId + " est orange"); gotOrange = true; - } else if (curHealthResponse.serviceStates[0].state === "red") { + } else if (curHealthResponse._serviceStates[0].state === "red") { LOGGER.debug("Le service " + curServiceId + " est red"); gotRed = true; - } else if (curHealthResponse.serviceStates[0].state === "green") { + } else if (curHealthResponse._serviceStates[0].state === "green") { // Tout va bien, rien à faire LOGGER.debug("Le service " + curServiceId + " est green"); } else { @@ -549,8 +560,8 @@ module.exports = class Administrator { } // On stocke le retour de ce service - curHealthResponse.serviceStates[0].id = curServiceId; - healthResponse.serviceStates.push(curHealthResponse.serviceStates[0]); + curHealthResponse._serviceStates[0].id = curServiceId; + healthResponse.serviceStates.push(curHealthResponse._serviceStates[0]); } diff --git a/src/js/responses/healthResponse.js b/src/js/responses/healthResponse.js index 6f436a45..855ca5c7 100644 --- a/src/js/responses/healthResponse.js +++ b/src/js/responses/healthResponse.js @@ -20,6 +20,9 @@ module.exports = class healthResponse { */ constructor() { + // Type de la réponse + this._type = "healthResponse"; + // État global this._globalState = "unknown"; diff --git a/src/js/service/main.js b/src/js/service/main.js index 4c0aec4c..dbfa9751 100644 --- a/src/js/service/main.js +++ b/src/js/service/main.js @@ -80,6 +80,12 @@ async function startService() { LOGGER.info("Les sources connectables ont été connectées"); + // Instanciation de la fonction permettant de recevoir des messages via IPC + if (process.argv[3] === "child") { + LOGGER.info("Ce service est un child d'un administrateur. Instanciation de la fonction permettant de recevoir les messages"); + service.initIPC(); + } + // On démarre les serveurs associé à ce service if (!service.startServers()) { pm.shutdown(5); diff --git a/src/js/service/service.js b/src/js/service/service.js index 9703baac..3c2b0a11 100644 --- a/src/js/service/service.js +++ b/src/js/service/service.js @@ -965,6 +965,49 @@ module.exports = class Service { } + /** + * + * @function + * @name initIPC + * @description Fonction utilisée pour permettra la communication IPC afin de traiter une requête venant de l'administrateur envoyée via ce protocol + * + */ + + initIPC() { + + LOGGER.info("initIPC..."); + + process.on('message', (request) => { + + LOGGER.debug("Service child received request: "); + LOGGER.debug(request); + + // TODO : vérifier que le message vient bien du parent ? + + let response; + try { + response = this.computeAdminRequest(request); + } catch(error) { + LOGGER.error("Erreur lors de l'exécution de la requête: " + error); + process.send(error); + return false; + } + + try { + response._uuid = request._uuid; + process.send(response); + } catch(error) { + LOGGER.error("Erreur lors de l'exécution de la requête: " + error); + process.send(error); + return false; + } + + return true; + + }); + + } + /** * * @function @@ -981,9 +1024,11 @@ module.exports = class Service { // On part du principe qu'un maximum de vérifications ont été faites avant par l'administrateur // On essaye de réduire l'exécution par le service + // Le passage potentiel par IPC fait perdre les méthodes donc dans la suite, on est obligé de prendre les attributs avec _ + // En fonction du type de la requête, on va appeler différentes fonctions // Le if est un choix modifiable. Pour le moment c'est ainsi car dans le cas du serviceProcess, on ne peut pas y échapper. - if (request.type === "healthRequest") { + if (request._type === "healthRequest") { return this.computeHealthRequest(request); } else { throw errorManager.createError("Unknown request type"); diff --git a/src/js/service/serviceInsider.js b/src/js/service/serviceInsider.js index edf84805..adc1b33b 100644 --- a/src/js/service/serviceInsider.js +++ b/src/js/service/serviceInsider.js @@ -153,6 +153,8 @@ module.exports = class ServiceInsider extends ServiceAdministered { */ computeRequest(request) { + LOGGER.info("computeRequest..."); + // L'instance de Service est accessible, il suffit de faire appel à la fonction qui traite les requêtes return this._serviceInstance.computeAdminRequest(request); diff --git a/src/js/service/serviceManager.js b/src/js/service/serviceManager.js index ef5183df..405249e2 100644 --- a/src/js/service/serviceManager.js +++ b/src/js/service/serviceManager.js @@ -145,18 +145,18 @@ module.exports = class serviceManager { // Quelques vérifications if (!serviceId) { - LOGGER.error("Aucun id de service"); + throw errorManager.createError("Aucun id de service"); } if (typeof(serviceId) !== "string") { - LOGGER.error("L'id de service n'est pas une string"); + throw errorManager.createError("L'id de service n'est pas une string"); } else { LOGGER.debug("serviceId: " + serviceId); } if (!request) { - LOGGER.error("Aucune requête"); + throw errorManager.createError("Aucune requête"); } if (typeof(request) !== "object") { - LOGGER.error("La requête n'est pas un objet"); + throw errorManager.createError("La requête n'est pas un objet"); } else { LOGGER.debug("request:"); LOGGER.debug(request); @@ -170,7 +170,9 @@ module.exports = class serviceManager { } // On envoit la requête et renvoit la réponse - return administeredService.computeRequest(request); + let response = await administeredService.computeRequest(request); + + return response; } diff --git a/src/js/service/serviceProcess.js b/src/js/service/serviceProcess.js index 2aee9d95..91180a80 100644 --- a/src/js/service/serviceProcess.js +++ b/src/js/service/serviceProcess.js @@ -4,6 +4,11 @@ const log4js = require('log4js'); const { fork } = require('child_process'); const ServiceAdministered = require('./serviceAdministered'); +const errorManager = require('../utils/errorManager'); +const healthResponse = require('../responses/healthResponse'); +const { + setInterval, + } = require('node:timers/promises'); // Création du LOGGER const LOGGER = log4js.getLogger("SERVICEPRO"); @@ -39,6 +44,12 @@ module.exports = class ServiceProcess extends ServiceAdministered { // Instance de childProcess quand le processus est lancé this._serviceInstance = {}; + // Compteur des requêtes envoyées effectivement au service + this._requestCount = 0; + + // Liste des réponses en attente de lecture + this._unReadResponses = {}; + } /** @@ -82,10 +93,21 @@ module.exports = class ServiceProcess extends ServiceAdministered { // Création du service via un fork : on lance simplement service/main.js LOGGER.info("Fork du processus pour créer le service..."); - this._serviceInstance = fork("./src/js/service/main.js", [this._configurationLocation], serviceOptions); + this._serviceInstance = fork("./src/js/service/main.js", [this._configurationLocation, "child"], serviceOptions); LOGGER.info("Processus enfant créé"); + // Puisqu'un processus enfant a été créé et qu'il y a un canal IPC entre eux, on instancie la gestion des messages + this._serviceInstance.on("message", (response) => { + + LOGGER.debug("Parent got message:"); + LOGGER.debug(response); + + // On stocke la réponse + this._unReadResponses[response._uuid] = response; + + }); + return true; } @@ -98,7 +120,74 @@ module.exports = class ServiceProcess extends ServiceAdministered { * @param {object} request - Instance fille de la classe Request * */ - computeRequest(request) { + async computeRequest(request) { + + LOGGER.info("computeRequest..."); + + // On vérifie que le child est toujours connecté + if (!this._serviceInstance.connected) { + throw errorManager.createError("Impossible d'envoyer une requête au service car non connecté"); + } else { + + LOGGER.debug("Le service child est connecté"); + + // On crée un UUID qui va permettre de faire le lien avec la réponse + // TODO : que se passe-t-il si l'instance tourne longtemps, y'a-t-il une limite ? + this._requestCount++; + request._uuid = this._requestCount.toString(); + LOGGER.debug("Création d'un UUID:" + request._uuid); + + // On envoit la requête au child + if (!this._serviceInstance.send(request)) { + throw errorManager.createError("Erreur lors de l'envoie de la requête"); + } + + // On attend la réponse et on la renvoit + let response = await this.waitResponse(request._uuid); + + return response; + + } + + } + + /** + * + * @function + * @name waitResponse + * @description Fonction pour utiliser pour récupérer la réponse d'une requête une fois qu'elle est arrivée + * @param {string} uuid - UUID de la requête + * + */ + async waitResponse(uuid) { + + LOGGER.info("waitResponse..."); + + let response = {}; + + // Toutes les 10ms on va voir si la réponse est disponible + const interval = 10; + + for await (const startTime of setInterval(interval, Date.now())) { + + // Est-ce que la réponse est disponible ? + if (this._unReadResponses[uuid]) { + LOGGER.debug("Response found for uuid: " + uuid); + response = this._unReadResponses[uuid]; + break; + } + + // Gestion du timeout : 1min + const now = Date.now(); + if ((now - startTime) > 60000) { + LOGGER.info("Timeout atteint pour l'attente de la réponse"); + response = errorManager.createError("Pas de réponse reçue dans le temps imparti"); + break; + } + + } + + return response; } From 4dcda02e6d98b2b4f7cc4c31be2fd9209534cfa7 Mon Sep 17 00:00:00 2001 From: Loic Date: Wed, 8 Mar 2023 13:04:46 +0100 Subject: [PATCH 5/7] add type inside response, update tests and doc --- changelog.md | 2 + documentation/test/integration/readme.md | 3 ++ src/js/responses/healthResponse.js | 6 ++- src/js/responses/isochroneResponse.js | 28 ++++++++++- src/js/responses/nearestResponse.js | 28 ++++++++++- src/js/responses/response.js | 24 +++------ src/js/responses/routeResponse.js | 28 ++++++++++- .../cucumber/features/support/world.js | 1 + .../requests/integrationHealthRequest.js | 31 ++++++++++++ .../responses/integrationHealthResponse.js | 49 +++++++++++++++++++ test/unit/mocha/responses/testsResponse.js | 12 ++--- 11 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 test/integration/mocha/requests/integrationHealthRequest.js create mode 100644 test/integration/mocha/responses/integrationHealthResponse.js diff --git a/changelog.md b/changelog.md index 097cb071..ccef58e0 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,8 @@ CHANGED: - Le fichier server.json permet maintenant de configurer l'administrateur et donc n'a plus le même contenu. Ce dernier est dans service.json. - Les sources ne sont plus configurées dans le même fichier que les ressources. Chaque source est configurée dans son fichier. L'ensemble est placé dans un dossier de sources. Il peut y en avoir plusieurs. - Les sources PGRouting et Valhalla ne sont plus configurées de la même manière : chaque source de ces types peut contenir plusieurs coûts. + - La documentation de l'API d'administration a été grandement enrichie. + - La route /health a une réponse plus complète et est vraiment codée pour prendre en compte l'état de chaque service et chaque source disponibles. FIXED: - Les reprojections des isochrones fonctionnent diff --git a/documentation/test/integration/readme.md b/documentation/test/integration/readme.md index f063aeaf..53f23726 100644 --- a/documentation/test/integration/readme.md +++ b/documentation/test/integration/readme.md @@ -20,6 +20,8 @@ C'est l'approche bottom-up qui a été choisie pour ces tests. On va tester les - operation (parameter) - resourceParameter (parameter) - serverManager (server, ExpressJS, log4js, fs, assert) + - healthRequest (request) + - healthResponse (response) - Deuxième niveau: - routeRequest (request, point) @@ -123,6 +125,7 @@ C'est l'approche bottom-up qui a été choisie pour ces tests. On va tester les - Router() - router.use() - json() + - set - got - utils/httpQuery.js diff --git a/src/js/responses/healthResponse.js b/src/js/responses/healthResponse.js index 855ca5c7..e3480a58 100644 --- a/src/js/responses/healthResponse.js +++ b/src/js/responses/healthResponse.js @@ -1,5 +1,7 @@ 'use strict'; +const Response = require('./response'); + /** * * @class @@ -8,7 +10,7 @@ * */ -module.exports = class healthResponse { +module.exports = class healthResponse extends Response { /** @@ -21,7 +23,7 @@ module.exports = class healthResponse { constructor() { // Type de la réponse - this._type = "healthResponse"; + super("healthResponse"); // État global this._globalState = "unknown"; diff --git a/src/js/responses/isochroneResponse.js b/src/js/responses/isochroneResponse.js index 42611533..5d738c87 100644 --- a/src/js/responses/isochroneResponse.js +++ b/src/js/responses/isochroneResponse.js @@ -42,7 +42,10 @@ module.exports = class isochroneResponse extends Response { distanceUnit) { // Constructeur parent - super(resource); + super("isochroneResponse"); + + // Ressource + this._resource = resource; // point this._point = point; @@ -73,6 +76,29 @@ module.exports = class isochroneResponse extends Response { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la réponse + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la réponse + * @param {Point} res - Ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/src/js/responses/nearestResponse.js b/src/js/responses/nearestResponse.js index 7a4f3d8f..22fbe49c 100644 --- a/src/js/responses/nearestResponse.js +++ b/src/js/responses/nearestResponse.js @@ -25,7 +25,10 @@ module.exports = class nearestResponse extends Response { constructor(resource, coordinates) { // Constructeur parent - super(resource); + super("nearestResponse"); + + // Ressource + this._resource = resource; // coordinates this._coordinates = coordinates; @@ -36,6 +39,29 @@ module.exports = class nearestResponse extends Response { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la réponse + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la réponse + * @param {Point} res - Ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/src/js/responses/response.js b/src/js/responses/response.js index a85e55ee..2568122a 100644 --- a/src/js/responses/response.js +++ b/src/js/responses/response.js @@ -16,37 +16,25 @@ module.exports = class Response { * @function * @name constructor * @description Constructeur de la classe Response - * @param {string} resource - Nom de la ressource + * @param {string} type - Type de la réponse * */ - constructor(resource) { + constructor(type) { // Nom de la ressource concernée par la réponse - this._resource = resource; + this._type = type; } /** * * @function - * @name get resource + * @name get type * @description Récupérer la ressource de la requête * */ - get resource () { - return this._resource; - } - - /** - * - * @function - * @name set resource - * @description Attribuer la ressource de la requête - * @param {string} res - Nom de la ressource - * - */ - set resource (res) { - this._resource = res; + get type () { + return this._type; } diff --git a/src/js/responses/routeResponse.js b/src/js/responses/routeResponse.js index 088b76ef..5bcea103 100644 --- a/src/js/responses/routeResponse.js +++ b/src/js/responses/routeResponse.js @@ -28,7 +28,10 @@ module.exports = class routeResponse extends Response { constructor(resource, start, end, profile, optimization) { // Constructeur parent - super(resource); + super("routeResponse"); + + // Ressource + this._resource = resource; // start this._start = start; @@ -48,6 +51,29 @@ module.exports = class routeResponse extends Response { } + /** + * + * @function + * @name get resource + * @description Récupérer la ressource de la réponse + * + */ + get resource () { + return this._resource; + } + + /** + * + * @function + * @name set resource + * @description Attribuer la ressource de la réponse + * @param {Point} res - Ressource + * + */ + set resource (res) { + this._resource = res; + } + /** * * @function diff --git a/test/functional/request/cucumber/features/support/world.js b/test/functional/request/cucumber/features/support/world.js index 0f3002cf..7c7c2812 100644 --- a/test/functional/request/cucumber/features/support/world.js +++ b/test/functional/request/cucumber/features/support/world.js @@ -739,6 +739,7 @@ class road2World { } else { // On part du principe que c'est du GeoJSON + // TODO : ajouter la gestion du polyline if (curIso.coordinates) { refIso = turf.polygon(refIso.coordinates); diff --git a/test/integration/mocha/requests/integrationHealthRequest.js b/test/integration/mocha/requests/integrationHealthRequest.js new file mode 100644 index 00000000..c29b4683 --- /dev/null +++ b/test/integration/mocha/requests/integrationHealthRequest.js @@ -0,0 +1,31 @@ +const assert = require('assert'); +const HealthRequest = require('../../../../src/js/requests/healthRequest'); +const logManager = require('../logManager'); + +describe('Test de la classe HealthRequest', function() { + + before(function() { + // runs before all tests in this block + logManager.manageLogs(); + }); + + let request = new HealthRequest(); + + describe('Test du constructeur et des getters/setters', function() { + + it('Get type', function() { + assert.equal(request.type, "healthRequest"); + }); + + it('Get verbose', function() { + assert.equal(request.verbose, false); + }); + + it('Set verbose', function() { + request.verbose = true; + assert.equal(request.verbose, true); + }); + + }); + +}); diff --git a/test/integration/mocha/responses/integrationHealthResponse.js b/test/integration/mocha/responses/integrationHealthResponse.js new file mode 100644 index 00000000..31796ce5 --- /dev/null +++ b/test/integration/mocha/responses/integrationHealthResponse.js @@ -0,0 +1,49 @@ +const assert = require('assert'); +const HealthResponse = require('../../../../src/js/requests/healthResponse'); +const logManager = require('../logManager'); + +describe('Test de la classe HealthResponse', function() { + + before(function() { + // runs before all tests in this block + logManager.manageLogs(); + }); + + let response = new HealthResponse(); + + describe('Test du constructeur et des getters/setters', function() { + + it('Get type', function() { + assert.equal(response.type, "healthResponse"); + }); + + it('Get globalState', function() { + assert.equal(response.globalState, "unknown"); + }); + + it('Set globalState', function() { + response.globalState = "green"; + assert.equal(response.globalState, "green"); + }); + + it('Get adminState', function() { + assert.equal(response.adminState, "unknown"); + }); + + it('Set adminState', function() { + response.adminState = "green"; + assert.equal(response.adminState, "green"); + }); + + it('Get serviceStates', function() { + assert.deepEqual(response.serviceStates, new Array()); + }); + + it('Set serviceStates', function() { + response.serviceStates.push = {"serviceId":"unknown","state":"green"}; + assert.deepEqual(response.serviceStates[0], {"serviceId":"unknown","state":"green"}); + }); + + }); + +}); diff --git a/test/unit/mocha/responses/testsResponse.js b/test/unit/mocha/responses/testsResponse.js index 1c7d0eae..4fe3f106 100644 --- a/test/unit/mocha/responses/testsResponse.js +++ b/test/unit/mocha/responses/testsResponse.js @@ -11,15 +11,15 @@ describe('Test de la classe Response', function() { describe('Test du constructeur et des getters/setters', function() { - let response = new Response("mon-id"); + let response = new Response("mon-type"); - it('Get Resource', function() { - assert.equal(response.resource, "mon-id"); + it('Get Type', function() { + assert.equal(response.type, "mon-type"); }); - it('Set Resource', function() { - response.resource = "nouvel-id"; - assert.equal(response.resource, "nouvel-id"); + it('Set Type n\'existe pas car non modifiable', function() { + response.type = "nouveau-type"; + assert.equal(response.type, "mon-type"); }); }); From 488c8a0f4f0e541ec610a9ef3cc54c30874e78c5 Mon Sep 17 00:00:00 2001 From: Loic Date: Thu, 9 Mar 2023 09:37:21 +0100 Subject: [PATCH 6/7] [fix] delete read message --- src/js/service/serviceProcess.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/js/service/serviceProcess.js b/src/js/service/serviceProcess.js index 91180a80..a9ef1d0b 100644 --- a/src/js/service/serviceProcess.js +++ b/src/js/service/serviceProcess.js @@ -174,6 +174,10 @@ module.exports = class ServiceProcess extends ServiceAdministered { if (this._unReadResponses[uuid]) { LOGGER.debug("Response found for uuid: " + uuid); response = this._unReadResponses[uuid]; + LOGGER.debug(response); + // On supprime la réponse de l'objet pour libérer la mémoire + delete this._unReadResponses[uuid]; + LOGGER.debug(this._unReadResponses); break; } From a017e3e04ecc71a43c8ff4df111c992264a96307 Mon Sep 17 00:00:00 2001 From: Loic Date: Thu, 9 Mar 2023 10:10:52 +0100 Subject: [PATCH 7/7] [doc] fix changelog version --- changelog.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index ccef58e0..0ad95e8e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.1.0 + +CHANGED: + - La documentation de l'API d'administration a été grandement enrichie. + - La route /health a une réponse plus complète et est vraiment codée pour prendre en compte l'état de chaque service et chaque source disponibles. + ## 2.0.0 ADDED: @@ -15,8 +21,6 @@ CHANGED: - Le fichier server.json permet maintenant de configurer l'administrateur et donc n'a plus le même contenu. Ce dernier est dans service.json. - Les sources ne sont plus configurées dans le même fichier que les ressources. Chaque source est configurée dans son fichier. L'ensemble est placé dans un dossier de sources. Il peut y en avoir plusieurs. - Les sources PGRouting et Valhalla ne sont plus configurées de la même manière : chaque source de ces types peut contenir plusieurs coûts. - - La documentation de l'API d'administration a été grandement enrichie. - - La route /health a une réponse plus complète et est vraiment codée pour prendre en compte l'état de chaque service et chaque source disponibles. FIXED: - Les reprojections des isochrones fonctionnent