diff --git a/src/module_gtf/module/javascript/script_module.js b/src/module_gtf/module/javascript/script_module.js index fbd07bc90c128c795025aee28c2a4d1c0d431e82..72413cbd5daed4ed1b32c1006b34b0bb0b13cb66 100644 --- a/src/module_gtf/module/javascript/script_module.js +++ b/src/module_gtf/module/javascript/script_module.js @@ -154,7 +154,8 @@ vitisApp.on('appMainDrtvLoaded', function () { "iTreatedOrders": 0, "iNonTreatableOrders": 0, "iProcessingOrders": 0, - "iNonAuthorizedOrders": 0 + "iNonAuthorizedOrders": 0, + "iStoppedOrders": 0 }, "subscription": { "iNonEnabledSubscription": 0, @@ -428,7 +429,7 @@ vitisApp.on('appMainDrtvLoaded', function () { // Traduction des libellés de statuts des demandes. if (typeof(scope["gtf_order_status_label"]) == "undefined") { var $translate = angular.element(vitisApp.appWorkspaceListDrtv).injector().get(["$translate"]); - var aOrderStatusLabel = ["WAITING_BOX_TITLE_SUPERVISION_ORDER", "ERROR_BOX_TITLE_SUPERVISION_ORDER", "TREATED_BOX_TITLE_SUPERVISION_ORDER", "NON_TREATABLE_BOX_TITLE_SUPERVISION_ORDER", "PROCESSING_BOX_TITLE_SUPERVISION_ORDER", "NON_AUTHORIZED_BOX_TITLE_SUPERVISION_ORDER"]; + var aOrderStatusLabel = ["WAITING_BOX_TITLE_SUPERVISION_ORDER", "ERROR_BOX_TITLE_SUPERVISION_ORDER", "TREATED_BOX_TITLE_SUPERVISION_ORDER", "NON_TREATABLE_BOX_TITLE_SUPERVISION_ORDER", "PROCESSING_BOX_TITLE_SUPERVISION_ORDER", "NON_AUTHORIZED_BOX_TITLE_SUPERVISION_ORDER", "STOPPED_BOX_TITLE_SUPERVISION_ORDER"]; scope.$root["gtf_order_status_label"] = []; $translate(aOrderStatusLabel).then(function (translations) { for(var i= 0; i < aOrderStatusLabel.length; i++) diff --git a/src/module_gtf/module/less/main.less b/src/module_gtf/module/less/main.less index c220a40001548b885fc48ab63e78dac96b2bcd6c..cfbf3a465262ac906dc7a0da53983fc2a47daf64 100755 --- a/src/module_gtf/module/less/main.less +++ b/src/module_gtf/module/less/main.less @@ -48,7 +48,7 @@ display : inline; background-color:#ffffff; cursor: pointer; - + } .box_number { @@ -74,16 +74,29 @@ text-transform: uppercase; text-align: center; } +// Etat des demandes et messages. +.box-dot-waiting {background-color: #5ac6de;} +.box-dot-error {background-color: #ff0000;} +.box-dot-treated {background-color: #9cce29;} +.box-dot-non-treatable {background-color: #000000;} +.box-dot-non-authorized {background-color: #c6c6c6;} +.box-dot-order-stopped {background-color: darkorange;} +// En cours (point clignotant). +.box-dot-processing {background-color: #f79cce; animation: blinking 1s linear infinite;} +@keyframes blinking {from, 49.9% {opacity: 0;} 50%, to {opacity: 1;}} +// Abonnements. +.box-dot-enabled-subscription {background-color: #9cce29;} +.box-dot-non-enabled-subscription {background-color: #ff0000;} +// Surveillances. +.box-dot-enabled-survey {background-color: #9cce29;} +.box-dot-non-enabled-survey {background-color: #ff0000;} -.box_waiting {background: #ffffff url("../../../images/sql_list/st1.gif") 2px 2px no-repeat;} -.box_error {background: #ffffff url("../../../images/sql_list/st2.png") 2px 2px no-repeat;} -.box_treated {background: #ffffff url("../../../images/sql_list/st3.png") 2px 2px no-repeat;} -.box_non_treatable {background: #ffffff url("../../../images/sql_list/st4.png") 2px 2px no-repeat;} -.box_processing {background: #ffffff url("../../../images/sql_list/st5.gif") 2px 2px no-repeat;} -.box_non_authorized {background: #ffffff url("../../../images/sql_list/st6.png") 2px 2px no-repeat;} - -.box_enabled_subscription {background: #ffffff url("../../../images/sql_list/st3.png") 2px 2px no-repeat;} -.box_non_enabled_subscription {background: #ffffff url("../../../images/sql_list/st2.png") 2px 2px no-repeat;} - -.box_enabled_survey {background: #ffffff url("../../../images/sql_list/st3.png") 2px 2px no-repeat;} -.box_non_enabled_survey {background: #ffffff url("../../../images/sql_list/st2.png") 2px 2px no-repeat;} +// Point indiquant la couleur de la demande. +.box-dot { + position: absolute; + display: inline-block; + height: 10px; + width: 10px; + margin: 3px; + border-radius: 50%; +} diff --git a/src/module_gtf/module/templates/supervisionStatusTpl.html b/src/module_gtf/module/templates/supervisionStatusTpl.html index f0ad53d6a5f5c1b05ad134e240c7797b36476303..7a31275f06dcc6ec55c4268fc7fdce122fa3931d 100755 --- a/src/module_gtf/module/templates/supervisionStatusTpl.html +++ b/src/module_gtf/module/templates/supervisionStatusTpl.html @@ -3,39 +3,52 @@ <div class="recap_title" data-translate="STATUS_TITLE_SUPERVISION_ORDER"></div> <div class="recap_boxes"> <div class="box_recap box_waiting" ng-click="setSupervisionRecapFilter(1)"> + <span class="box-dot box-dot-waiting"></span> <div class="box_number">{{oSupervisionStatus.order.iWaitingOrders}}</div> <div class="box_text" data-translate="WAITING_BOX_TITLE_SUPERVISION_ORDER"></div> </div> <div class="box_recap box_error" ng-click="setSupervisionRecapFilter(2)"> + <span class="box-dot box-dot-error"></span> <div class="box_number">{{oSupervisionStatus.order.iErrors}}</div> <div class="box_text" data-translate="ERROR_BOX_TITLE_SUPERVISION_ORDER"></div> </div> <div class="box_recap box_treated" ng-click="setSupervisionRecapFilter(3)"> + <span class="box-dot box-dot-treated"></span> <div class="box_number">{{oSupervisionStatus.order.iTreatedOrders}}</div> <div class="box_text" data-translate="TREATED_BOX_TITLE_SUPERVISION_ORDER"></div> </div> <div class="box_recap box_non_treatable" ng-click="setSupervisionRecapFilter(4)"> + <span class="box-dot box-dot-non-treatable"></span> <div class="box_number">{{oSupervisionStatus.order.iNonTreatableOrders}}</div> <div class="box_text" data-translate="NON_TREATABLE_BOX_TITLE_SUPERVISION_ORDER"></div> </div> <div class="box_recap box_processing" ng-click="setSupervisionRecapFilter(5)"> + <span class="box-dot box-dot-processing"></span> <div class="box_number">{{oSupervisionStatus.order.iProcessingOrders}}</div> <div class="box_text" data-translate="PROCESSING_BOX_TITLE_SUPERVISION_ORDER"></div> </div> <div class="box_recap box_non_authorized" ng-click="setSupervisionRecapFilter(6)"> + <span class="box-dot box-dot-non-authorized"></span> <div class="box_number">{{oSupervisionStatus.order.iNonAuthorizedOrders}}</div> <div class="box_text" data-translate="NON_AUTHORIZED_BOX_TITLE_SUPERVISION_ORDER"></div> </div> + <div class="box_recap box_stopped" ng-click="setSupervisionRecapFilter(7)"> + <span class="box-dot box-dot-order-stopped"></span> + <div class="box_number">{{oSupervisionStatus.order.iStoppedOrders}}</div> + <div class="box_text" data-translate="STOPPED_BOX_TITLE_SUPERVISION_ORDER"></div> + </div> </div> </div> <div ng-if="sSelectedObjectName == 'supervision_gtf_subscription'" class="recap"> <div class="recap_title" data-translate="STATUS_TITLE_SUPERVISION_SUBSCRIPTION"></div> <div class="recap_boxes"> <div class="box_recap box_enabled_subscription" ng-click="setSupervisionRecapFilter('TRUE')"> + <span class="box-dot box-dot-enabled-subscription"></span> <div class="box_number">{{oSupervisionStatus.subscription.iEnabledSubscription}}</div> <div class="box_text" data-translate="ENABLED_SUBSCRIPTION_BOX_TITLE_SUPERVISION_SUBSCRIPTION"></div> </div> <div class="box_recap box_non_enabled_subscription" ng-click="setSupervisionRecapFilter('FALSE')"> + <span class="box-dot box-dot-non-enabled-subscription"></span> <div class="box_number">{{oSupervisionStatus.subscription.iNonEnabledSubscription}}</div> <div class="box_text" data-translate="NON_ENABLED_SUBSCRIPTION_BOX_TITLE_SUPERVISION_SUBSCRIPTION"></div> </div> @@ -45,10 +58,12 @@ <div class="recap_title" data-translate="STATUS_TITLE_SUPERVISION_SURVEY"></div> <div class="recap_boxes"> <div class="box_recap box_enabled_survey" ng-click="setSupervisionRecapFilter('TRUE')"> + <span class="box-dot box-dot-enabled-survey"></span> <div class="box_number">{{oSupervisionStatus.survey.iEnabledSurvey}}</div> <div class="box_text" data-translate="ENABLED_SURVEY_BOX_TITLE_SUPERVISION_SURVEY"></div> </div> <div class="box_recap box_non_enabled_survey" ng-click="setSupervisionRecapFilter('FALSE')"> + <span class="box-dot box-dot-non-enabled-survey"></span> <div class="box_number">{{oSupervisionStatus.survey.iNonEnabledSurvey}}</div> <div class="box_text" data-translate="NON_ENABLED_SURVEY_BOX_TITLE_SUPERVISION_SURVEY"></div> </div> @@ -58,18 +73,22 @@ <div class="recap_title" data-translate="STATUS_TITLE_SUPERVISION_MESSAGE"></div> <div class="recap_boxes"> <div class="box_recap box_waiting" ng-click="setSupervisionRecapFilter(1)"> + <span class="box-dot box-dot-waiting"></span> <div class="box_number">{{oSupervisionStatus.message.iWaitingMessages}}</div> <div class="box_text" data-translate="WAITING_BOX_TITLE_SUPERVISION_MESSAGE"></div> </div> <div class="box_recap box_error" ng-click="setSupervisionRecapFilter(2)"> + <span class="box-dot box-dot-error"></span> <div class="box_number">{{oSupervisionStatus.message.iErrorMessage}}</div> <div class="box_text" data-translate="ERROR_BOX_TITLE_SUPERVISION_MESSAGE"></div> </div> <div class="box_recap box_treated" ng-click="setSupervisionRecapFilter(3)"> + <span class="box-dot box-dot-treated"></span> <div class="box_number">{{oSupervisionStatus.message.iTreatedMessages}}</div> <div class="box_text" data-translate="TREATED_BOX_TITLE_SUPERVISION_MESSAGE"></div> </div> <div class="box_recap box_processing" ng-click="setSupervisionRecapFilter(5)"> + <span class="box-dot box-dot-processing"></span> <div class="box_number">{{oSupervisionStatus.message.iProcessingMessages}}</div> <div class="box_text" data-translate="PROCESSING_BOX_TITLE_SUPERVISION_MESSAGE"></div> </div> diff --git a/src/module_gtf/web_service/class/gtf_lib/FmeServer.class - Copie.inc b/src/module_gtf/web_service/class/gtf_lib/FmeServer.class - Copie.inc new file mode 100644 index 0000000000000000000000000000000000000000..db5b8de52861f6ed1e9961318fccc212c49675db --- /dev/null +++ b/src/module_gtf/web_service/class/gtf_lib/FmeServer.class - Copie.inc @@ -0,0 +1,700 @@ +<?php +require_once("vmlib/logUtil.inc"); + +/** + * \file FmeServer.php + * \brief Main class to use Fme Server services. + * + * \author Frederic Carretero <frederic.carretero@veremes.com> + */ + +Class FmeServer { + const CURL_CONNECTION_TIMEOUT = 0; + const CURL_TIMEOUT = 360; + const INFO_FME_SERVER_JOB_CANCELED = '|INFORM|PHP| Le traitement a été annulé sur Fme Server'; + const INFO_FME_SERVER_JOB_STOPPED = '|INFORM|PHP| Le traitement a été arrêté sur Fme Server'; + const INFO_FME_SERVER_JOB_REMOVED = '|INFORM|PHP| Le traitement a été supprimé sur Fme Server'; + + public $sUrl; + public $sTimeUnit; + public $iExpiration; + public $aLastCurlRequestInfo; + public $sLogFilePath; // Chemin optionnel vers le fichier de log pour Fme Server. + private $sUser; + private $sPassword; + private $sToken; + + /** + * construct + * @param {string} $sUrl Url of the fme server. + * @param {string} $sUser User id. + * @param {string} $sPassword User password. + * @param {string} $sTimeUnit Time unit (day, hour, minute, second). + * @param {number} $iExpiration Token expiration. + * @param {boolean} $bUpdate New (true) or current token if exists (false). + */ + function __construct ($sUrl, $sUser, $sPassword, $sTimeUnit = 'day', $iExpiration = 1, $bUpdate = false) { + $this->sUrl = $sUrl; + $this->sUser = $sUser; + $this->sPassword = $sPassword; + $this->sTimeUnit = $sTimeUnit; // Unité de temps pour la durée du token (day, hour, minute, second). + $this->iExpiration = $iExpiration; // Durée de validité du token. + $this->bUpdate = $bUpdate; // true -> génère un nouveau token écrase l’ancien / false -> retourne le token courant. + } + + /** + * Get a FME Server Token + * @return Token + */ + function getToken() { + // Url vers le serveur fme. + $sUrl = $this->sUrl; + // Url vers le service de génération d'un token. + $sUrl = $this->sUrl . '/fmetoken/service/generate'; + // Données de la requête. + $aRequestData = array ( + 'user' => $this->sUser, + 'password' => $this->sPassword, + 'expiration' => $this->iExpiration, + 'timeunit' => $this->sTimeUnit, + 'update' => $this->bUpdate + ); + // Transfert cURL + $sRequestResponse = $this->curlRequest($sUrl, 'post', $aRequestData); + if ($this->aLastCurlRequestInfo['http_code'] != 200) { + $this->writeToErrorLog($sRequestResponse); + $this->sToken = false; + } + else + $this->sToken = $sRequestResponse; + return $this->sToken; + } + + /** + * Curl request + * @param {string} $sUrl Url of the Curl request. + * @param {string} $sType Type of the Curl request (get, post). + * @param {array} $aData Data of the Curl request. + * @param {array} $aHeaders Headers of the Curl request. + * @return Request result + */ + // + function curlRequest($sUrl, $sType, $aData = array(), $aHeaders = array()) { + // + $this->aLastCurlRequestInfo = ''; + // + $ch = curl_init(); + $sType = strtoupper($sType); + // Force la méthode de requête utilisée (GET, POST...). + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $sType); + // Url à utiliser. + if (($sType == 'GET' || $sType == 'DELETE') && !empty($aData)) + $sUrl .= '?' . http_build_query($aData); + curl_setopt($ch, CURLOPT_URL, $sUrl); + // Retour sous forme de texte. + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + // Requête POST. + if ($sType == 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + // Chaîne de requête en encodage URL. + if (is_array($aData)) + $aData = http_build_query($aData); + // Données de la requête. + curl_setopt($ch, CURLOPT_POSTFIELDS, $aData); + // + curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true); + // Entête pour la requête en POST. + //$aHeaders[] = 'Content-Type: application/x-www-form-urlencoded'; + } + // Entête pour la requête + $aHeaders[] = 'Accept: application/json'; + if (!empty($this->sToken)) + $aHeaders[] = 'Authorization: fmetoken token=' . $this->sToken; // Token obligatoire pour éxécuter la requête. + curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeaders); + // Le nombre de secondes à attendre durant la tentative de connexion. + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::CURL_CONNECTION_TIMEOUT); + // Le temps maximum d'exécution de la fonction cURL (secondes). + curl_setopt($ch, CURLOPT_TIMEOUT, self::CURL_TIMEOUT); + // Exécute la session CURL. + // Log. + /* + $handle = fopen("curl_log.txt", "a"); + fwrite($handle, PHP_EOL . '-----------------------' . PHP_EOL); + curl_setopt($ch, CURLOPT_VERBOSE, true); + curl_setopt($ch, CURLOPT_STDERR , $handle); + */ + curl_setopt($ch, CURLINFO_HEADER_OUT, true); + // Curl error: SSL certificate problem: unable to get local issuer certificate + // Curl error n°60 + curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false); + // Curl error: SSL: no alternative certificate subject name matches target host name '52.205.208.184' (si utilisation de l'adresse ip et non ) + // Curl error n°51 + curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); + // + $output = curl_exec($ch); + // Erreur de la requête CURL. + if(curl_errno($ch)) { + $this->writeToErrorLog('Curl error: ' . curl_error($ch)); + $this->writeToErrorLog('Curl error n°' . curl_errno($ch)); + } + // Informations de la requête. + $aCurlInfo = curl_getinfo($ch); + $this->aLastCurlRequestInfo = $aCurlInfo; + //file_put_contents('C:/svn/gtf_cloud/gtf.engines/log/response.log', print_r($aCurlInfo, true)); + //writeToErrorLog(print_r(curl_getinfo($ch), true)); + + // Ferme la session CURL. + curl_close($ch); + // + //fclose($handle); + // + return $output; + } + + /** + * Send a request to the REST API. + * @param {string} $sService Name of the service. + * @param {string} $sMethod Method of the service (get, post...). + * @param {array} $aData Data of the Curl request. + * @return Request result + */ + function serviceRequest($sService, $sMethod = 'get', $aData = array(), $bWriteToErrorLog = true) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url vers le serveur fme. + $sUrl = $this->sUrl; + // Url vers le service d'information. + $sUrl = $this->sUrl . '/fmerest/v3/' . $sService; + // Transfert cURL + $sRequestResponse = $this->curlRequest($sUrl, $sMethod, $aData); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + if ($bWriteToErrorLog) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog('|' . $sService . '|' . ' ' . $oRequestResponse->message); + else + $this->writeToErrorLog('|' . $sService . '|' . ' ' . $sRequestResponse); + } + return false; + } + else + return json_decode($sRequestResponse); + } + else + return false; + } + + /** + * Upload a file + * @param {string} $sFilePath Path of the file to upload. + * @param {string} $sServiceUrl Url of the web service to upload the file. + * @param {string} $sFileName Name of the created file. + * @return Request result + */ + function uploadFile($sServiceUrl, $sFilePath, $sFileName = '') { + if (file_exists($sFilePath)) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Nom du fichier. + if (empty($sFileName)) + $sFileName = pathinfo($sFilePath, PATHINFO_BASENAME); + // Type MIME du fichier. + //$finfo = finfo_open(FILEINFO_MIME_TYPE); + // Crée un objet CURLFile. + //$oCfile = new CURLFile($sFilePath, finfo_file($finfo, $sFilePath), $sFileName); + //finfo_close($finfo); + // Entêtes de la requête Curl. + $aRequestHeaders = array( + 'Content-Type: application/octet-stream', + 'Content-Disposition: attachment; filename="' . $sFileName . '"', + //'Content-Length: ' . filesize($sFilePath) + ); + // + $sRequestResponse = $this->curlRequest($sServiceUrl, 'post', file_get_contents($sFilePath), $aRequestHeaders); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog($oRequestResponse->message); + else + $this->writeToErrorLog($sRequestResponse); + return false; + } + else + return json_decode($sRequestResponse); + } + else + return false; + } + else { + $this->writeToErrorLog('The file does not exist (' . $sFilePath . ')'); + return false; + } + } + + /** + * Upload a file to the resource connection + * @param {string} $sFilePath Path of the file to upload. + * @param {string} $sResource Name of a resource connection. + * @param {string} $sPath Path, relative to the resource connection. + * @param {boolean} $bCreateDirectories Create directories corresponding to the file path. + * @param {boolean} $bOverwrite Overwrite the file if it already exists. + * @return Request result + */ + function uploadResourceFile($sFilePath, $sResource, $sPath, $bCreateDirectories = false, $bOverwrite = false) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du service de ressources. + $sUrl = $this->sUrl . '/fmerest/v3/resources/connections/' . $sResource . '/filesys/' . $sPath; + $sUrl .= '?createDirectories=' . var_export($bCreateDirectories, true) . '&overwrite=' . var_export($bOverwrite, true); + return $this->uploadFile($sUrl, $sFilePath); + } + else + return false; + } + + /** + * Publish a file to a repository + * @param {string} $sFilePath Path of the file to upload. + * @param {string} $sRepository Name of the repository. + * @param {boolean} $bOverwrite Overwrite the file if it already exists. + * @param {string} $sRepositoryFileName File name in the repository. + * @return Request result + */ + function uploadWorkspaceFile($sFilePath, $sRepository, $bOverwrite = false, $sRepositoryFileName = '') { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Vérification de l'existence du fichier. + $bUploadFile = true; + if (!empty($sRepositoryFileName)) + $sSourceFileName = $sRepositoryFileName; + else + $sSourceFileName = pathinfo($sFilePath, PATHINFO_BASENAME); + $this->serviceRequest('repositories/' . $sRepository . '/items/' . $sSourceFileName, 'get', null, false); + // Supprime le fichier s'il existe déja. + if ($this->aLastCurlRequestInfo['http_code'] == 200) { + if ($bOverwrite) { + if ($this->serviceRequest('repositories/' . $sRepository . '/items/' . $sSourceFileName, 'delete') === false) + return false; + } + else + $bUploadFile = false; + } + //Upload du fichier. + if ($bUploadFile) { + $sUrl = $this->sUrl . '/fmerest/v3/repositories/' . $sRepository . '/items'; + return $this->uploadFile($sUrl, $sFilePath, $sRepositoryFileName); + } + } + else + return false; + } + + /** + * Upload a resource to a repository item + * @param {string} $sFilePath Path of the file to upload. + * @param {string} $sRepository Name of the repository. + * @param {string} $sItem Name of the repository item. + * @param {boolean} $bOverwrite Overwrite the file if it already exists. + * @return Request result + */ + function uploadWorkspaceResourceFile($sFilePath, $sRepository, $sItem, $bOverwrite = false) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + $bUploadFile = true; + $sFileName = pathinfo($sFilePath, PATHINFO_BASENAME); + // Télécharge la liste des ressources complémentaires du projet. + $aResources = $this->serviceRequest('repositories/' . $sRepository . '/items/' . $sItem . '/resources', 'get'); + if ($aResources !== false) { + // Vérification de l'existence du fichier. + foreach ($aResources as $oResource) { + // Supprime le fichier s'il existe déja. + if ($oResource->name == $sFileName) { + if ($bOverwrite) { + if ($this->serviceRequest('repositories/' . $sRepository . '/items/' . $sItem . '/resources/' . $sFileName, 'delete') === false) + return false; + } + else + $bUploadFile = false; + } + } + } + else + return false; + // Upload du fichier. + if ($bUploadFile) { + $sUrl = $this->sUrl . '/fmerest/v3/repositories/' . $sRepository . '/items/' . $sItem . '/resources'; + return $this->uploadFile($sUrl, $sFilePath); + } + } + else + return false; + } + + /** + * Get information about a repository item. + * @param {string} $sRepository Name of the repository. + * @param {string} $sWorkspace Name of the repository item. + * @return Request result + */ + function getWorkspaceParams($sRepository, $sWorkspace) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du service vers le traitement (fichier.fmw) spécifié. + $sUrl = $this->sUrl . '/fmerest/v3/repositories/' . $sRepository . '/items/' . $sWorkspace; + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'get'); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog($oRequestResponse->message); + else + $this->writeToErrorLog($sRequestResponse); + return false; + } + else + return json_decode($sRequestResponse); + + } + else + return false; + } + + /** + * Submit a job to run a transformation. + * @param {string} $sRepository Name of the repository. + * @param {string} $sWorkspace Name of the repository item. + * @param {array} $aParams The definition of the transformation request. + * @param {boolean} $bAsync Asynchronous job. + * @return Request result + */ + function submitJob($sRepository, $sWorkspace, $aParams, $bAsync = false) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du service vers le traitement (fichier.fmw) spécifié. + if ($bAsync) + $sUrl = $this->sUrl . '/fmerest/v3/transformations/submit/' . $sRepository . '/' . $sWorkspace; + else + $sUrl = $this->sUrl . '/fmerest/v3/transformations/transact/' . $sRepository . '/' . $sWorkspace; + // Données au format json. + $aHeaders = array('Content-Type: application/json'); + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'post', json_encode($aParams), $aHeaders); + $oRequestResponse = json_decode($sRequestResponse); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + if (is_object($oRequestResponse)) { + if (empty($oRequestResponse->id)) { + $this->writeToErrorLog($oRequestResponse->message); + return false; + } + else + $this->writeToErrorLog($oRequestResponse->statusMessage); + } + else + $this->writeToErrorLog($sRequestResponse); + } + return $oRequestResponse; + } + else + return false; + } + + /** + * Downloads a file from a resource connection. + * @param {string} $sResource Name of a resource connection. + * @param {string} $sPath Path, relative to the resource connection. + * @param {string} $sFilePath Path of the file to save. + * @return File content + */ + function downloadResourceFile($sResource, $sPath, $sFilePath = null) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du service vers le traitement (fichier.fmw) spécifié. + $sUrl = $this->sUrl . '/fmerest/v3/resources/connections/' . $sResource . '/filesys/' . $sPath; + // Obligatoire pour récupérer le contenu du fichier. + $aHeaders = array('Accept: application/octet-stream'); + // Données de la requête. + /* + $aRequestData = array ( + 'accept' => 'contents', + 'disposition' => 'inline' + ); + */ + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'get', null, $aHeaders); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog($oRequestResponse->message); + else + $this->writeToErrorLog($sRequestResponse); + return false; + } + else { + if (!empty($sFilePath)) + file_put_contents($sFilePath, $sRequestResponse); + else + return $sRequestResponse; + } + } + else + return false; + } + + /** + * Get the log file of a job. + * @param {number} $sJobId Job id. + * @return Log file content + */ + function getJobLog($sJobId, $sFilePath = '') { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du service vers le traitement (fichier.fmw) spécifié. + $sUrl = $this->sUrl . '/fmerest/v3/transformations/jobs/id/' . $sJobId . '/log'; + // Obligatoire pour récupérer le contenu du fichier. + $aHeaders = array('Accept: text/plain'); + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'get', null, $aHeaders); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog($oRequestResponse->message); + else + $this->writeToErrorLog($sRequestResponse); + return false; + } + else { + if (!empty($sFilePath)) + file_put_contents($sFilePath, $sRequestResponse); + else + return $sRequestResponse; + } + } + else + return false; + } + + /** + * Create a repository to the FME Server instance. + * @param {string} $sRepository Name of the repository. + * @param {string} $sDescription Description of the repository. + * @return Request result + */ + function createRepository($sRepository, $sDescription) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Crée le dépot s'il n'existe pas déja. + $aRequestResult = $this->serviceRequest('repositories/' . $sRepository, 'get', null, false); + if ($this->aLastCurlRequestInfo['http_code'] == 404) { + $aRequestData = array ( + 'name' => $sRepository, + 'description' => $sDescription + ); + $aRequestResult = $this->serviceRequest('repositories', 'post', $aRequestData); + } + return $aRequestResult; + } + else + return false; + } + + /** + * Upload a file to the resource connection from Amazon S3 service. + * @param {string} $aS3Params Parameters of the Amazon S3 service. + * @param {string} $sRepository Name of the repository. + * @param {string} $sResource Name of a resource connection. + * @param {string} $sPath Path, relative to the resource connection. + * @return Request result + */ + function uploadResourceFileFromS3($aS3Params, $sRepository, $sResource, $sPath) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // + $aJobParams = array( + 'publishedParameters' => array( + array('name' => 'access_key_id', 'value' => $aS3Params['access_key_id']), + array('name' => 'secret_access_key', 'value' => $aS3Params['secret_access_key']), + array('name' => 'bucket_name', 'value' => $aS3Params['bucket_name']), + array('name' => 'object_key', 'value' => $aS3Params['object_key']), + array('name' => 'target_file', 'value' => '$(' . $sResource . ')/' . $sPath . '/' . pathinfo($aS3Params['object_key'], PATHINFO_BASENAME)) + ) + ); + $oJobResult = $this->submitJob($sRepository, 'S3Downloader.fmw', $aJobParams); + return $oJobResult; + } + else + return false; + } + + /** + * Create a repository to the FME Server instance. + * @param {string} $sResource Name of a resource connection. + * @param {string} $sPath Path, relative to the resource connection. + * @param {string} $DirectoryName Name of the directory. + * @return Request result + */ + function createResourceConnectionDirectory($sResource, $sPath, $DirectoryName) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Crée le répertoire s'il n'existe pas déja. + $aRequestResult = $this->serviceRequest('resources/connections/' . $sResource . '/filesys/' . $sPath . '/' . $DirectoryName, 'get', null, false); + if ($this->aLastCurlRequestInfo['http_code'] == 404) { + $aRequestData = array ( + 'directoryname' => $DirectoryName + ); + $aRequestResult = $this->serviceRequest('resources/connections/' . $sResource . '/filesys/' . $sPath, 'post', $aRequestData); + } + return $aRequestResult; + } + else + return false; + } + + /** + * Get the FME Server build number and version. + * @return Request result + */ + function getInfo() { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du web service info. + $sUrl = $this->sUrl . '/fmerest/v3/info'; + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'get'); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $oRequestResponse = json_decode($sRequestResponse); + if (is_object($oRequestResponse) && !empty($oRequestResponse->message)) + $this->writeToErrorLog($oRequestResponse->message); + else + $this->writeToErrorLog($sRequestResponse); + return false; + } + else + return json_decode($sRequestResponse); + } + else + return false; + } + + /** + * Get status of the installed FME Server license. + * @return Request result + */ + function getLicenceStatus() { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Url du web service info. + $sUrl = $this->sUrl . '/fmerest/v3/licensing/license/status'; + // Transfert cURL. + $sRequestResponse = $this->curlRequest($sUrl, 'get'); + if ($this->aLastCurlRequestInfo['http_code'] >= 400) { + $this->writeToErrorLog($sRequestResponse); + return false; + } + else + return json_decode($sRequestResponse); + } + else + return false; + } + + /** + * Write a message to the error log file. + * @param {string} $sMessage Message to write to the log file. + */ + function writeToErrorLog($sMessage) { + $aDebugBacktrace = debug_backtrace(); + $sLogMessage = '|ERROR|' . $aDebugBacktrace[1]['class'] . '::' . $aDebugBacktrace[1]['function'] . '| ' . $sMessage; + if (empty($this->sLogFilePath)) + writeToErrorLog($sLogMessage); + else + writeToLog($sLogMessage, $this->sLogFilePath); + } + + /** + * Delete a job. + * @param {number} $iJobId The id of the job. + * @return Request result + */ + function deleteJob($iJobId) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Annule une demande en attente ou arrête une demande en cours. + if ($this->stopJob($iJobId) !== false) { + // Supprime définitivement la demande sur Fme Server. + if ($this->serviceRequest('transformations/jobs/completed/' . $iJobId, 'delete') !== false) + writeToLog(self::INFO_FME_SERVER_JOB_REMOVED . " (job id $iJobId).", $this->sLogFilePath); + else + return false; + } + } + else + return false; + } + + /** + * Cancel a queued job. + * @param {number} $iJobId The id of the job. + * @return Request result + */ + function cancelJob($iJobId) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + // Annule le traitement. + if ($this->serviceRequest('transformations/jobs/queued/' . $iJobId, 'delete') !== false) + writeToLog(self::INFO_FME_SERVER_JOB_CANCELED . " (job id $iJobId).", $this->sLogFilePath); + else + return false; + } + else + return false; + } + + /** + * Stop a queued or running job. + * @param {number} $iJobId The id of the job. + * @return Request result + */ + function stopJob($iJobId) { + // Demande de token. + $this->getToken(); + if ($this->sToken !== false) { + $oJobLog = $this->serviceRequest('transformations/jobs/id/' . $iJobId); + if ($oJobLog !== false) { + // Annule une demande en attente ou arrête une demande en cours. + $aQueuedStatus = array('SUBMITTED', 'QUEUED', 'DELAYED', 'PAUSED'); + $aRunningStatus = array('IN_PROCESS', 'PULLED'); + $aStoppedStatus = array('DELETED', 'ABORTED', 'FME_FAILURE', 'JOB_FAILURE', 'SUCCESS'); + if (in_array($oJobLog->status, $aQueuedStatus)) + $this->cancelJob($iJobId); + else if (!in_array($oJobLog->status, $aStoppedStatus)){ + // Annule le traitement. + if ($this->serviceRequest('transformations/jobs/running/' . $iJobId, 'delete') !== false) + writeToLog(self::INFO_FME_SERVER_JOB_STOPPED . " (job id $iJobId).", $this->sLogFilePath); + else + return false; + } + } + else + return false; + } + else + return false; + } +} +?> \ No newline at end of file diff --git a/src/module_gtf/web_service/ws/Gtf.class.sql.inc b/src/module_gtf/web_service/ws/Gtf.class.sql.inc index 724684fd24dc3c6678a3d13df317140b5edf6c46..fcb43b1bdbe0ef0b48611d17f267a8703b75e6f1 100644 --- a/src/module_gtf/web_service/ws/Gtf.class.sql.inc +++ b/src/module_gtf/web_service/ws/Gtf.class.sql.inc @@ -31,7 +31,8 @@ $aSql['getOrdersToDelete'] = 'SELECT fme_engine.fme_engine_type_id, "order".orde $aSql['getGtfEngineHomeFromOrderId'] = 'SELECT engines_home, "order".gtf_engine_id, "order".order_id FROM [sSchemaGtf]."server", [sSchemaGtf].gtf_engine, [sSchemaGtf]."order" WHERE gtf_engine.server_id = "server".server_id AND gtf_engine.gtf_engine_id = "order".gtf_engine_id AND order_id = [order_id]'; $aSql['getGtfEngineHomeFromEngineId'] = 'SELECT engines_home, "order".gtf_engine_id, "order".order_id FROM [sSchemaGtf]."server", [sSchemaGtf].gtf_engine, [sSchemaGtf]."order" WHERE gtf_engine.server_id = "server".server_id AND gtf_engine.gtf_engine_id = "order".gtf_engine_id AND gtf_engine.gtf_engine_id = [iGtfEngineId]'; $aSql['getFmeServerOrder'] = 'SELECT fme_engine.fme_engine_type_id, fme_engine.server_url, fme_engine.login, fme_engine.password, fme_engine.fme_cloud_api_token, fme_engine.fme_server_instance_name, "order".gtf_engine_id, "order".pid, server.engines_home, "order".log_url FROM [sSchemaGtf].order, [sSchemaGtf].gtf_engine, [sSchemaGtf].fme_engine, [sSchemaGtf].server WHERE gtf_engine.gtf_engine_id = "order".gtf_engine_id AND fme_engine.fme_engine_id = gtf_engine.fme_engine_id AND server.server_id = fme_engine.server_id AND order_id = [order_id] LIMIT 1'; -$aSql['getOrderPid'] = 'SELECT fme_engine.fme_engine_type_id, "order".gtf_engine_id, "order".pid FROM [sSchemaGtf]."order", [sSchemaGtf].gtf_engine, [sSchemaGtf].fme_engine, [sSchemaGtf].server WHERE gtf_engine.gtf_engine_id = "order".gtf_engine_id AND fme_engine.fme_engine_id = gtf_engine.fme_engine_id AND server.server_id = fme_engine.server_id AND order_id = [order_id] LIMIT 1'; +//$aSql['getOrderPid'] = 'SELECT fme_engine.fme_engine_type_id, "order".gtf_engine_id, "order".pid FROM [sSchemaGtf]."order", [sSchemaGtf].gtf_engine, [sSchemaGtf].fme_engine, [sSchemaGtf].server WHERE gtf_engine.gtf_engine_id = "order".gtf_engine_id AND fme_engine.fme_engine_id = gtf_engine.fme_engine_id AND server.server_id = fme_engine.server_id AND order_id = [order_id] LIMIT 1'; +$aSql['getOrderPid'] = 'SELECT pid FROM [sSchemaGtf]."order" WHERE order_id = [order_id] AND pid IS NOT NULL'; $aSql['getOrderFmeEngineType'] = 'SELECT fme_engine.fme_engine_type_id FROM [sSchemaGtf]."order", [sSchemaGtf].gtf_engine, [sSchemaGtf].fme_engine WHERE gtf_engine.gtf_engine_id = "order".gtf_engine_id AND fme_engine.fme_engine_id = gtf_engine.fme_engine_id AND order_id = [order_id] LIMIT 1'; // UserSubscriptions $aSql['setSubscriptionEngineId'] = 'UPDATE [sSchemaGtf].subscription SET gtf_engine_id=[gtf_engine_id] WHERE subscription_id=[subscription_id]'; diff --git a/src/module_gtf/web_service/ws/Orders.class.inc b/src/module_gtf/web_service/ws/Orders.class.inc index c3142fb17ae5c8e40a2c483535967333fadd400b..3c8565a7d261b2484f518dd2bfe9a7a331b893ec 100644 --- a/src/module_gtf/web_service/ws/Orders.class.inc +++ b/src/module_gtf/web_service/ws/Orders.class.inc @@ -852,38 +852,35 @@ class Orders extends GTF { $aParams = array(); $aParams['sSchemaGtf'] = array('value' => $this->aProperties['schema_gtf'], 'type' => 'schema_name'); $aParams['order_id'] = array('value' => $iOrderId, 'type' => 'number'); - $oPDOresult = $this->oConnection->oBd->executeWithParams($aSql['getGtfEngineHomeFromOrderId'], $aParams); - if (!$this->oConnection->oBd->enErreur()) { - $aGtfEngineHome = $this->oConnection->oBd->ligneSuivante($oPDOresult); - $sPidFilePath = $aGtfEngineHome['engines_home'] . '/' . 'pid_' . $aGtfEngineHome['gtf_engine_id'] . '.txt'; - if (file_exists($sPidFilePath)) { - $iPid = file_get_contents($sPidFilePath); - if (is_numeric($iPid)) { - if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { - // Supprime le processus "engine.exe". - $this->killProcess($iPid); - // Tue tous les processus liés à une demande et un traitement sur Fme Desktop. - $aProcessName = array('cmd.exe', 'php.exe', 'cmd.exe', 'fme.exe'); - foreach ($aProcessName as $sProcessName) { - $iPid = $this->getChildProcess($iPid, $sProcessName); - if ($iPid !== false) - $this->killProcess($iPid); - } - } - else { - // Supprime tous les processus enfants. - $aResult = array(); - $sResultCommande = exec('pkill -9 -P ' . $iPid, $aResult, $iResult); - // Supprime le processus du moteur. + $oPDOresult = $this->oConnection->oBd->executeWithParams($aSql['getOrderPid'], $aParams); + if (!$this->oConnection->oBd->enErreur() && $this->oConnection->oBd->nombreLigne($oPDOresult) > 0) { + $aPid = $this->oConnection->oBd->ligneSuivante($oPDOresult); + $iPid = $aPid['pid']; + if (strtolower(substr(PHP_OS, 0, 3)) == 'win') { + // Supprime le processus "engine.exe". + $this->killProcess($iPid); + // Tue tous les processus liés à une demande et un traitement sur Fme Desktop. + $aProcessName = array('cmd.exe', 'php.exe', 'cmd.exe', 'fme.exe'); + foreach ($aProcessName as $sProcessName) { + $iPid = $this->getChildProcess($iPid, $sProcessName); + if ($iPid !== false) $this->killProcess($iPid); - } } - // Suppression du fichier contenant le pid du processus "engine.exe". - unlink($sPidFilePath); + } + else { + // Récupère l'id de session du processus du moteur GTF. + $aResult = array(); + $sResultCommande = exec('ps -p ' . $iPid . ' -o sess', $aResult, $iResult); + // Supprime tous les processus enfants. + if ($iResult == 0 && !empty($aResult) && is_numeric($aResult[1])) { + $iSess = $aResult[1]; + $aResult = array(); + $sResultCommande = exec('pkill -9 -s ' . $iSess, $aResult, $iResult); + } } } } - + /** * function killProcess * \param $iPid Id of the process.